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