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