xref: /illumos-gate/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c (revision 9c88ac3ab4edaa5e8c0130ed1b4b376ea57c545a)
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 *)&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 /* 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 }
1249