xref: /illumos-gate/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2018, Joyent, Inc.
25  */
26 
27 
28 /*
29  * dcam.c
30  *
31  * dcam1394 driver. Controls IIDC compliant devices attached through a
32  * IEEE-1394 bus.
33  */
34 
35 #include <sys/conf.h>
36 #include <sys/ddi.h>
37 #include <sys/modctl.h>
38 #include <sys/sunndi.h>
39 #include <sys/types.h>
40 #include <sys/ddi.h>
41 #include <sys/sunddi.h>
42 #include <sys/file.h>
43 #include <sys/errno.h>
44 #include <sys/open.h>
45 #include <sys/cred.h>
46 #include <sys/mkdev.h>
47 #include <sys/kmem.h>
48 #include <sys/stat.h>
49 #include <sys/cmn_err.h>
50 #include <sys/stream.h>
51 #include <sys/buf.h>
52 #include <sys/uio.h>
53 #include <sys/devops.h>
54 #include <sys/1394/t1394.h>
55 
56 #include <sys/dcam/dcam1394_io.h>
57 #include <sys/1394/targets/dcam1394/dcam.h>
58 #include <sys/1394/targets/dcam1394/dcam_reg.h>
59 #include <sys/1394/targets/dcam1394/dcam_param.h>
60 #include <sys/1394/targets/dcam1394/dcam_frame.h>
61 
62 /* for power management (we have only one component) */
63 static char *dcam_pmc[] = {
64 	"NAME=dcam1394",
65 	"0=Off",
66 	"1=On"
67 };
68 
69 int g_vid_mode_frame_num_bytes[] =
70 {
71 	57600,		/* vid mode 0 */
72 	153600,		/* vid mode 1 */
73 	460800,		/* vid mode 2 */
74 	614400,		/* vid mode 3 */
75 	921600,		/* vid mode 4 */
76 	307200		/* vid mode 5 */
77 };
78 
79 static int	byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p,
80 		    size_t num_bytes, int start_index, int *end_index);
81 static int	byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
82 		    size_t num_bytes, int start_index, int *end_index);
83 static int	dcam_reset(dcam_state_t *softc_p);
84 
85 /* opaque state structure head */
86 void *dcam_state_p;
87 
88 static struct cb_ops dcam_cb_ops = {
89 	dcam_open,		/* open		*/
90 	dcam_close,		/* close	*/
91 	nodev,			/* strategy	*/
92 	nodev,			/* print	*/
93 	nodev,			/* dump		*/
94 	dcam_read,		/* read		*/
95 	nodev,			/* write	*/
96 	dcam_ioctl,		/* ioctl	*/
97 	nodev,			/* devmap	*/
98 	nodev,			/* mmap		*/
99 	nodev,			/* segmap	*/
100 	dcam_chpoll,		/* chpoll	*/
101 	ddi_prop_op,		/* prop_op	*/
102 	NULL,			/* streams	*/
103 				/* flags	*/
104 	D_NEW | D_MP | D_64BIT | D_HOTPLUG,
105 	CB_REV,			/* rev		*/
106 	nodev,			/* aread	*/
107 	nodev			/* awrite	*/
108 };
109 
110 static struct dev_ops dcam_dev_ops = {
111 	DEVO_REV,		/* DEVO_REV indicated by manual	*/
112 	0,			/* device reference count	*/
113 	dcam_getinfo,		/* getinfo			*/
114 	nulldev,		/* identify			*/
115 	nulldev,		/* probe			*/
116 	dcam_attach,		/* attach			*/
117 	dcam_detach,		/* detach			*/
118 	nodev,			/* reset			*/
119 	&dcam_cb_ops,		/* ptr to cb_ops struct		*/
120 	NULL,			/* ptr to bus_ops struct; none	*/
121 	dcam_power,		/* power			*/
122 	ddi_quiesce_not_supported,	/* devo_quiesce */
123 };
124 
125 extern	struct	mod_ops mod_driverops;
126 
127 static	struct modldrv modldrv = {
128 	&mod_driverops,
129 	"SUNW 1394-based Digital Camera driver",
130 	&dcam_dev_ops,
131 };
132 
133 static	struct modlinkage modlinkage = {
134 	MODREV_1,
135 	(void *)&modldrv,
136 	NULL,
137 };
138 
139 
140 int
141 _init(void)
142 {
143 	int err;
144 
145 	err = ddi_soft_state_init(&dcam_state_p, sizeof (dcam_state_t), 2);
146 
147 	if (err) {
148 		return (err);
149 	}
150 
151 	if (err = mod_install(&modlinkage)) {
152 		ddi_soft_state_fini(&dcam_state_p);
153 	}
154 
155 	return (err);
156 }
157 
158 
159 int
160 _info(struct modinfo *modinfop)
161 {
162 	int err;
163 
164 	err = mod_info(&modlinkage, modinfop);
165 	return (err);
166 }
167 
168 
169 int
170 _fini(void)
171 {
172 	int err;
173 
174 	if ((err = mod_remove(&modlinkage)) != 0) {
175 		return (err);
176 	}
177 
178 	ddi_soft_state_fini(&dcam_state_p);
179 
180 	return (err);
181 }
182 
183 
184 /*
185  * dcam_attach
186  */
187 /* ARGSUSED */
188 int
189 dcam_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
190 {
191 	char			tmp_str[MAX_STR_LEN];
192 	dcam_state_t		*softc_p;
193 	ddi_eventcookie_t	ev_cookie;
194 	int			instance;
195 	int			ret_val;
196 
197 	switch (cmd) {
198 
199 	case DDI_ATTACH:
200 		instance = ddi_get_instance(dip);
201 
202 		if (ddi_soft_state_zalloc(dcam_state_p, instance) !=
203 		    DDI_SUCCESS) {
204 			return (DDI_FAILURE);
205 		}
206 
207 		if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
208 		    NULL) {
209 			ddi_soft_state_free(dcam_state_p, instance);
210 			return (DDI_FAILURE);
211 		}
212 
213 		/*
214 		 * Initialize soft state
215 		 */
216 		softc_p->dip			= dip;
217 		softc_p->instance		= instance;
218 		softc_p->usr_model		= -1;
219 		softc_p->ixlp			= NULL;
220 
221 		softc_p->seq_count 		= 0;
222 		softc_p->param_status 		= 0;
223 
224 		/*
225 		 * set default vid_mode, frame_rate and ring_buff_capacity
226 		 */
227 		softc_p->cur_vid_mode 		= 1;
228 		softc_p->cur_frame_rate 	= 3;
229 		softc_p->cur_ring_buff_capacity = 10;
230 		softc_p->camera_online		= 1;
231 
232 		(void) sprintf(tmp_str, "dcam%d", instance);
233 
234 		if (ddi_create_minor_node(dip, tmp_str, S_IFCHR, instance,
235 		    DDI_PSEUDO, 0) != DDI_SUCCESS) {
236 			ddi_soft_state_free(dcam_state_p, instance);
237 
238 			return (DDI_FAILURE);
239 		}
240 
241 		(void) sprintf(tmp_str, "dcamctl%d", instance);
242 
243 		if (ddi_create_minor_node(dip, tmp_str, S_IFCHR,
244 		    instance + DCAM1394_MINOR_CTRL, "ddi_dcam1394", 0) !=
245 		    DDI_SUCCESS) {
246 			ddi_soft_state_free(dcam_state_p, instance);
247 
248 			return (DDI_FAILURE);
249 		}
250 
251 		if (t1394_attach(dip, T1394_VERSION_V1, 0,
252 		    &(softc_p->attachinfo),
253 		    &(softc_p->sl_handle)) != DDI_SUCCESS) {
254 			ddi_soft_state_free(dcam_state_p, instance);
255 			ddi_remove_minor_node(dip, NULL);
256 
257 			return (DDI_FAILURE);
258 		}
259 
260 		if (t1394_get_targetinfo(softc_p->sl_handle,
261 		    softc_p->attachinfo.localinfo.bus_generation, 0,
262 		    &(softc_p->targetinfo)) != DDI_SUCCESS) {
263 			cmn_err(CE_WARN,
264 			    "dcam_attach: t1394_get_targetinfo failed\n");
265 		}
266 
267 		if (ddi_get_eventcookie(dip, DDI_DEVI_BUS_RESET_EVENT,
268 		    &ev_cookie) != DDI_SUCCESS) {
269 			(void) t1394_detach(&softc_p->sl_handle, 0);
270 
271 			ddi_soft_state_free(dcam_state_p, instance);
272 			ddi_remove_minor_node(dip, NULL);
273 
274 			return (DDI_FAILURE);
275 		}
276 
277 		if (ddi_add_event_handler(dip, ev_cookie, dcam_bus_reset_notify,
278 		    softc_p, &softc_p->event_id) != DDI_SUCCESS) {
279 			(void) t1394_detach(&softc_p->sl_handle, 0);
280 
281 			ddi_soft_state_free(dcam_state_p, instance);
282 			ddi_remove_minor_node(dip, NULL);
283 
284 			return (DDI_FAILURE);
285 		}
286 
287 		mutex_init(&softc_p->softc_mutex, NULL, MUTEX_DRIVER,
288 		    softc_p->attachinfo.iblock_cookie);
289 
290 		mutex_init(&softc_p->dcam_frame_is_done_mutex, NULL,
291 		    MUTEX_DRIVER, softc_p->attachinfo.iblock_cookie);
292 
293 		/*
294 		 * init the soft state's parameter attribute structure
295 		 */
296 		if (param_attr_init(softc_p, softc_p->param_attr) !=
297 		    DDI_SUCCESS) {
298 			(void) ddi_remove_event_handler(softc_p->event_id);
299 			(void) t1394_detach(&softc_p->sl_handle, 0);
300 
301 			ddi_soft_state_free(dcam_state_p, instance);
302 			ddi_remove_minor_node(dip, NULL);
303 
304 			return (DDI_FAILURE);
305 		}
306 
307 		/*
308 		 * power management stuff
309 		 */
310 		if (ddi_prop_update_string_array(DDI_DEV_T_NONE,
311 		    dip, "pm-components", dcam_pmc,
312 		    sizeof (dcam_pmc)/sizeof (char *)) == DDI_PROP_SUCCESS) {
313 
314 			(void) pm_raise_power(dip, 0, 1);
315 			if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0,
316 			    "power-managed?")) {
317 				(void) pm_idle_component(dip, 0);
318 			} else {
319 				(void) pm_busy_component(dip, 0);
320 			}
321 		}
322 
323 		softc_p->flags |= DCAM1394_FLAG_ATTACH_COMPLETE;
324 
325 		ddi_report_dev(dip);
326 		ret_val = DDI_SUCCESS;
327 		break;
328 
329 	case DDI_RESUME:
330 		instance = ddi_get_instance(dip);
331 		if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
332 		    NULL) {
333 			ddi_soft_state_free(dcam_state_p, instance);
334 			return (DDI_FAILURE);
335 		}
336 
337 		mutex_enter(&softc_p->softc_mutex);
338 
339 		if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
340 			(void) dcam1394_ioctl_frame_rcv_start(softc_p);
341 		}
342 
343 		softc_p->suspended = 0;
344 
345 		mutex_exit(&softc_p->softc_mutex);
346 
347 		ret_val = DDI_SUCCESS;
348 		break;
349 
350 	default:
351 		ret_val = DDI_FAILURE;
352 		break;
353 	}
354 
355 	return (ret_val);
356 }
357 
358 
359 /*
360  * dcam_power: perform dcam power management
361  */
362 /* ARGSUSED */
363 int
364 dcam_power(dev_info_t *dip, int component, int level)
365 {
366 	dcam_state_t	*softc_p;
367 	int		instance;
368 
369 	instance = ddi_get_instance(dip);
370 	softc_p  = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
371 
372 	if (softc_p == NULL)
373 		return (DDI_FAILURE);
374 
375 	softc_p->pm_cable_power = level;
376 
377 	return (DDI_SUCCESS);
378 
379 }
380 
381 
382 /*
383  * dcam_getinfo
384  */
385 /* ARGSUSED */
386 int
387 dcam_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
388 {
389 	dev_t		 dev;
390 	dcam_state_t	*softc_p;
391 	int		 status;
392 	int		 instance;
393 
394 	switch (cmd) {
395 
396 	case DDI_INFO_DEVT2DEVINFO:
397 		dev	 = (dev_t)arg;
398 		instance = DEV_TO_INSTANCE(dev);
399 		softc_p  = (dcam_state_t *)
400 		    ddi_get_soft_state(dcam_state_p, instance);
401 
402 		if (softc_p == NULL) {
403 			return (DDI_FAILURE);
404 		}
405 
406 		*result = (void *)softc_p->dip;
407 		status  = DDI_SUCCESS;
408 		break;
409 
410 	case DDI_INFO_DEVT2INSTANCE:
411 		dev	 = (dev_t)arg;
412 		instance = DEV_TO_INSTANCE(dev);
413 		*result	 = (void *)(uintptr_t)instance;
414 		status	 = DDI_SUCCESS;
415 		break;
416 
417 	default:
418 		status = DDI_FAILURE;
419 	}
420 
421 	return (status);
422 }
423 
424 
425 /*
426  * dcam_detach
427  */
428 /* ARGSUSED */
429 int
430 dcam_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
431 {
432 	int			 instance;
433 	dcam_state_t		*softc_p;
434 
435 	instance = ddi_get_instance(dip);
436 
437 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
438 	if (softc_p == NULL) {
439 		return (DDI_FAILURE);
440 	}
441 
442 
443 	switch (cmd) {
444 
445 	case DDI_SUSPEND:
446 		mutex_enter(&softc_p->softc_mutex);
447 
448 		softc_p->suspended = 1;
449 
450 		if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
451 			(void) dcam_frame_rcv_stop(softc_p);
452 		}
453 
454 		mutex_exit(&softc_p->softc_mutex);
455 		return (DDI_SUCCESS);
456 
457 
458 	case DDI_DETACH:
459 		/*
460 		 * power management stuff
461 		 */
462 		(void) pm_lower_power(dip, 0, 0);
463 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
464 
465 		/*
466 		 * deregister with 1394 DDI framework
467 		 */
468 		if (t1394_detach(&softc_p->sl_handle, 0) != DDI_SUCCESS) {
469 			return (DDI_FAILURE);
470 		}
471 
472 		(void) ddi_remove_event_handler(softc_p->event_id);
473 
474 		/*
475 		 * free state structures, mutexes, condvars;
476 		 * deregister interrupts
477 		 */
478 		mutex_destroy(&softc_p->softc_mutex);
479 		mutex_destroy(&softc_p->dcam_frame_is_done_mutex);
480 
481 		/*
482 		 * Remove all minor nodes, all dev_t's properties
483 		 */
484 		ddi_remove_minor_node(dip, NULL);
485 
486 		ddi_soft_state_free(dcam_state_p, instance);
487 		ddi_prop_remove_all(dip);
488 
489 		return (DDI_SUCCESS);
490 
491 	default:
492 		return (DDI_FAILURE);
493 
494 	}
495 }
496 
497 
498 /*
499  * dcam_open
500  */
501 /* ARGSUSED */
502 int
503 dcam_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
504 {
505 	dcam_state_t	*softc_p;
506 	int		instance;
507 	int		is_ctrl_file;
508 	uint_t		new_flags;
509 
510 	instance = (int)DEV_TO_INSTANCE(*dev_p);
511 
512 	if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
513 		return (ENXIO);
514 	}
515 
516 	/*
517 	 * if dcam_attach hasn't completed, return error
518 	 * XXX: Check this out
519 	 */
520 	if (!(softc_p->flags & DCAM1394_FLAG_ATTACH_COMPLETE)) {
521 		return (ENXIO);
522 	}
523 
524 	/* disallow block, mount, and layered opens */
525 	if (otyp != OTYP_CHR) {
526 		return (EINVAL);
527 	}
528 
529 	new_flags    = 0;
530 	is_ctrl_file = (getminor(*dev_p) & DCAM1394_MINOR_CTRL) ? 1 : 0;
531 
532 	mutex_enter(&softc_p->softc_mutex);
533 
534 	/*
535 	 * The open is either for the capture file or the control file.
536 	 * If it's the control file construct new flags.
537 	 *
538 	 * If it's the capture file return busy if it's already open,
539 	 * otherwise construct new flags.
540 	 */
541 	if (is_ctrl_file) {
542 		new_flags |= DCAM1394_FLAG_OPEN_CONTROL;
543 	} else {
544 		if (softc_p->flags & DCAM1394_FLAG_OPEN_CAPTURE) {
545 			mutex_exit(&softc_p->softc_mutex);
546 			return (EBUSY);
547 		}
548 
549 		new_flags |= DCAM1394_FLAG_OPEN_CAPTURE;
550 	}
551 
552 	new_flags |= DCAM1394_FLAG_OPEN;
553 	softc_p->flags |= new_flags;
554 
555 	mutex_exit(&softc_p->softc_mutex);
556 
557 	/*
558 	 * power management stuff
559 	 */
560 	if (softc_p->pm_open_count == 0) {
561 		if (ddi_prop_exists(DDI_DEV_T_ANY, softc_p->dip, 0,
562 		    "power-managed?")) {
563 			(void) pm_busy_component(softc_p->dip, 0);
564 			if (softc_p->pm_cable_power == 0) {
565 				int i;
566 
567 				(void) pm_raise_power(softc_p->dip, 0, 1);
568 
569 				/*
570 				 * Wait for the power to be up and stable
571 				 * before proceeding.  100 msecs should
572 				 * certainly be enough, and if we check
573 				 * every msec we'll probably loop just a
574 				 * few times.
575 				 */
576 				for (i = 0; i < 100; i++) {
577 					if (param_power_set(softc_p, 1) == 0) {
578 						break;
579 					}
580 					delay((clock_t)drv_usectohz(1000));
581 				}
582 			}
583 		}
584 	}
585 	softc_p->pm_open_count++;
586 
587 	return (0);
588 }
589 
590 
591 /*
592  * dcam_close
593  */
594 /* ARGSUSED */
595 int
596 dcam_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
597 {
598 	int instance;
599 	dcam_state_t *softc;
600 
601 	instance = DEV_TO_INSTANCE(dev);
602 	softc    = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
603 
604 	/*
605 	 * power management stuff
606 	 */
607 	softc->pm_open_count = 0;
608 	if (ddi_prop_exists(DDI_DEV_T_ANY, softc->dip, 0, "power-managed?")) {
609 		(void) pm_idle_component(softc->dip, 0);
610 	}
611 
612 	mutex_enter(&softc->softc_mutex);
613 
614 	if (getminor(dev) & DCAM1394_MINOR_CTRL) {
615 		softc->flags &= ~DCAM1394_FLAG_OPEN_CONTROL;
616 	} else {
617 		/*
618 		 * If an application which has opened the camera capture
619 		 * device exits without calling DCAM1394_CMD_FRAME_RCV_STOP
620 		 * ioctl, then we need to release resources.
621 		 */
622 		if (softc->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
623 			(void) dcam_frame_rcv_stop(softc);
624 			softc->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
625 		}
626 
627 		(void) param_power_set(softc, 0);
628 
629 		softc->flags &= ~DCAM1394_FLAG_OPEN_CAPTURE;
630 	}
631 
632 	/*
633 	 * If driver is completely closed, then stabilize the camera
634 	 * and turn off transient flags
635 	 */
636 	if (!(softc->flags &
637 	    (DCAM1394_FLAG_OPEN_CONTROL | DCAM1394_FLAG_OPEN_CAPTURE))) {
638 		softc->flags &= DCAM1394_FLAG_ATTACH_COMPLETE;
639 	}
640 
641 	mutex_exit(&softc->softc_mutex);
642 
643 	return (DDI_SUCCESS);
644 
645 }
646 
647 
648 /*
649  * dcam_read
650  *
651  * If read pointer is not pointing to the same position as write pointer
652  * copy frame data from ring buffer position pointed to by read pointer.
653  *
654  *	If during the course of copying frame data, the device driver
655  *	invalidated this read() request processing operation, restart
656  *	this operation.
657  *
658  *     Increment read pointer and return frame data to user process.
659  *
660  * Else return error
661  *
662  */
663 /* ARGSUSED */
664 int
665 dcam_read(dev_t dev, struct uio *uio_p, cred_t *cred_p)
666 {
667 	buff_info_t	*buff_info_p;
668 	dcam_state_t	*softc_p;
669 	hrtime_t	 timestamp;
670 	int		 index, instance;
671 	int		 read_ptr_id;
672 	size_t		 read_ptr_pos, write_ptr_pos;
673 	int		 read_req_invalid;
674 	ring_buff_t	*ring_buff_p;
675 	uchar_t		*frame_data_p;
676 	uint_t		 seq_num;
677 	unsigned long	 user_frame_buff_addr;
678 	uint_t		 vid_mode;
679 	int		 gotten_addr_flag;
680 
681 	instance = DEV_TO_INSTANCE(dev);
682 
683 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
684 	if (softc_p == NULL) {
685 		return (ENXIO);
686 	}
687 
688 	if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
689 		return (EAGAIN);
690 	}
691 
692 	read_ptr_id = 0;
693 
694 	mutex_enter(&softc_p->dcam_frame_is_done_mutex);
695 
696 	softc_p->reader_flags[read_ptr_id] |= DCAM1394_FLAG_READ_REQ_PROC;
697 
698 	user_frame_buff_addr = 0;
699 	gotten_addr_flag = 0;
700 
701 	do {
702 		read_ptr_pos = ring_buff_read_ptr_pos_get(ring_buff_p,
703 		    read_ptr_id);
704 
705 		write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
706 
707 		if (read_ptr_pos != write_ptr_pos) {
708 			/*
709 			 * Since the app wants realtime video, set the read
710 			 * pointer to the newest data.
711 			 */
712 			if (write_ptr_pos == 0) {
713 				read_ptr_pos = ring_buff_p->num_buffs - 1;
714 			} else {
715 				read_ptr_pos = write_ptr_pos - 1;
716 			}
717 
718 			/*
719 			 * copy frame data from ring buffer position pointed
720 			 * to by read pointer
721 			 */
722 			index = 0;
723 			buff_info_p =
724 			    &(ring_buff_p->buff_info_array_p[read_ptr_pos]);
725 
726 			vid_mode = softc_p->cur_vid_mode;
727 			seq_num  = buff_info_p->seq_num;
728 			timestamp = buff_info_p->timestamp;
729 			frame_data_p = (uchar_t *)buff_info_p->kaddr_p;
730 
731 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
732 
733 			/*
734 			 * Fix for bug #4424042
735 			 * don't lock this section
736 			 */
737 
738 			if (byte_copy_to_user_buff((uchar_t *)&vid_mode,
739 			    uio_p, sizeof (uint_t), index, &index)) {
740 
741 				return (EFAULT);
742 			}
743 
744 			if (byte_copy_to_user_buff((uchar_t *)&seq_num,
745 			    uio_p, sizeof (unsigned int), index, &index)) {
746 
747 				return (EFAULT);
748 			}
749 
750 			if (byte_copy_to_user_buff((uchar_t *)&timestamp,
751 			    uio_p, sizeof (hrtime_t), index, &index)) {
752 
753 				return (EFAULT);
754 			}
755 
756 			/*
757 			 * get buff pointer; do ddi_copyout()
758 			 * get user buffer address only once
759 			 */
760 			if (!gotten_addr_flag) {
761 				if (byte_copy_from_user_buff(
762 				    (uchar_t *)&user_frame_buff_addr, uio_p,
763 				    softc_p->usr_model, index, &index)) {
764 
765 					return (EFAULT);
766 				}
767 
768 #ifdef _MULTI_DATAMODEL
769 				if (softc_p->usr_model == ILP32_PTR_SIZE) {
770 					user_frame_buff_addr =
771 					    ((user_frame_buff_addr >> 32) &
772 					    0xffffffffULL) |
773 					    ((user_frame_buff_addr << 32) &
774 					    0xffffffff00000000ULL);
775 				}
776 #endif /* _MULTI_DATAMODEL */
777 
778 				gotten_addr_flag = 1;
779 			}
780 
781 			if (ddi_copyout(
782 			    (caddr_t)frame_data_p,
783 			    (caddr_t)user_frame_buff_addr,
784 			    g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode],
785 			    0)) {
786 				return (EFAULT);
787 			}
788 
789 			/*
790 			 * if during the course of copying frame data,
791 			 * the device driver invalidated this read()
792 			 * request processing operation; restart this
793 			 * operation
794 			 */
795 
796 			mutex_enter(&softc_p->dcam_frame_is_done_mutex);
797 
798 			read_req_invalid = softc_p->reader_flags[read_ptr_id] &
799 			    DCAM1394_FLAG_READ_REQ_INVALID;
800 
801 			softc_p->reader_flags[read_ptr_id] &=
802 			    ~(DCAM1394_FLAG_READ_REQ_INVALID);
803 
804 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
805 
806 		} else {
807 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
808 			return (EAGAIN);
809 		}
810 
811 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
812 	} while (read_req_invalid);
813 
814 	/*
815 	 * return number of bytes actually written to user space
816 	 */
817 	uio_p->uio_resid -= g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode];
818 
819 	softc_p->reader_flags[read_ptr_id] &= ~(DCAM1394_FLAG_READ_REQ_PROC);
820 
821 	/* increment read pointer */
822 	ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
823 
824 	mutex_exit(&softc_p->dcam_frame_is_done_mutex);
825 
826 	return (0);
827 }
828 
829 
830 /*
831  * dcam_ioctl
832  */
833 /* ARGSUSED */
834 int
835 dcam_ioctl(dev_t dev, int cmd, intptr_t  arg, int mode, cred_t *cred_p,
836     int *rvalp)
837 {
838 	dcam_state_t		*softc_p;
839 	dcam1394_param_list_t	*param_list;
840 	dcam1394_reg_io_t	 dcam_reg_io;
841 	int			 instance, is_ctrl_file, rc, i;
842 
843 	rc = 0;
844 	param_list = (dcam1394_param_list_t *)0;
845 
846 	instance = DEV_TO_INSTANCE(dev);
847 
848 	if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
849 		rc = ENXIO;
850 		goto done;
851 	}
852 
853 	/*
854 	 * determine user applications data model
855 	 */
856 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
857 		softc_p->usr_model = ILP32_PTR_SIZE;
858 	else
859 		softc_p->usr_model = LP64_PTR_SIZE;
860 
861 
862 	switch (cmd) {
863 
864 	case DCAM1394_CMD_REG_READ:
865 		if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
866 		    sizeof (dcam1394_reg_io_t), mode)) {
867 			rc = EFAULT;
868 			goto done;
869 		}
870 
871 		if (dcam_reg_read(softc_p, &dcam_reg_io)) {
872 			rc = EFAULT;
873 			goto done;
874 		}
875 
876 		if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
877 		    sizeof (dcam1394_reg_io_t), mode)) {
878 			rc = EFAULT;
879 			goto done;
880 		}
881 		break;
882 
883 	case DCAM1394_CMD_REG_WRITE:
884 		if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
885 		    sizeof (dcam1394_reg_io_t), mode)) {
886 			rc = EFAULT;
887 			goto done;
888 		}
889 
890 		if (dcam_reg_write(softc_p, &dcam_reg_io)) {
891 			rc = EFAULT;
892 			goto done;
893 		}
894 
895 		if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
896 		    sizeof (dcam1394_reg_io_t), mode)) {
897 			rc = EFAULT;
898 			goto done;
899 		}
900 		break;
901 
902 	case DCAM1394_CMD_CAM_RESET:
903 		if (dcam_reset(softc_p)) {
904 			rc = EIO;
905 			goto done;
906 		}
907 		break;
908 
909 	case DCAM1394_CMD_PARAM_GET:
910 		param_list = (dcam1394_param_list_t *)
911 		    kmem_alloc(sizeof (dcam1394_param_list_t), KM_SLEEP);
912 
913 		if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
914 		    sizeof (dcam1394_param_list_t), mode)) {
915 			rc = EFAULT;
916 			goto done;
917 		}
918 
919 		if (dcam1394_ioctl_param_get(softc_p, *param_list)) {
920 			rc = EINVAL;
921 		}
922 
923 		if (ddi_copyout((caddr_t)param_list, (caddr_t)arg,
924 		    sizeof (dcam1394_param_list_t), mode)) {
925 			rc = EFAULT;
926 			goto done;
927 		}
928 		break;
929 
930 	case DCAM1394_CMD_PARAM_SET:
931 		param_list = (dcam1394_param_list_t *)
932 		    kmem_alloc((size_t)sizeof (dcam1394_param_list_t),
933 		    KM_SLEEP);
934 
935 		if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
936 		    sizeof (dcam1394_param_list_t), mode)) {
937 			rc = EFAULT;
938 			goto done;
939 		}
940 
941 		is_ctrl_file = (getminor(dev) & DCAM1394_MINOR_CTRL) ? 1:0;
942 
943 		if (dcam1394_ioctl_param_set(softc_p, is_ctrl_file,
944 		    *param_list)) {
945 			rc = EINVAL;
946 		}
947 
948 		if (is_ctrl_file) {
949 			mutex_enter(&softc_p->dcam_frame_is_done_mutex);
950 			softc_p->param_status |= DCAM1394_STATUS_PARAM_CHANGE;
951 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
952 		}
953 
954 		if (ddi_copyout(param_list, (caddr_t)arg,
955 		    sizeof (dcam1394_param_list_t), mode)) {
956 			rc = EFAULT;
957 			goto done;
958 		}
959 		break;
960 
961 	case DCAM1394_CMD_FRAME_RCV_START:
962 		if (dcam1394_ioctl_frame_rcv_start(softc_p)) {
963 			rc = ENXIO;
964 		}
965 		break;
966 
967 	case DCAM1394_CMD_FRAME_RCV_STOP:
968 		if (dcam_frame_rcv_stop(softc_p)) {
969 			rc = ENXIO;
970 		}
971 		break;
972 
973 	case DCAM1394_CMD_RING_BUFF_FLUSH:
974 		if (softc_p->ring_buff_p == NULL) {
975 			rc = EAGAIN;
976 			break;
977 		}
978 
979 		/*
980 		 * the simplest way to flush ring_buff is to empty it
981 		 */
982 		for (i = 0; i < softc_p->ring_buff_p->num_read_ptrs; i++) {
983 			softc_p->ring_buff_p->read_ptr_pos[i] =
984 			    softc_p->ring_buff_p->write_ptr_pos;
985 
986 			/*
987 			 * if device driver is processing a user
988 			 * process's read() request
989 			 */
990 			if (softc_p->reader_flags[i] &
991 			    DCAM1394_FLAG_READ_REQ_PROC) {
992 
993 				/*
994 				 * invalidate the read() request processing
995 				 * operation
996 				 */
997 				softc_p->reader_flags[i] |=
998 				    DCAM1394_FLAG_READ_REQ_INVALID;
999 			}
1000 		}
1001 		break;
1002 
1003 	case DCAM1394_CMD_FRAME_SEQ_NUM_COUNT_RESET:
1004 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
1005 		softc_p->seq_count = 0;
1006 		mutex_exit(&softc_p->dcam_frame_is_done_mutex);
1007 		break;
1008 
1009 	default:
1010 		rc = EIO;
1011 		break;
1012 
1013 	}
1014 
1015 done:
1016 	if (param_list)
1017 		kmem_free(param_list, sizeof (dcam1394_param_list_t));
1018 
1019 	return (rc);
1020 }
1021 
1022 
1023 /* ARGSUSED */
1024 int
1025 dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
1026     struct pollhead **phpp)
1027 {
1028 	dcam_state_t	*softc_p;
1029 	int		instance;
1030 	short		revent = 0;
1031 
1032 	/*
1033 	 * Without the logic to perform wakeups (see comment below), reject
1034 	 * attempts at edge-triggered polling.
1035 	 */
1036 	if (events & POLLET) {
1037 		return (EPERM);
1038 	}
1039 
1040 	instance = DEV_TO_INSTANCE(dev);
1041 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
1042 	if (softc_p == NULL) {
1043 		return (ENXIO);
1044 	}
1045 
1046 	if (softc_p->ring_buff_p != NULL) {
1047 		size_t read_ptr_pos, write_ptr_pos;
1048 
1049 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
1050 		read_ptr_pos =
1051 		    ring_buff_read_ptr_pos_get(softc_p->ring_buff_p, 0);
1052 		write_ptr_pos =
1053 		    ring_buff_write_ptr_pos_get(softc_p->ring_buff_p);
1054 		mutex_exit(&softc_p->dcam_frame_is_done_mutex);
1055 
1056 		if ((events & POLLRDNORM) && read_ptr_pos != write_ptr_pos) {
1057 			revent |= POLLRDNORM;
1058 		}
1059 	}
1060 
1061 	if ((events & POLLPRI) && softc_p->param_status) {
1062 		revent |= POLLPRI;
1063 	}
1064 
1065 	/*
1066 	 * No portion of this driver was ever wired up to perform a
1067 	 * pollwakeup() on an associated pollhead.  The lack of an emitted
1068 	 * pollhead informs poll/devpoll that the event status of this resource
1069 	 * is not cacheable.
1070 	 */
1071 	*reventsp = revent;
1072 
1073 	return (0);
1074 }
1075 
1076 
1077 /*
1078  * dcam_bus_reset_notify
1079  */
1080 /* ARGSUSED */
1081 void
1082 dcam_bus_reset_notify(dev_info_t *dip, ddi_eventcookie_t ev_cookie, void *arg,
1083     void *impl_data)
1084 {
1085 
1086 	dcam_state_t 		*softc_p;
1087 	t1394_localinfo_t 	*localinfo = impl_data;
1088 	t1394_targetinfo_t 	targetinfo;
1089 
1090 	softc_p = arg;
1091 
1092 	/*
1093 	 * this is needed to handle LG camera "changing GUID" bug
1094 	 * XXX: What's this about?
1095 	 */
1096 	if ((dip == NULL) || (arg == NULL) || (impl_data == NULL) ||
1097 	    (softc_p->sl_handle == NULL)) {
1098 		return;
1099 	}
1100 
1101 	localinfo = impl_data;
1102 
1103 	/*
1104 	 * simply return if no target info
1105 	 */
1106 	if (t1394_get_targetinfo(softc_p->sl_handle,
1107 	    localinfo->bus_generation, 0, &targetinfo) != DDI_SUCCESS)
1108 		return;
1109 
1110 	if (localinfo->local_nodeID == softc_p->targetinfo.target_nodeID) {
1111 		softc_p->param_status |= DCAM1394_STATUS_CAM_UNPLUG;
1112 	} else {
1113 		softc_p->param_status &= ~DCAM1394_STATUS_CAM_UNPLUG;
1114 	}
1115 
1116 	/* struct copies */
1117 	softc_p->attachinfo.localinfo = *localinfo;
1118 
1119 	if (targetinfo.target_nodeID != T1394_INVALID_NODEID) {
1120 		softc_p->targetinfo.current_max_payload =
1121 		    targetinfo.current_max_payload;
1122 
1123 		softc_p->targetinfo.current_max_speed =
1124 		    targetinfo.current_max_speed;
1125 
1126 		softc_p->targetinfo.target_nodeID =
1127 		    targetinfo.target_nodeID;
1128 	}
1129 }
1130 
1131 
1132 /*
1133  * byte_copy_to_user_buff
1134  */
1135 static int
1136 byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, size_t num_bytes,
1137     int start_index, int *end_index_p)
1138 {
1139 	int	 index;
1140 	size_t	 len;
1141 	uchar_t	*u8_p;
1142 
1143 	index = start_index;
1144 	u8_p  = (uchar_t *)src_addr_p;
1145 
1146 	while (num_bytes) {
1147 
1148 		len = num_bytes;
1149 
1150 		if (uiomove(u8_p, len, UIO_READ, uio_p)) {
1151 			return (-1);
1152 		}
1153 
1154 		index++;
1155 		u8_p		+= len;
1156 		num_bytes	-= len;
1157 	}
1158 
1159 	*end_index_p = index;
1160 
1161 	return (0);
1162 }
1163 
1164 
1165 /*
1166  * byte_copy_from_user_buff
1167  */
1168 static int
1169 byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
1170     size_t num_bytes, int start_index, int *end_index_p)
1171 {
1172 	int	 index;
1173 	size_t	 len;
1174 	uchar_t	*u8_p;
1175 
1176 	index = start_index;
1177 	u8_p  = (uchar_t *)dst_addr_p;
1178 
1179 	while (num_bytes) {
1180 		len = num_bytes;
1181 
1182 		if (uiomove(u8_p, len, UIO_WRITE, uio_p)) {
1183 			return (-1);
1184 
1185 		}
1186 
1187 		index++;
1188 		u8_p		+= len;
1189 		num_bytes	-= len;
1190 
1191 	}
1192 
1193 	*end_index_p = index;
1194 
1195 	return (0);
1196 }
1197 
1198 
1199 /*
1200  * dcam_reset()
1201  */
1202 static int
1203 dcam_reset(dcam_state_t *softc_p)
1204 {
1205 	dcam1394_reg_io_t dcam_reg_io;
1206 
1207 	dcam_reg_io.offs = DCAM1394_REG_OFFS_INITIALIZE;
1208 	dcam_reg_io.val  = DCAM1394_REG_VAL_INITIALIZE_ASSERT;
1209 
1210 	if (dcam_reg_write(softc_p, &dcam_reg_io)) {
1211 		return (-1);
1212 	}
1213 
1214 	/*
1215 	 * If the camera has a TI VSP, tweak the iris feature
1216 	 * to "on" and value 4.
1217 	 */
1218 	dcam_reg_io.offs = DCAM1394_REG_OFFS_FEATURE_CSR_BASE +
1219 	    DCAM1394_REG_OFFS_IRIS_CSR;
1220 	dcam_reg_io.val  = 0x82000004;
1221 
1222 	if (dcam_reg_write(softc_p, &dcam_reg_io)) {
1223 		return (-1);
1224 	}
1225 
1226 	return (0);
1227 }
1228