xref: /illumos-gate/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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 *)&timestamp,
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