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