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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * dcam.c 31 * 32 * dcam1394 driver. Controls IIDC compliant devices attached through a 33 * IEEE-1394 bus. 34 */ 35 36 #include <sys/conf.h> 37 #include <sys/ddi.h> 38 #include <sys/modctl.h> 39 #include <sys/sunndi.h> 40 #include <sys/types.h> 41 #include <sys/ddi.h> 42 #include <sys/sunddi.h> 43 #include <sys/file.h> 44 #include <sys/errno.h> 45 #include <sys/open.h> 46 #include <sys/cred.h> 47 #include <sys/mkdev.h> 48 #include <sys/kmem.h> 49 #include <sys/stat.h> 50 #include <sys/cmn_err.h> 51 #include <sys/stream.h> 52 #include <sys/buf.h> 53 #include <sys/uio.h> 54 #include <sys/devops.h> 55 #include <sys/1394/t1394.h> 56 #include <sys/tnf_probe.h> 57 58 #include <sys/dcam/dcam1394_io.h> 59 #include <sys/1394/targets/dcam1394/dcam.h> 60 #include <sys/1394/targets/dcam1394/dcam_reg.h> 61 #include <sys/1394/targets/dcam1394/dcam_param.h> 62 #include <sys/1394/targets/dcam1394/dcam_frame.h> 63 64 #ifndef NPROBE 65 extern int tnf_mod_load(void); 66 extern int tnf_mod_unload(struct modlinkage *mlp); 67 #endif /* ! NPROBE */ 68 69 70 /* for power management (we have only one component) */ 71 static char *dcam_pmc[] = { 72 "NAME=dcam1394", 73 "0=Off", 74 "1=On" 75 }; 76 77 int g_vid_mode_frame_num_bytes[] = 78 { 79 57600, /* vid mode 0 */ 80 153600, /* vid mode 1 */ 81 460800, /* vid mode 2 */ 82 614400, /* vid mode 3 */ 83 921600, /* vid mode 4 */ 84 307200 /* vid mode 5 */ 85 }; 86 87 static int byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, 88 size_t num_bytes, int start_index, int *end_index); 89 static int byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p, 90 size_t num_bytes, int start_index, int *end_index); 91 static int dcam_reset(dcam_state_t *softc_p); 92 93 /* opaque state structure head */ 94 void *dcam_state_p; 95 96 static struct cb_ops dcam_cb_ops = { 97 dcam_open, /* open */ 98 dcam_close, /* close */ 99 nodev, /* strategy */ 100 nodev, /* print */ 101 nodev, /* dump */ 102 dcam_read, /* read */ 103 nodev, /* write */ 104 dcam_ioctl, /* ioctl */ 105 nodev, /* devmap */ 106 nodev, /* mmap */ 107 nodev, /* segmap */ 108 dcam_chpoll, /* chpoll */ 109 ddi_prop_op, /* prop_op */ 110 NULL, /* streams */ 111 /* flags */ 112 D_NEW | D_MP | D_64BIT | D_HOTPLUG, 113 CB_REV, /* rev */ 114 nodev, /* aread */ 115 nodev /* awrite */ 116 }; 117 118 static struct dev_ops dcam_dev_ops = { 119 DEVO_REV, /* DEVO_REV indicated by manual */ 120 0, /* device reference count */ 121 dcam_getinfo, /* getinfo */ 122 nulldev, /* identify */ 123 nulldev, /* probe */ 124 dcam_attach, /* attach */ 125 dcam_detach, /* detach */ 126 nodev, /* reset */ 127 &dcam_cb_ops, /* ptr to cb_ops struct */ 128 NULL, /* ptr to bus_ops struct; none */ 129 dcam_power, /* power */ 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 1.0", 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 *)×tamp, 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 /* 1045 * dcam_chpoll 1046 */ 1047 /* ARGSUSED */ 1048 int 1049 dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 1050 struct pollhead **phpp) 1051 { 1052 dcam_state_t *softc_p; 1053 int instance, ring_buff_has_data, read_ptr_id; 1054 size_t read_ptr_pos, write_ptr_pos; 1055 short revent; 1056 1057 instance = DEV_TO_INSTANCE(dev); 1058 1059 softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance); 1060 if (softc_p == NULL) { 1061 return (ENXIO); 1062 } 1063 1064 read_ptr_id = 0; 1065 revent = 0; 1066 1067 if (softc_p->ring_buff_p == NULL) { 1068 ring_buff_has_data = 0; 1069 } else { 1070 mutex_enter(&softc_p->dcam_frame_is_done_mutex); 1071 1072 read_ptr_pos = 1073 ring_buff_read_ptr_pos_get(softc_p->ring_buff_p, 1074 read_ptr_id); 1075 1076 write_ptr_pos = 1077 ring_buff_write_ptr_pos_get(softc_p->ring_buff_p); 1078 1079 if (read_ptr_pos != write_ptr_pos) { 1080 ring_buff_has_data = 1; 1081 } else { 1082 ring_buff_has_data = 0; 1083 } 1084 1085 mutex_exit(&softc_p->dcam_frame_is_done_mutex); 1086 } 1087 1088 /* 1089 * now check for events 1090 */ 1091 if ((events & POLLRDNORM) && ring_buff_has_data) { 1092 revent |= POLLRDNORM; 1093 } 1094 1095 if ((events & POLLPRI) && softc_p->param_status) { 1096 revent |= POLLPRI; 1097 } 1098 1099 /* if no events have occurred */ 1100 if (revent == 0) { 1101 if (!anyyet) { 1102 *phpp = &softc_p->dcam_pollhead; 1103 } 1104 } 1105 1106 *reventsp = revent; 1107 1108 return (0); 1109 } 1110 1111 1112 /* 1113 * dcam_bus_reset_notify 1114 */ 1115 /* ARGSUSED */ 1116 void 1117 dcam_bus_reset_notify(dev_info_t *dip, ddi_eventcookie_t ev_cookie, void *arg, 1118 void *impl_data) 1119 { 1120 1121 dcam_state_t *softc_p; 1122 t1394_localinfo_t *localinfo = impl_data; 1123 t1394_targetinfo_t targetinfo; 1124 1125 softc_p = arg; 1126 1127 /* 1128 * this is needed to handle LG camera "changing GUID" bug 1129 * XXX: What's this about? 1130 */ 1131 if ((dip == NULL) || (arg == NULL) || (impl_data == NULL) || 1132 (softc_p->sl_handle == NULL)) { 1133 return; 1134 } 1135 1136 localinfo = impl_data; 1137 1138 /* 1139 * simply return if no target info 1140 */ 1141 if (t1394_get_targetinfo(softc_p->sl_handle, 1142 localinfo->bus_generation, 0, &targetinfo) != DDI_SUCCESS) 1143 return; 1144 1145 if (localinfo->local_nodeID == softc_p->targetinfo.target_nodeID) { 1146 softc_p->param_status |= DCAM1394_STATUS_CAM_UNPLUG; 1147 } else { 1148 softc_p->param_status &= ~DCAM1394_STATUS_CAM_UNPLUG; 1149 } 1150 1151 /* struct copies */ 1152 softc_p->attachinfo.localinfo = *localinfo; 1153 1154 if (targetinfo.target_nodeID != T1394_INVALID_NODEID) { 1155 softc_p->targetinfo.current_max_payload = 1156 targetinfo.current_max_payload; 1157 1158 softc_p->targetinfo.current_max_speed = 1159 targetinfo.current_max_speed; 1160 1161 softc_p->targetinfo.target_nodeID = 1162 targetinfo.target_nodeID; 1163 } 1164 } 1165 1166 1167 /* 1168 * byte_copy_to_user_buff 1169 */ 1170 static int 1171 byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, size_t num_bytes, 1172 int start_index, int *end_index_p) 1173 { 1174 int index; 1175 size_t len; 1176 uchar_t *u8_p; 1177 1178 index = start_index; 1179 u8_p = (uchar_t *)src_addr_p; 1180 1181 while (num_bytes) { 1182 1183 len = num_bytes; 1184 1185 if (uiomove(u8_p, len, UIO_READ, uio_p)) { 1186 return (-1); 1187 } 1188 1189 index++; 1190 u8_p += len; 1191 num_bytes -= len; 1192 } 1193 1194 *end_index_p = index; 1195 1196 return (0); 1197 } 1198 1199 1200 /* 1201 * byte_copy_from_user_buff 1202 */ 1203 static int 1204 byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p, 1205 size_t num_bytes, int start_index, int *end_index_p) 1206 { 1207 int index; 1208 size_t len; 1209 uchar_t *u8_p; 1210 1211 index = start_index; 1212 u8_p = (uchar_t *)dst_addr_p; 1213 1214 while (num_bytes) { 1215 len = num_bytes; 1216 1217 if (uiomove(u8_p, len, UIO_WRITE, uio_p)) { 1218 return (-1); 1219 1220 } 1221 1222 index++; 1223 u8_p += len; 1224 num_bytes -= len; 1225 1226 } 1227 1228 *end_index_p = index; 1229 1230 return (0); 1231 } 1232 1233 1234 /* 1235 * dcam_reset() 1236 */ 1237 static int 1238 dcam_reset(dcam_state_t *softc_p) 1239 { 1240 dcam1394_reg_io_t dcam_reg_io; 1241 1242 dcam_reg_io.offs = DCAM1394_REG_OFFS_INITIALIZE; 1243 dcam_reg_io.val = DCAM1394_REG_VAL_INITIALIZE_ASSERT; 1244 1245 if (dcam_reg_write(softc_p, &dcam_reg_io)) { 1246 return (-1); 1247 } 1248 1249 /* 1250 * If the camera has a TI VSP, tweak the iris feature 1251 * to "on" and value 4. 1252 */ 1253 dcam_reg_io.offs = DCAM1394_REG_OFFS_FEATURE_CSR_BASE + 1254 DCAM1394_REG_OFFS_IRIS_CSR; 1255 dcam_reg_io.val = 0x82000004; 1256 1257 if (dcam_reg_write(softc_p, &dcam_reg_io)) { 1258 return (-1); 1259 } 1260 1261 return (0); 1262 } 1263