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
_init(void)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
_info(struct modinfo * modinfop)160 _info(struct modinfo *modinfop)
161 {
162 int err;
163
164 err = mod_info(&modlinkage, modinfop);
165 return (err);
166 }
167
168
169 int
_fini(void)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
dcam_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
dcam_power(dev_info_t * dip,int component,int level)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
dcam_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)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
dcam_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
dcam_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)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
dcam_close(dev_t dev,int flags,int otyp,cred_t * cred_p)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
dcam_read(dev_t dev,struct uio * uio_p,cred_t * cred_p)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
dcam_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rvalp)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
dcam_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)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
dcam_bus_reset_notify(dev_info_t * dip,ddi_eventcookie_t ev_cookie,void * arg,void * impl_data)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
byte_copy_to_user_buff(uchar_t * src_addr_p,struct uio * uio_p,size_t num_bytes,int start_index,int * end_index_p)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
byte_copy_from_user_buff(uchar_t * dst_addr_p,struct uio * uio_p,size_t num_bytes,int start_index,int * end_index_p)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
dcam_reset(dcam_state_t * softc_p)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