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 *)×tamp, 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 }