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
_init(void)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
_info(struct modinfo * modinfop)176 _info(struct modinfo *modinfop)
177 {
178 int err;
179
180 err = mod_info(&modlinkage, modinfop);
181 return (err);
182 }
183
184
185 int
_fini(void)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
dcam_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
dcam_power(dev_info_t * dip,int component,int level)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
dcam_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)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
dcam_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
dcam_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)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
dcam_close(dev_t dev,int flags,int otyp,cred_t * cred_p)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
dcam_read(dev_t dev,struct uio * uio_p,cred_t * cred_p)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
dcam_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rvalp)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
dcam_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)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
dcam_bus_reset_notify(dev_info_t * dip,ddi_eventcookie_t ev_cookie,void * arg,void * impl_data)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
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)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
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)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
dcam_reset(dcam_state_t * softc_p)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 }
1262