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