1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * dcam.c
  29  *
  30  * dcam1394 driver. Controls IIDC compliant devices attached through a
  31  * IEEE-1394 bus.
  32  */
  33 
  34 #include <sys/conf.h>
  35 #include <sys/ddi.h>
  36 #include <sys/modctl.h>
  37 #include <sys/sunndi.h>
  38 #include <sys/types.h>
  39 #include <sys/ddi.h>
  40 #include <sys/sunddi.h>
  41 #include <sys/file.h>
  42 #include <sys/errno.h>
  43 #include <sys/open.h>
  44 #include <sys/cred.h>
  45 #include <sys/mkdev.h>
  46 #include <sys/kmem.h>
  47 #include <sys/stat.h>
  48 #include <sys/cmn_err.h>
  49 #include <sys/stream.h>
  50 #include <sys/buf.h>
  51 #include <sys/uio.h>
  52 #include <sys/devops.h>
  53 #include <sys/1394/t1394.h>
  54 #include <sys/tnf_probe.h>
  55 
  56 #include <sys/dcam/dcam1394_io.h>
  57 #include <sys/1394/targets/dcam1394/dcam.h>
  58 #include <sys/1394/targets/dcam1394/dcam_reg.h>
  59 #include <sys/1394/targets/dcam1394/dcam_param.h>
  60 #include <sys/1394/targets/dcam1394/dcam_frame.h>
  61 
  62 #ifndef NPROBE
  63 extern int tnf_mod_load(void);
  64 extern int tnf_mod_unload(struct modlinkage *mlp);
  65 #endif /* ! NPROBE */
  66 
  67 
  68 /* for power management (we have only one component) */
  69 static char *dcam_pmc[] = {
  70         "NAME=dcam1394",
  71         "0=Off",
  72         "1=On"
  73 };
  74 
  75 int g_vid_mode_frame_num_bytes[] =
  76 {
  77         57600,          /* vid mode 0 */
  78         153600,         /* vid mode 1 */
  79         460800,         /* vid mode 2 */
  80         614400,         /* vid mode 3 */
  81         921600,         /* vid mode 4 */
  82         307200          /* vid mode 5 */
  83 };
  84 
  85 static int      byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p,
  86                     size_t num_bytes, int start_index, int *end_index);
  87 static int      byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
  88                     size_t num_bytes, int start_index, int *end_index);
  89 static int      dcam_reset(dcam_state_t *softc_p);
  90 
  91 /* opaque state structure head */
  92 void *dcam_state_p;
  93 
  94 static struct cb_ops dcam_cb_ops = {
  95         dcam_open,              /* open         */
  96         dcam_close,             /* close        */
  97         nodev,                  /* strategy     */
  98         nodev,                  /* print        */
  99         nodev,                  /* dump         */
 100         dcam_read,              /* read         */
 101         nodev,                  /* write        */
 102         dcam_ioctl,             /* ioctl        */
 103         nodev,                  /* devmap       */
 104         nodev,                  /* mmap         */
 105         nodev,                  /* segmap       */
 106         dcam_chpoll,            /* chpoll       */
 107         ddi_prop_op,            /* prop_op      */
 108         NULL,                   /* streams      */
 109                                 /* flags        */
 110         D_NEW | D_MP | D_64BIT | D_HOTPLUG,
 111         CB_REV,                 /* rev          */
 112         nodev,                  /* aread        */
 113         nodev                   /* awrite       */
 114 };
 115 
 116 static struct dev_ops dcam_dev_ops = {
 117         DEVO_REV,               /* DEVO_REV indicated by manual */
 118         0,                      /* device reference count       */
 119         dcam_getinfo,           /* getinfo                      */
 120         nulldev,                /* identify                     */
 121         nulldev,                /* probe                        */
 122         dcam_attach,            /* attach                       */
 123         dcam_detach,            /* detach                       */
 124         nodev,                  /* reset                        */
 125         &dcam_cb_ops,               /* ptr to cb_ops struct         */
 126         NULL,                   /* ptr to bus_ops struct; none  */
 127         dcam_power,             /* power                        */
 128         ddi_quiesce_not_supported,      /* devo_quiesce */
 129 };
 130 
 131 extern  struct  mod_ops mod_driverops;
 132 
 133 static  struct modldrv modldrv = {
 134         &mod_driverops,
 135         "SUNW 1394-based Digital Camera driver",
 136         &dcam_dev_ops,
 137 };
 138 
 139 static  struct modlinkage modlinkage = {
 140         MODREV_1,
 141         {   (void *)&modldrv,
 142             NULL }
 143 };
 144 
 145 
 146 int
 147 _init(void)
 148 {
 149         int err;
 150 
 151         err = ddi_soft_state_init(&dcam_state_p, sizeof (dcam_state_t), 2);
 152 
 153         if (err) {
 154                 return (err);
 155         }
 156 
 157 #ifndef NPROBE
 158         (void) tnf_mod_load();
 159 #endif /* ! NPROBE */
 160 
 161         if (err = mod_install(&modlinkage)) {
 162 
 163 #ifndef NPROBE
 164                 (void) tnf_mod_unload(&modlinkage);
 165 #endif /* ! NPROBE */
 166 
 167                 ddi_soft_state_fini(&dcam_state_p);
 168 
 169         }
 170 
 171         return (err);
 172 }
 173 
 174 
 175 int
 176 _info(struct modinfo *modinfop)
 177 {
 178         int err;
 179 
 180         err = mod_info(&modlinkage, modinfop);
 181         return (err);
 182 }
 183 
 184 
 185 int
 186 _fini(void)
 187 {
 188         int err;
 189 
 190         if ((err = mod_remove(&modlinkage)) != 0) {
 191                 return (err);
 192         }
 193 
 194 #ifndef NPROBE
 195                 (void) tnf_mod_unload(&modlinkage);
 196 #endif /* ! NPROBE */
 197 
 198         ddi_soft_state_fini(&dcam_state_p);
 199 
 200         return (err);
 201 }
 202 
 203 
 204 /*
 205  * dcam_attach
 206  */
 207 /* ARGSUSED */
 208 int
 209 dcam_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 210 {
 211         char                    tmp_str[MAX_STR_LEN];
 212         dcam_state_t            *softc_p;
 213         ddi_eventcookie_t       ev_cookie;
 214         int                     instance;
 215         int                     ret_val;
 216 
 217         switch (cmd) {
 218 
 219         case DDI_ATTACH:
 220                 instance = ddi_get_instance(dip);
 221 
 222                 if (ddi_soft_state_zalloc(dcam_state_p, instance) !=
 223                     DDI_SUCCESS) {
 224                         return (DDI_FAILURE);
 225                 }
 226 
 227                 if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
 228                     NULL) {
 229                         ddi_soft_state_free(dcam_state_p, instance);
 230                         return (DDI_FAILURE);
 231                 }
 232 
 233                 /*
 234                  * Initialize soft state
 235                  */
 236                 softc_p->dip                 = dip;
 237                 softc_p->instance            = instance;
 238                 softc_p->usr_model           = -1;
 239                 softc_p->ixlp                        = NULL;
 240 
 241                 softc_p->seq_count           = 0;
 242                 softc_p->param_status                = 0;
 243 
 244                 /*
 245                  * set default vid_mode, frame_rate and ring_buff_capacity
 246                  */
 247                 softc_p->cur_vid_mode                = 1;
 248                 softc_p->cur_frame_rate      = 3;
 249                 softc_p->cur_ring_buff_capacity = 10;
 250                 softc_p->camera_online               = 1;
 251 
 252                 (void) sprintf(tmp_str, "dcam%d", instance);
 253 
 254                 if (ddi_create_minor_node(dip, tmp_str, S_IFCHR, instance,
 255                     DDI_PSEUDO, 0) != DDI_SUCCESS) {
 256                         ddi_soft_state_free(dcam_state_p, instance);
 257 
 258                         return (DDI_FAILURE);
 259                 }
 260 
 261                 (void) sprintf(tmp_str, "dcamctl%d", instance);
 262 
 263                 if (ddi_create_minor_node(dip, tmp_str, S_IFCHR,
 264                     instance + DCAM1394_MINOR_CTRL, "ddi_dcam1394", 0) !=
 265                     DDI_SUCCESS) {
 266                         ddi_soft_state_free(dcam_state_p, instance);
 267 
 268                         return (DDI_FAILURE);
 269                 }
 270 
 271                 if (t1394_attach(dip, T1394_VERSION_V1, 0,
 272                     &(softc_p->attachinfo),
 273                     &(softc_p->sl_handle)) != DDI_SUCCESS) {
 274                         ddi_soft_state_free(dcam_state_p, instance);
 275                         ddi_remove_minor_node(dip, NULL);
 276 
 277                         return (DDI_FAILURE);
 278                 }
 279 
 280                 if (t1394_get_targetinfo(softc_p->sl_handle,
 281                     softc_p->attachinfo.localinfo.bus_generation, 0,
 282                     &(softc_p->targetinfo)) != DDI_SUCCESS) {
 283                         cmn_err(CE_WARN,
 284                             "dcam_attach: t1394_get_targetinfo failed\n");
 285                 }
 286 
 287                 if (ddi_get_eventcookie(dip, DDI_DEVI_BUS_RESET_EVENT,
 288                     &ev_cookie) != DDI_SUCCESS) {
 289                         (void) t1394_detach(&softc_p->sl_handle, 0);
 290 
 291                         ddi_soft_state_free(dcam_state_p, instance);
 292                         ddi_remove_minor_node(dip, NULL);
 293 
 294                         return (DDI_FAILURE);
 295                 }
 296 
 297                 if (ddi_add_event_handler(dip, ev_cookie, dcam_bus_reset_notify,
 298                     softc_p, &softc_p->event_id) != DDI_SUCCESS) {
 299                         (void) t1394_detach(&softc_p->sl_handle, 0);
 300 
 301                         ddi_soft_state_free(dcam_state_p, instance);
 302                         ddi_remove_minor_node(dip, NULL);
 303 
 304                         return (DDI_FAILURE);
 305                 }
 306 
 307                 mutex_init(&softc_p->softc_mutex, NULL, MUTEX_DRIVER,
 308                     softc_p->attachinfo.iblock_cookie);
 309 
 310                 mutex_init(&softc_p->dcam_frame_is_done_mutex, NULL,
 311                     MUTEX_DRIVER, softc_p->attachinfo.iblock_cookie);
 312 
 313                 /*
 314                  * init the soft state's parameter attribute structure
 315                  */
 316                 if (param_attr_init(softc_p, softc_p->param_attr) !=
 317                     DDI_SUCCESS) {
 318                         (void) ddi_remove_event_handler(softc_p->event_id);
 319                         (void) t1394_detach(&softc_p->sl_handle, 0);
 320 
 321                         ddi_soft_state_free(dcam_state_p, instance);
 322                         ddi_remove_minor_node(dip, NULL);
 323 
 324                         return (DDI_FAILURE);
 325                 }
 326 
 327                 /*
 328                  * power management stuff
 329                  */
 330                 if (ddi_prop_update_string_array(DDI_DEV_T_NONE,
 331                     dip, "pm-components", dcam_pmc,
 332                     sizeof (dcam_pmc)/sizeof (char *)) == DDI_PROP_SUCCESS) {
 333 
 334                         (void) pm_raise_power(dip, 0, 1);
 335                         if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0,
 336                             "power-managed?")) {
 337                                 (void) pm_idle_component(dip, 0);
 338                         } else {
 339                                 (void) pm_busy_component(dip, 0);
 340                         }
 341                 }
 342 
 343                 softc_p->flags |= DCAM1394_FLAG_ATTACH_COMPLETE;
 344 
 345                 ddi_report_dev(dip);
 346                 ret_val = DDI_SUCCESS;
 347                 break;
 348 
 349         case DDI_RESUME:
 350                 instance = ddi_get_instance(dip);
 351                 if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
 352                     NULL) {
 353                         ddi_soft_state_free(dcam_state_p, instance);
 354                         return (DDI_FAILURE);
 355                 }
 356 
 357                 mutex_enter(&softc_p->softc_mutex);
 358 
 359                 if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
 360                         (void) dcam1394_ioctl_frame_rcv_start(softc_p);
 361                 }
 362 
 363                 softc_p->suspended = 0;
 364 
 365                 mutex_exit(&softc_p->softc_mutex);
 366 
 367                 ret_val = DDI_SUCCESS;
 368                 break;
 369 
 370         default:
 371                 ret_val = DDI_FAILURE;
 372                 break;
 373         }
 374 
 375         return (ret_val);
 376 }
 377 
 378 
 379 /*
 380  * dcam_power: perform dcam power management
 381  */
 382 /* ARGSUSED */
 383 int
 384 dcam_power(dev_info_t *dip, int component, int level)
 385 {
 386         dcam_state_t    *softc_p;
 387         int             instance;
 388 
 389         instance = ddi_get_instance(dip);
 390         softc_p  = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
 391 
 392         if (softc_p == NULL)
 393                 return (DDI_FAILURE);
 394 
 395         softc_p->pm_cable_power = level;
 396 
 397         return (DDI_SUCCESS);
 398 
 399 }
 400 
 401 
 402 /*
 403  * dcam_getinfo
 404  */
 405 /* ARGSUSED */
 406 int
 407 dcam_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 408 {
 409         dev_t            dev;
 410         dcam_state_t    *softc_p;
 411         int              status;
 412         int              instance;
 413 
 414         switch (cmd) {
 415 
 416         case DDI_INFO_DEVT2DEVINFO:
 417                 dev      = (dev_t)arg;
 418                 instance = DEV_TO_INSTANCE(dev);
 419                 softc_p  = (dcam_state_t *)
 420                     ddi_get_soft_state(dcam_state_p, instance);
 421 
 422                 if (softc_p == NULL) {
 423                         return (DDI_FAILURE);
 424                 }
 425 
 426                 *result = (void *)softc_p->dip;
 427                 status  = DDI_SUCCESS;
 428                 break;
 429 
 430         case DDI_INFO_DEVT2INSTANCE:
 431                 dev      = (dev_t)arg;
 432                 instance = DEV_TO_INSTANCE(dev);
 433                 *result  = (void *)(uintptr_t)instance;
 434                 status   = DDI_SUCCESS;
 435                 break;
 436 
 437         default:
 438                 status = DDI_FAILURE;
 439         }
 440 
 441         return (status);
 442 }
 443 
 444 
 445 /*
 446  * dcam_detach
 447  */
 448 /* ARGSUSED */
 449 int
 450 dcam_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 451 {
 452         int                      instance;
 453         dcam_state_t            *softc_p;
 454 
 455         instance = ddi_get_instance(dip);
 456 
 457         softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
 458         if (softc_p == NULL) {
 459                 return (DDI_FAILURE);
 460         }
 461 
 462 
 463         switch (cmd) {
 464 
 465         case DDI_SUSPEND:
 466                 mutex_enter(&softc_p->softc_mutex);
 467 
 468                 softc_p->suspended = 1;
 469 
 470                 if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
 471                         (void) dcam_frame_rcv_stop(softc_p);
 472                 }
 473 
 474                 mutex_exit(&softc_p->softc_mutex);
 475                 return (DDI_SUCCESS);
 476 
 477 
 478         case DDI_DETACH:
 479                 /*
 480                  * power management stuff
 481                  */
 482                 (void) pm_lower_power(dip, 0, 0);
 483                 (void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
 484 
 485                 /*
 486                  * deregister with 1394 DDI framework
 487                  */
 488                 if (t1394_detach(&softc_p->sl_handle, 0) != DDI_SUCCESS) {
 489                         return (DDI_FAILURE);
 490                 }
 491 
 492                 (void) ddi_remove_event_handler(softc_p->event_id);
 493 
 494                 /*
 495                  * free state structures, mutexes, condvars;
 496                  * deregister interrupts
 497                  */
 498                 mutex_destroy(&softc_p->softc_mutex);
 499                 mutex_destroy(&softc_p->dcam_frame_is_done_mutex);
 500 
 501                 /*
 502                  * Remove all minor nodes, all dev_t's properties
 503                  */
 504                 ddi_remove_minor_node(dip, NULL);
 505 
 506                 ddi_soft_state_free(dcam_state_p, instance);
 507                 ddi_prop_remove_all(dip);
 508 
 509                 return (DDI_SUCCESS);
 510 
 511         default:
 512                 return (DDI_FAILURE);
 513 
 514         }
 515 }
 516 
 517 
 518 /*
 519  * dcam_open
 520  */
 521 /* ARGSUSED */
 522 int
 523 dcam_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
 524 {
 525         dcam_state_t    *softc_p;
 526         int             instance;
 527         int             is_ctrl_file;
 528         uint_t          new_flags;
 529 
 530         instance = (int)DEV_TO_INSTANCE(*dev_p);
 531 
 532         if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
 533                 return (ENXIO);
 534         }
 535 
 536         /*
 537          * if dcam_attach hasn't completed, return error
 538          * XXX: Check this out
 539          */
 540         if (!(softc_p->flags & DCAM1394_FLAG_ATTACH_COMPLETE)) {
 541                 return (ENXIO);
 542         }
 543 
 544         /* disallow block, mount, and layered opens */
 545         if (otyp != OTYP_CHR) {
 546                 return (EINVAL);
 547         }
 548 
 549         new_flags    = 0;
 550         is_ctrl_file = (getminor(*dev_p) & DCAM1394_MINOR_CTRL) ? 1 : 0;
 551 
 552         mutex_enter(&softc_p->softc_mutex);
 553 
 554         /*
 555          * The open is either for the capture file or the control file.
 556          * If it's the control file construct new flags.
 557          *
 558          * If it's the capture file return busy if it's already open,
 559          * otherwise construct new flags.
 560          */
 561         if (is_ctrl_file) {
 562                 new_flags |= DCAM1394_FLAG_OPEN_CONTROL;
 563         } else {
 564                 if (softc_p->flags & DCAM1394_FLAG_OPEN_CAPTURE) {
 565                         mutex_exit(&softc_p->softc_mutex);
 566                         return (EBUSY);
 567                 }
 568 
 569                 new_flags |= DCAM1394_FLAG_OPEN_CAPTURE;
 570         }
 571 
 572         new_flags |= DCAM1394_FLAG_OPEN;
 573         softc_p->flags |= new_flags;
 574 
 575         mutex_exit(&softc_p->softc_mutex);
 576 
 577         /*
 578          * power management stuff
 579          */
 580         if (softc_p->pm_open_count == 0) {
 581                 if (ddi_prop_exists(DDI_DEV_T_ANY, softc_p->dip, 0,
 582                     "power-managed?")) {
 583                         (void) pm_busy_component(softc_p->dip, 0);
 584                         if (softc_p->pm_cable_power == 0) {
 585                                 int i;
 586 
 587                                 (void) pm_raise_power(softc_p->dip, 0, 1);
 588 
 589                                 /*
 590                                  * Wait for the power to be up and stable
 591                                  * before proceeding.  100 msecs should
 592                                  * certainly be enough, and if we check
 593                                  * every msec we'll probably loop just a
 594                                  * few times.
 595                                  */
 596                                 for (i = 0; i < 100; i++) {
 597                                         if (param_power_set(softc_p, 1) == 0) {
 598                                                 break;
 599                                         }
 600                                         delay((clock_t)drv_usectohz(1000));
 601                                 }
 602                         }
 603                 }
 604         }
 605         softc_p->pm_open_count++;
 606 
 607         return (0);
 608 }
 609 
 610 
 611 /*
 612  * dcam_close
 613  */
 614 /* ARGSUSED */
 615 int
 616 dcam_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
 617 {
 618         int instance;
 619         dcam_state_t *softc;
 620 
 621         instance = DEV_TO_INSTANCE(dev);
 622         softc    = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
 623 
 624         /*
 625          * power management stuff
 626          */
 627         softc->pm_open_count = 0;
 628         if (ddi_prop_exists(DDI_DEV_T_ANY, softc->dip, 0, "power-managed?")) {
 629                 (void) pm_idle_component(softc->dip, 0);
 630         }
 631 
 632         mutex_enter(&softc->softc_mutex);
 633 
 634         if (getminor(dev) & DCAM1394_MINOR_CTRL) {
 635                 softc->flags &= ~DCAM1394_FLAG_OPEN_CONTROL;
 636         } else {
 637                 /*
 638                  * If an application which has opened the camera capture
 639                  * device exits without calling DCAM1394_CMD_FRAME_RCV_STOP
 640                  * ioctl, then we need to release resources.
 641                  */
 642                 if (softc->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
 643                         (void) dcam_frame_rcv_stop(softc);
 644                         softc->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
 645                 }
 646 
 647                 (void) param_power_set(softc, 0);
 648 
 649                 softc->flags &= ~DCAM1394_FLAG_OPEN_CAPTURE;
 650         }
 651 
 652         /*
 653          * If driver is completely closed, then stabilize the camera
 654          * and turn off transient flags
 655          */
 656         if (!(softc->flags &
 657             (DCAM1394_FLAG_OPEN_CONTROL | DCAM1394_FLAG_OPEN_CAPTURE))) {
 658                 softc->flags &= DCAM1394_FLAG_ATTACH_COMPLETE;
 659         }
 660 
 661         mutex_exit(&softc->softc_mutex);
 662 
 663         return (DDI_SUCCESS);
 664 
 665 }
 666 
 667 
 668 /*
 669  * dcam_read
 670  *
 671  * If read pointer is not pointing to the same position as write pointer
 672  * copy frame data from ring buffer position pointed to by read pointer.
 673  *
 674  *      If during the course of copying frame data, the device driver
 675  *      invalidated this read() request processing operation, restart
 676  *      this operation.
 677  *
 678  *     Increment read pointer and return frame data to user process.
 679  *
 680  * Else return error
 681  *
 682  */
 683 /* ARGSUSED */
 684 int
 685 dcam_read(dev_t dev, struct uio *uio_p, cred_t *cred_p)
 686 {
 687         buff_info_t     *buff_info_p;
 688         dcam_state_t    *softc_p;
 689         hrtime_t         timestamp;
 690         int              index, instance;
 691         int              read_ptr_id;
 692         size_t           read_ptr_pos, write_ptr_pos;
 693         int              read_req_invalid;
 694         ring_buff_t     *ring_buff_p;
 695         uchar_t         *frame_data_p;
 696         uint_t           seq_num;
 697         unsigned long    user_frame_buff_addr;
 698         uint_t           vid_mode;
 699         int              gotten_addr_flag;
 700 
 701         instance = DEV_TO_INSTANCE(dev);
 702 
 703         softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
 704         if (softc_p == NULL) {
 705                 return (ENXIO);
 706         }
 707 
 708         if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
 709                 return (EAGAIN);
 710         }
 711 
 712         read_ptr_id = 0;
 713 
 714         mutex_enter(&softc_p->dcam_frame_is_done_mutex);
 715 
 716         softc_p->reader_flags[read_ptr_id] |= DCAM1394_FLAG_READ_REQ_PROC;
 717 
 718         user_frame_buff_addr = 0;
 719         gotten_addr_flag = 0;
 720 
 721         do {
 722                 read_ptr_pos = ring_buff_read_ptr_pos_get(ring_buff_p,
 723                     read_ptr_id);
 724 
 725                 write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
 726 
 727                 if (read_ptr_pos != write_ptr_pos) {
 728                         /*
 729                          * Since the app wants realtime video, set the read
 730                          * pointer to the newest data.
 731                          */
 732                         if (write_ptr_pos == 0) {
 733                                 read_ptr_pos = ring_buff_p->num_buffs - 1;
 734                         } else {
 735                                 read_ptr_pos = write_ptr_pos - 1;
 736                         }
 737 
 738                         /*
 739                          * copy frame data from ring buffer position pointed
 740                          * to by read pointer
 741                          */
 742                         index = 0;
 743                         buff_info_p =
 744                             &(ring_buff_p->buff_info_array_p[read_ptr_pos]);
 745 
 746                         vid_mode = softc_p->cur_vid_mode;
 747                         seq_num  = buff_info_p->seq_num;
 748                         timestamp = buff_info_p->timestamp;
 749                         frame_data_p = (uchar_t *)buff_info_p->kaddr_p;
 750 
 751                         mutex_exit(&softc_p->dcam_frame_is_done_mutex);
 752 
 753                         /*
 754                          * Fix for bug #4424042
 755                          * don't lock this section
 756                          */
 757 
 758                         if (byte_copy_to_user_buff((uchar_t *)&vid_mode,
 759                             uio_p, sizeof (uint_t), index, &index)) {
 760 
 761                                 return (EFAULT);
 762                         }
 763 
 764                         if (byte_copy_to_user_buff((uchar_t *)&seq_num,
 765                             uio_p, sizeof (unsigned int), index, &index)) {
 766 
 767                                 return (EFAULT);
 768                         }
 769 
 770                         if (byte_copy_to_user_buff((uchar_t *)&timestamp,
 771                             uio_p, sizeof (hrtime_t), index, &index)) {
 772 
 773                                 return (EFAULT);
 774                         }
 775 
 776                         /*
 777                          * get buff pointer; do ddi_copyout()
 778                          * get user buffer address only once
 779                          */
 780                         if (!gotten_addr_flag) {
 781                                 if (byte_copy_from_user_buff(
 782                                     (uchar_t *)&user_frame_buff_addr, uio_p,
 783                                     softc_p->usr_model, index, &index)) {
 784 
 785                                         return (EFAULT);
 786                                 }
 787 
 788 #ifdef _MULTI_DATAMODEL
 789                                 if (softc_p->usr_model == ILP32_PTR_SIZE) {
 790                                         user_frame_buff_addr =
 791                                             ((user_frame_buff_addr >> 32) &
 792                                             0xffffffffULL) |
 793                                             ((user_frame_buff_addr << 32) &
 794                                             0xffffffff00000000ULL);
 795                                 }
 796 #endif /* _MULTI_DATAMODEL */
 797 
 798                                 gotten_addr_flag = 1;
 799                         }
 800 
 801                         if (ddi_copyout(
 802                             (caddr_t)frame_data_p,
 803                             (caddr_t)user_frame_buff_addr,
 804                             g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode],
 805                             0)) {
 806                                 return (EFAULT);
 807                         }
 808 
 809                         /*
 810                          * if during the course of copying frame data,
 811                          * the device driver invalidated this read()
 812                          * request processing operation; restart this
 813                          * operation
 814                          */
 815 
 816                         mutex_enter(&softc_p->dcam_frame_is_done_mutex);
 817 
 818                         read_req_invalid = softc_p->reader_flags[read_ptr_id] &
 819                             DCAM1394_FLAG_READ_REQ_INVALID;
 820 
 821                         softc_p->reader_flags[read_ptr_id] &=
 822                             ~(DCAM1394_FLAG_READ_REQ_INVALID);
 823 
 824                         mutex_exit(&softc_p->dcam_frame_is_done_mutex);
 825 
 826                 } else {
 827                         mutex_exit(&softc_p->dcam_frame_is_done_mutex);
 828                         return (EAGAIN);
 829                 }
 830 
 831                 mutex_enter(&softc_p->dcam_frame_is_done_mutex);
 832         } while (read_req_invalid);
 833 
 834         /*
 835          * return number of bytes actually written to user space
 836          */
 837         uio_p->uio_resid -= g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode];
 838 
 839         softc_p->reader_flags[read_ptr_id] &= ~(DCAM1394_FLAG_READ_REQ_PROC);
 840 
 841         /* increment read pointer */
 842         ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
 843 
 844         mutex_exit(&softc_p->dcam_frame_is_done_mutex);
 845 
 846         return (0);
 847 }
 848 
 849 
 850 /*
 851  * dcam_ioctl
 852  */
 853 /* ARGSUSED */
 854 int
 855 dcam_ioctl(dev_t dev, int cmd, intptr_t  arg, int mode, cred_t *cred_p,
 856     int *rvalp)
 857 {
 858         dcam_state_t            *softc_p;
 859         dcam1394_param_list_t   *param_list;
 860         dcam1394_reg_io_t        dcam_reg_io;
 861         int                      instance, is_ctrl_file, rc, i;
 862 
 863         rc = 0;
 864         param_list = (dcam1394_param_list_t *)0;
 865 
 866         instance = DEV_TO_INSTANCE(dev);
 867 
 868         if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
 869                 rc = ENXIO;
 870                 goto done;
 871         }
 872 
 873         /*
 874          * determine user applications data model
 875          */
 876         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
 877                 softc_p->usr_model = ILP32_PTR_SIZE;
 878         else
 879                 softc_p->usr_model = LP64_PTR_SIZE;
 880 
 881 
 882         switch (cmd) {
 883 
 884         case DCAM1394_CMD_REG_READ:
 885                 if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
 886                     sizeof (dcam1394_reg_io_t), mode)) {
 887                         rc = EFAULT;
 888                         goto done;
 889                 }
 890 
 891                 if (dcam_reg_read(softc_p, &dcam_reg_io)) {
 892                         rc = EFAULT;
 893                         goto done;
 894                 }
 895 
 896                 if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
 897                     sizeof (dcam1394_reg_io_t), mode)) {
 898                         rc = EFAULT;
 899                         goto done;
 900                 }
 901                 break;
 902 
 903         case DCAM1394_CMD_REG_WRITE:
 904                 if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
 905                     sizeof (dcam1394_reg_io_t), mode)) {
 906                         rc = EFAULT;
 907                         goto done;
 908                 }
 909 
 910                 if (dcam_reg_write(softc_p, &dcam_reg_io)) {
 911                         rc = EFAULT;
 912                         goto done;
 913                 }
 914 
 915                 if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
 916                     sizeof (dcam1394_reg_io_t), mode)) {
 917                         rc = EFAULT;
 918                         goto done;
 919                 }
 920                 break;
 921 
 922         case DCAM1394_CMD_CAM_RESET:
 923                 if (dcam_reset(softc_p)) {
 924                         rc = EIO;
 925                         goto done;
 926                 }
 927                 break;
 928 
 929         case DCAM1394_CMD_PARAM_GET:
 930                 param_list = (dcam1394_param_list_t *)
 931                     kmem_alloc(sizeof (dcam1394_param_list_t), KM_SLEEP);
 932 
 933                 if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
 934                     sizeof (dcam1394_param_list_t), mode)) {
 935                         rc = EFAULT;
 936                         goto done;
 937                 }
 938 
 939                 if (dcam1394_ioctl_param_get(softc_p, *param_list)) {
 940                         rc = EINVAL;
 941                 }
 942 
 943                 if (ddi_copyout((caddr_t)param_list, (caddr_t)arg,
 944                     sizeof (dcam1394_param_list_t), mode)) {
 945                         rc = EFAULT;
 946                         goto done;
 947                 }
 948                 break;
 949 
 950         case DCAM1394_CMD_PARAM_SET:
 951                 param_list = (dcam1394_param_list_t *)
 952                     kmem_alloc((size_t)sizeof (dcam1394_param_list_t),
 953                     KM_SLEEP);
 954 
 955                 if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
 956                     sizeof (dcam1394_param_list_t), mode)) {
 957                         rc = EFAULT;
 958                         goto done;
 959                 }
 960 
 961                 is_ctrl_file = (getminor(dev) & DCAM1394_MINOR_CTRL) ? 1:0;
 962 
 963                 if (dcam1394_ioctl_param_set(softc_p, is_ctrl_file,
 964                     *param_list)) {
 965                         rc = EINVAL;
 966                 }
 967 
 968                 if (is_ctrl_file) {
 969                         mutex_enter(&softc_p->dcam_frame_is_done_mutex);
 970                         softc_p->param_status |= DCAM1394_STATUS_PARAM_CHANGE;
 971                         mutex_exit(&softc_p->dcam_frame_is_done_mutex);
 972                 }
 973 
 974                 if (ddi_copyout(param_list, (caddr_t)arg,
 975                     sizeof (dcam1394_param_list_t), mode)) {
 976                         rc = EFAULT;
 977                         goto done;
 978                 }
 979                 break;
 980 
 981         case DCAM1394_CMD_FRAME_RCV_START:
 982                 if (dcam1394_ioctl_frame_rcv_start(softc_p)) {
 983                         rc = ENXIO;
 984                 }
 985                 break;
 986 
 987         case DCAM1394_CMD_FRAME_RCV_STOP:
 988                 if (dcam_frame_rcv_stop(softc_p)) {
 989                         rc = ENXIO;
 990                 }
 991                 break;
 992 
 993         case DCAM1394_CMD_RING_BUFF_FLUSH:
 994                 if (softc_p->ring_buff_p == NULL) {
 995                         rc = EAGAIN;
 996                         break;
 997                 }
 998 
 999                 /*
1000                  * the simplest way to flush ring_buff is to empty it
1001                  */
1002                 for (i = 0; i < softc_p->ring_buff_p->num_read_ptrs; i++) {
1003                         softc_p->ring_buff_p->read_ptr_pos[i] =
1004                             softc_p->ring_buff_p->write_ptr_pos;
1005 
1006                         /*
1007                          * if device driver is processing a user
1008                          * process's read() request
1009                          */
1010                         if (softc_p->reader_flags[i] &
1011                             DCAM1394_FLAG_READ_REQ_PROC) {
1012 
1013                                 /*
1014                                  * invalidate the read() request processing
1015                                  * operation
1016                                  */
1017                                 softc_p->reader_flags[i] |=
1018                                     DCAM1394_FLAG_READ_REQ_INVALID;
1019                         }
1020                 }
1021                 break;
1022 
1023         case DCAM1394_CMD_FRAME_SEQ_NUM_COUNT_RESET:
1024                 mutex_enter(&softc_p->dcam_frame_is_done_mutex);
1025                 softc_p->seq_count = 0;
1026                 mutex_exit(&softc_p->dcam_frame_is_done_mutex);
1027                 break;
1028 
1029         default:
1030                 rc = EIO;
1031                 break;
1032 
1033         }
1034 
1035 done:
1036         if (param_list)
1037                 kmem_free(param_list, sizeof (dcam1394_param_list_t));
1038 
1039         return (rc);
1040 }
1041 
1042 
1043 /*
1044  * dcam_chpoll
1045  */
1046 /* ARGSUSED */
1047 int
1048 dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
1049     struct pollhead **phpp)
1050 {
1051         dcam_state_t    *softc_p;
1052         int              instance, ring_buff_has_data, read_ptr_id;
1053         size_t           read_ptr_pos, write_ptr_pos;
1054         short            revent;
1055 
1056         instance = DEV_TO_INSTANCE(dev);
1057 
1058         softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
1059         if (softc_p == NULL) {
1060                 return (ENXIO);
1061         }
1062 
1063         read_ptr_id     = 0;
1064         revent          = 0;
1065 
1066         if (softc_p->ring_buff_p == NULL) {
1067                 ring_buff_has_data = 0;
1068         } else {
1069                 mutex_enter(&softc_p->dcam_frame_is_done_mutex);
1070 
1071                 read_ptr_pos =
1072                     ring_buff_read_ptr_pos_get(softc_p->ring_buff_p,
1073                     read_ptr_id);
1074 
1075                 write_ptr_pos =
1076                     ring_buff_write_ptr_pos_get(softc_p->ring_buff_p);
1077 
1078                 if (read_ptr_pos != write_ptr_pos) {
1079                         ring_buff_has_data = 1;
1080                 } else {
1081                         ring_buff_has_data = 0;
1082                 }
1083 
1084                 mutex_exit(&softc_p->dcam_frame_is_done_mutex);
1085         }
1086 
1087         /*
1088          * now check for events
1089          */
1090         if ((events & POLLRDNORM) && ring_buff_has_data) {
1091                 revent |= POLLRDNORM;
1092         }
1093 
1094         if ((events & POLLPRI) && softc_p->param_status) {
1095                 revent |= POLLPRI;
1096         }
1097 
1098         /* if no events have occurred */
1099         if (revent == 0) {
1100                 if (!anyyet) {
1101                         *phpp = &softc_p->dcam_pollhead;
1102                 }
1103         }
1104 
1105         *reventsp = revent;
1106 
1107         return (0);
1108 }
1109 
1110 
1111 /*
1112  * dcam_bus_reset_notify
1113  */
1114 /* ARGSUSED */
1115 void
1116 dcam_bus_reset_notify(dev_info_t *dip, ddi_eventcookie_t ev_cookie, void *arg,
1117     void *impl_data)
1118 {
1119 
1120         dcam_state_t            *softc_p;
1121         t1394_localinfo_t       *localinfo = impl_data;
1122         t1394_targetinfo_t      targetinfo;
1123 
1124         softc_p = arg;
1125 
1126         /*
1127          * this is needed to handle LG camera "changing GUID" bug
1128          * XXX: What's this about?
1129          */
1130         if ((dip == NULL) || (arg == NULL) || (impl_data == NULL) ||
1131             (softc_p->sl_handle == NULL)) {
1132                 return;
1133         }
1134 
1135         localinfo = impl_data;
1136 
1137         /*
1138          * simply return if no target info
1139          */
1140         if (t1394_get_targetinfo(softc_p->sl_handle,
1141             localinfo->bus_generation, 0, &targetinfo) != DDI_SUCCESS)
1142                 return;
1143 
1144         if (localinfo->local_nodeID == softc_p->targetinfo.target_nodeID) {
1145                 softc_p->param_status |= DCAM1394_STATUS_CAM_UNPLUG;
1146         } else {
1147                 softc_p->param_status &= ~DCAM1394_STATUS_CAM_UNPLUG;
1148         }
1149 
1150         /* struct copies */
1151         softc_p->attachinfo.localinfo = *localinfo;
1152 
1153         if (targetinfo.target_nodeID != T1394_INVALID_NODEID) {
1154                 softc_p->targetinfo.current_max_payload =
1155                     targetinfo.current_max_payload;
1156 
1157                 softc_p->targetinfo.current_max_speed =
1158                     targetinfo.current_max_speed;
1159 
1160                 softc_p->targetinfo.target_nodeID =
1161                     targetinfo.target_nodeID;
1162         }
1163 }
1164 
1165 
1166 /*
1167  * byte_copy_to_user_buff
1168  */
1169 static int
1170 byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, size_t num_bytes,
1171     int start_index, int *end_index_p)
1172 {
1173         int      index;
1174         size_t   len;
1175         uchar_t *u8_p;
1176 
1177         index = start_index;
1178         u8_p  = (uchar_t *)src_addr_p;
1179 
1180         while (num_bytes) {
1181 
1182                 len = num_bytes;
1183 
1184                 if (uiomove(u8_p, len, UIO_READ, uio_p)) {
1185                         return (-1);
1186                 }
1187 
1188                 index++;
1189                 u8_p            += len;
1190                 num_bytes       -= len;
1191         }
1192 
1193         *end_index_p = index;
1194 
1195         return (0);
1196 }
1197 
1198 
1199 /*
1200  * byte_copy_from_user_buff
1201  */
1202 static int
1203 byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
1204     size_t num_bytes, int start_index, int *end_index_p)
1205 {
1206         int      index;
1207         size_t   len;
1208         uchar_t *u8_p;
1209 
1210         index = start_index;
1211         u8_p  = (uchar_t *)dst_addr_p;
1212 
1213         while (num_bytes) {
1214                 len = num_bytes;
1215 
1216                 if (uiomove(u8_p, len, UIO_WRITE, uio_p)) {
1217                         return (-1);
1218 
1219                 }
1220 
1221                 index++;
1222                 u8_p            += len;
1223                 num_bytes       -= len;
1224 
1225         }
1226 
1227         *end_index_p = index;
1228 
1229         return (0);
1230 }
1231 
1232 
1233 /*
1234  * dcam_reset()
1235  */
1236 static int
1237 dcam_reset(dcam_state_t *softc_p)
1238 {
1239         dcam1394_reg_io_t dcam_reg_io;
1240 
1241         dcam_reg_io.offs = DCAM1394_REG_OFFS_INITIALIZE;
1242         dcam_reg_io.val  = DCAM1394_REG_VAL_INITIALIZE_ASSERT;
1243 
1244         if (dcam_reg_write(softc_p, &dcam_reg_io)) {
1245                 return (-1);
1246         }
1247 
1248         /*
1249          * If the camera has a TI VSP, tweak the iris feature
1250          * to "on" and value 4.
1251          */
1252         dcam_reg_io.offs = DCAM1394_REG_OFFS_FEATURE_CSR_BASE +
1253             DCAM1394_REG_OFFS_IRIS_CSR;
1254         dcam_reg_io.val  = 0x82000004;
1255 
1256         if (dcam_reg_write(softc_p, &dcam_reg_io)) {
1257                 return (-1);
1258         }
1259 
1260         return (0);
1261 }