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#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
64extern int tnf_mod_load(void);
65extern int tnf_mod_unload(struct modlinkage *mlp);
66#endif /* ! NPROBE */
67
68
69/* for power management (we have only one component) */
70static char *dcam_pmc[] = {
71	"NAME=dcam1394",
72	"0=Off",
73	"1=On"
74};
75
76int 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
86static 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);
88static 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);
90static int	dcam_reset(dcam_state_t *softc_p);
91
92/* opaque state structure head */
93void *dcam_state_p;
94
95static 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
117static 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
132extern	struct	mod_ops mod_driverops;
133
134static	struct modldrv modldrv = {
135	&mod_driverops,
136	"SUNW 1394-based Digital Camera driver",
137	&dcam_dev_ops,
138};
139
140static	struct modlinkage modlinkage = {
141	MODREV_1,
142	(void *)&modldrv,
143	NULL,
144};
145
146
147int
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
176int
177_info(struct modinfo *modinfop)
178{
179	int err;
180
181	err = mod_info(&modlinkage, modinfop);
182	return (err);
183}
184
185
186int
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 */
209int
210dcam_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 */
384int
385dcam_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 */
407int
408dcam_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 */
450int
451dcam_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 */
523int
524dcam_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 */
616int
617dcam_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 */
685int
686dcam_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 */
855int
856dcam_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
1036done:
1037	if (param_list)
1038		kmem_free(param_list, sizeof (dcam1394_param_list_t));
1039
1040	return (rc);
1041}
1042
1043
1044/* ARGSUSED */
1045int
1046dcam_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 */
1102void
1103dcam_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 */
1156static int
1157byte_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 */
1189static int
1190byte_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 */
1223static int
1224dcam_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