xref: /onnv-gate/usr/src/uts/common/io/1394/targets/dcam1394/dcam.c (revision 7656:2621e50fdf4a)
121Sap25164 /*
221Sap25164  * CDDL HEADER START
321Sap25164  *
421Sap25164  * The contents of this file are subject to the terms of the
5*7656SSherry.Moore@Sun.COM  * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM  * You may not use this file except in compliance with the License.
721Sap25164  *
821Sap25164  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
921Sap25164  * or http://www.opensolaris.org/os/licensing.
1021Sap25164  * See the License for the specific language governing permissions
1121Sap25164  * and limitations under the License.
1221Sap25164  *
1321Sap25164  * When distributing Covered Code, include this CDDL HEADER in each
1421Sap25164  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1521Sap25164  * If applicable, add the following below this CDDL HEADER, with the
1621Sap25164  * fields enclosed by brackets "[]" replaced with your own identifying
1721Sap25164  * information: Portions Copyright [yyyy] [name of copyright owner]
1821Sap25164  *
1921Sap25164  * CDDL HEADER END
2021Sap25164  */
2121Sap25164 /*
22*7656SSherry.Moore@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2321Sap25164  * Use is subject to license terms.
2421Sap25164  */
2521Sap25164 
2621Sap25164 
2721Sap25164 /*
2821Sap25164  * dcam.c
2921Sap25164  *
3021Sap25164  * dcam1394 driver. Controls IIDC compliant devices attached through a
3121Sap25164  * IEEE-1394 bus.
3221Sap25164  */
3321Sap25164 
3421Sap25164 #include <sys/conf.h>
3521Sap25164 #include <sys/ddi.h>
3621Sap25164 #include <sys/modctl.h>
3721Sap25164 #include <sys/sunndi.h>
3821Sap25164 #include <sys/types.h>
3921Sap25164 #include <sys/ddi.h>
4021Sap25164 #include <sys/sunddi.h>
4121Sap25164 #include <sys/file.h>
4221Sap25164 #include <sys/errno.h>
4321Sap25164 #include <sys/open.h>
4421Sap25164 #include <sys/cred.h>
4521Sap25164 #include <sys/mkdev.h>
4621Sap25164 #include <sys/kmem.h>
4721Sap25164 #include <sys/stat.h>
4821Sap25164 #include <sys/cmn_err.h>
4921Sap25164 #include <sys/stream.h>
5021Sap25164 #include <sys/buf.h>
5121Sap25164 #include <sys/uio.h>
5221Sap25164 #include <sys/devops.h>
5321Sap25164 #include <sys/1394/t1394.h>
5421Sap25164 #include <sys/tnf_probe.h>
5521Sap25164 
5621Sap25164 #include <sys/dcam/dcam1394_io.h>
5721Sap25164 #include <sys/1394/targets/dcam1394/dcam.h>
5821Sap25164 #include <sys/1394/targets/dcam1394/dcam_reg.h>
5921Sap25164 #include <sys/1394/targets/dcam1394/dcam_param.h>
6021Sap25164 #include <sys/1394/targets/dcam1394/dcam_frame.h>
6121Sap25164 
6221Sap25164 #ifndef NPROBE
6321Sap25164 extern int tnf_mod_load(void);
6421Sap25164 extern int tnf_mod_unload(struct modlinkage *mlp);
6521Sap25164 #endif /* ! NPROBE */
6621Sap25164 
6721Sap25164 
6821Sap25164 /* for power management (we have only one component) */
6921Sap25164 static char *dcam_pmc[] = {
7021Sap25164 	"NAME=dcam1394",
7121Sap25164 	"0=Off",
7221Sap25164 	"1=On"
7321Sap25164 };
7421Sap25164 
7521Sap25164 int g_vid_mode_frame_num_bytes[] =
7621Sap25164 {
7721Sap25164 	57600,		/* vid mode 0 */
7821Sap25164 	153600,		/* vid mode 1 */
7921Sap25164 	460800,		/* vid mode 2 */
8021Sap25164 	614400,		/* vid mode 3 */
8121Sap25164 	921600,		/* vid mode 4 */
8221Sap25164 	307200		/* vid mode 5 */
8321Sap25164 };
8421Sap25164 
8521Sap25164 static int	byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p,
8621Sap25164 		    size_t num_bytes, int start_index, int *end_index);
8721Sap25164 static int	byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
8821Sap25164 		    size_t num_bytes, int start_index, int *end_index);
8921Sap25164 static int	dcam_reset(dcam_state_t *softc_p);
9021Sap25164 
9121Sap25164 /* opaque state structure head */
9221Sap25164 void *dcam_state_p;
9321Sap25164 
9421Sap25164 static struct cb_ops dcam_cb_ops = {
9521Sap25164 	dcam_open,		/* open		*/
9621Sap25164 	dcam_close,		/* close	*/
9721Sap25164 	nodev,			/* strategy	*/
9821Sap25164 	nodev,			/* print	*/
9921Sap25164 	nodev,			/* dump		*/
10021Sap25164 	dcam_read,		/* read		*/
10121Sap25164 	nodev,			/* write	*/
10221Sap25164 	dcam_ioctl,		/* ioctl	*/
10321Sap25164 	nodev,			/* devmap	*/
10421Sap25164 	nodev,			/* mmap		*/
10521Sap25164 	nodev,			/* segmap	*/
10621Sap25164 	dcam_chpoll,		/* chpoll	*/
10721Sap25164 	ddi_prop_op,		/* prop_op	*/
10821Sap25164 	NULL,			/* streams	*/
10921Sap25164 				/* flags	*/
11021Sap25164 	D_NEW | D_MP | D_64BIT | D_HOTPLUG,
11121Sap25164 	CB_REV,			/* rev		*/
11221Sap25164 	nodev,			/* aread	*/
11321Sap25164 	nodev			/* awrite	*/
11421Sap25164 };
11521Sap25164 
11621Sap25164 static struct dev_ops dcam_dev_ops = {
11721Sap25164 	DEVO_REV,		/* DEVO_REV indicated by manual	*/
11821Sap25164 	0,			/* device reference count	*/
11921Sap25164 	dcam_getinfo,		/* getinfo			*/
12021Sap25164 	nulldev,		/* identify			*/
12121Sap25164 	nulldev,		/* probe			*/
12221Sap25164 	dcam_attach,		/* attach			*/
12321Sap25164 	dcam_detach,		/* detach			*/
12421Sap25164 	nodev,			/* reset			*/
12521Sap25164 	&dcam_cb_ops,		/* ptr to cb_ops struct		*/
12621Sap25164 	NULL,			/* ptr to bus_ops struct; none	*/
12721Sap25164 	dcam_power,		/* power			*/
128*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
12921Sap25164 };
13021Sap25164 
13121Sap25164 extern	struct	mod_ops mod_driverops;
13221Sap25164 
13321Sap25164 static	struct modldrv modldrv = {
13421Sap25164 	&mod_driverops,
135*7656SSherry.Moore@Sun.COM 	"SUNW 1394-based Digital Camera driver",
13621Sap25164 	&dcam_dev_ops,
13721Sap25164 };
13821Sap25164 
13921Sap25164 static	struct modlinkage modlinkage = {
14021Sap25164 	MODREV_1,
14121Sap25164 	(void *)&modldrv,
14221Sap25164 	NULL,
14321Sap25164 };
14421Sap25164 
14521Sap25164 
14621Sap25164 int
_init(void)14721Sap25164 _init(void)
14821Sap25164 {
14921Sap25164 	int err;
15021Sap25164 
15121Sap25164 	err = ddi_soft_state_init(&dcam_state_p, sizeof (dcam_state_t), 2);
15221Sap25164 
15321Sap25164 	if (err) {
15421Sap25164 		return (err);
15521Sap25164 	}
15621Sap25164 
15721Sap25164 #ifndef NPROBE
15821Sap25164 	(void) tnf_mod_load();
15921Sap25164 #endif /* ! NPROBE */
16021Sap25164 
16121Sap25164 	if (err = mod_install(&modlinkage)) {
16221Sap25164 
16321Sap25164 #ifndef NPROBE
16421Sap25164 		(void) tnf_mod_unload(&modlinkage);
16521Sap25164 #endif /* ! NPROBE */
16621Sap25164 
16721Sap25164 		ddi_soft_state_fini(&dcam_state_p);
16821Sap25164 
16921Sap25164 	}
17021Sap25164 
17121Sap25164 	return (err);
17221Sap25164 }
17321Sap25164 
17421Sap25164 
17521Sap25164 int
_info(struct modinfo * modinfop)17621Sap25164 _info(struct modinfo *modinfop)
17721Sap25164 {
17821Sap25164 	int err;
17921Sap25164 
18021Sap25164 	err = mod_info(&modlinkage, modinfop);
18121Sap25164 	return (err);
18221Sap25164 }
18321Sap25164 
18421Sap25164 
18521Sap25164 int
_fini(void)18621Sap25164 _fini(void)
18721Sap25164 {
18821Sap25164 	int err;
18921Sap25164 
19021Sap25164 	if ((err = mod_remove(&modlinkage)) != 0) {
19121Sap25164 		return (err);
19221Sap25164 	}
19321Sap25164 
19421Sap25164 #ifndef NPROBE
19521Sap25164 		(void) tnf_mod_unload(&modlinkage);
19621Sap25164 #endif /* ! NPROBE */
19721Sap25164 
19821Sap25164 	ddi_soft_state_fini(&dcam_state_p);
19921Sap25164 
20021Sap25164 	return (err);
20121Sap25164 }
20221Sap25164 
20321Sap25164 
20421Sap25164 /*
20521Sap25164  * dcam_attach
20621Sap25164  */
20721Sap25164 /* ARGSUSED */
20821Sap25164 int
dcam_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)20921Sap25164 dcam_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
21021Sap25164 {
21121Sap25164 	char			tmp_str[MAX_STR_LEN];
21221Sap25164 	dcam_state_t		*softc_p;
21321Sap25164 	ddi_eventcookie_t	ev_cookie;
21421Sap25164 	int			instance;
21521Sap25164 	int			ret_val;
21621Sap25164 
21721Sap25164 	switch (cmd) {
21821Sap25164 
21921Sap25164 	case DDI_ATTACH:
22021Sap25164 		instance = ddi_get_instance(dip);
22121Sap25164 
22221Sap25164 		if (ddi_soft_state_zalloc(dcam_state_p, instance) !=
22321Sap25164 		    DDI_SUCCESS) {
22421Sap25164 			return (DDI_FAILURE);
22521Sap25164 		}
22621Sap25164 
22721Sap25164 		if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
22821Sap25164 		    NULL) {
22921Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
23021Sap25164 			return (DDI_FAILURE);
23121Sap25164 		}
23221Sap25164 
23321Sap25164 		/*
23421Sap25164 		 * Initialize soft state
23521Sap25164 		 */
23621Sap25164 		softc_p->dip			= dip;
23721Sap25164 		softc_p->instance		= instance;
23821Sap25164 		softc_p->usr_model		= -1;
23921Sap25164 		softc_p->ixlp			= NULL;
24021Sap25164 
24121Sap25164 		softc_p->seq_count 		= 0;
24221Sap25164 		softc_p->param_status 		= 0;
24321Sap25164 
24421Sap25164 		/*
24521Sap25164 		 * set default vid_mode, frame_rate and ring_buff_capacity
24621Sap25164 		 */
24721Sap25164 		softc_p->cur_vid_mode 		= 1;
24821Sap25164 		softc_p->cur_frame_rate 	= 3;
24921Sap25164 		softc_p->cur_ring_buff_capacity = 10;
25021Sap25164 		softc_p->camera_online		= 1;
25121Sap25164 
25221Sap25164 		(void) sprintf(tmp_str, "dcam%d", instance);
25321Sap25164 
25421Sap25164 		if (ddi_create_minor_node(dip, tmp_str, S_IFCHR, instance,
25521Sap25164 		    DDI_PSEUDO, 0) != DDI_SUCCESS) {
25621Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
25721Sap25164 
25821Sap25164 			return (DDI_FAILURE);
25921Sap25164 		}
26021Sap25164 
26121Sap25164 		(void) sprintf(tmp_str, "dcamctl%d", instance);
26221Sap25164 
26321Sap25164 		if (ddi_create_minor_node(dip, tmp_str, S_IFCHR,
26421Sap25164 		    instance + DCAM1394_MINOR_CTRL, "ddi_dcam1394", 0) !=
26521Sap25164 		    DDI_SUCCESS) {
26621Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
26721Sap25164 
26821Sap25164 			return (DDI_FAILURE);
26921Sap25164 		}
27021Sap25164 
27121Sap25164 		if (t1394_attach(dip, T1394_VERSION_V1, 0,
27221Sap25164 		    &(softc_p->attachinfo),
27321Sap25164 		    &(softc_p->sl_handle)) != DDI_SUCCESS) {
27421Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
27521Sap25164 			ddi_remove_minor_node(dip, NULL);
27621Sap25164 
27721Sap25164 			return (DDI_FAILURE);
27821Sap25164 		}
27921Sap25164 
28021Sap25164 		if (t1394_get_targetinfo(softc_p->sl_handle,
28121Sap25164 		    softc_p->attachinfo.localinfo.bus_generation, 0,
28221Sap25164 		    &(softc_p->targetinfo)) != DDI_SUCCESS) {
28321Sap25164 			cmn_err(CE_WARN,
28421Sap25164 			    "dcam_attach: t1394_get_targetinfo failed\n");
28521Sap25164 		}
28621Sap25164 
28721Sap25164 		if (ddi_get_eventcookie(dip, DDI_DEVI_BUS_RESET_EVENT,
28821Sap25164 		    &ev_cookie) != DDI_SUCCESS) {
28921Sap25164 			(void) t1394_detach(&softc_p->sl_handle, 0);
29021Sap25164 
29121Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
29221Sap25164 			ddi_remove_minor_node(dip, NULL);
29321Sap25164 
29421Sap25164 			return (DDI_FAILURE);
29521Sap25164 		}
29621Sap25164 
29721Sap25164 		if (ddi_add_event_handler(dip, ev_cookie, dcam_bus_reset_notify,
29821Sap25164 		    softc_p, &softc_p->event_id) != DDI_SUCCESS) {
29921Sap25164 			(void) t1394_detach(&softc_p->sl_handle, 0);
30021Sap25164 
30121Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
30221Sap25164 			ddi_remove_minor_node(dip, NULL);
30321Sap25164 
30421Sap25164 			return (DDI_FAILURE);
30521Sap25164 		}
30621Sap25164 
30721Sap25164 		mutex_init(&softc_p->softc_mutex, NULL, MUTEX_DRIVER,
30821Sap25164 		    softc_p->attachinfo.iblock_cookie);
30921Sap25164 
31021Sap25164 		mutex_init(&softc_p->dcam_frame_is_done_mutex, NULL,
31121Sap25164 		    MUTEX_DRIVER, softc_p->attachinfo.iblock_cookie);
31221Sap25164 
31321Sap25164 		/*
31421Sap25164 		 * init the soft state's parameter attribute structure
31521Sap25164 		 */
31621Sap25164 		if (param_attr_init(softc_p, softc_p->param_attr) !=
31721Sap25164 		    DDI_SUCCESS) {
31821Sap25164 			(void) ddi_remove_event_handler(softc_p->event_id);
31921Sap25164 			(void) t1394_detach(&softc_p->sl_handle, 0);
32021Sap25164 
32121Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
32221Sap25164 			ddi_remove_minor_node(dip, NULL);
32321Sap25164 
32421Sap25164 			return (DDI_FAILURE);
32521Sap25164 		}
32621Sap25164 
32721Sap25164 		/*
32821Sap25164 		 * power management stuff
32921Sap25164 		 */
33021Sap25164 		if (ddi_prop_update_string_array(DDI_DEV_T_NONE,
33121Sap25164 		    dip, "pm-components", dcam_pmc,
33221Sap25164 		    sizeof (dcam_pmc)/sizeof (char *)) == DDI_PROP_SUCCESS) {
33321Sap25164 
33421Sap25164 			(void) pm_raise_power(dip, 0, 1);
33521Sap25164 			if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0,
33621Sap25164 			    "power-managed?")) {
33721Sap25164 				(void) pm_idle_component(dip, 0);
33821Sap25164 			} else {
33921Sap25164 				(void) pm_busy_component(dip, 0);
34021Sap25164 			}
34121Sap25164 		}
34221Sap25164 
34321Sap25164 		softc_p->flags |= DCAM1394_FLAG_ATTACH_COMPLETE;
34421Sap25164 
34521Sap25164 		ddi_report_dev(dip);
34621Sap25164 		ret_val = DDI_SUCCESS;
34721Sap25164 		break;
34821Sap25164 
34921Sap25164 	case DDI_RESUME:
35021Sap25164 		instance = ddi_get_instance(dip);
35121Sap25164 		if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) ==
35221Sap25164 		    NULL) {
35321Sap25164 			ddi_soft_state_free(dcam_state_p, instance);
35421Sap25164 			return (DDI_FAILURE);
35521Sap25164 		}
35621Sap25164 
35721Sap25164 		mutex_enter(&softc_p->softc_mutex);
35821Sap25164 
35921Sap25164 		if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
36021Sap25164 			(void) dcam1394_ioctl_frame_rcv_start(softc_p);
36121Sap25164 		}
36221Sap25164 
36321Sap25164 		softc_p->suspended = 0;
36421Sap25164 
36521Sap25164 		mutex_exit(&softc_p->softc_mutex);
36621Sap25164 
36721Sap25164 		ret_val = DDI_SUCCESS;
36821Sap25164 		break;
36921Sap25164 
37021Sap25164 	default:
37121Sap25164 		ret_val = DDI_FAILURE;
37221Sap25164 		break;
37321Sap25164 	}
37421Sap25164 
37521Sap25164 	return (ret_val);
37621Sap25164 }
37721Sap25164 
37821Sap25164 
37921Sap25164 /*
38021Sap25164  * dcam_power: perform dcam power management
38121Sap25164  */
38221Sap25164 /* ARGSUSED */
38321Sap25164 int
dcam_power(dev_info_t * dip,int component,int level)38421Sap25164 dcam_power(dev_info_t *dip, int component, int level)
38521Sap25164 {
38621Sap25164 	dcam_state_t	*softc_p;
38721Sap25164 	int		instance;
38821Sap25164 
38921Sap25164 	instance = ddi_get_instance(dip);
39021Sap25164 	softc_p  = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
39121Sap25164 
39221Sap25164 	if (softc_p == NULL)
39321Sap25164 		return (DDI_FAILURE);
39421Sap25164 
39521Sap25164 	softc_p->pm_cable_power = level;
39621Sap25164 
39721Sap25164 	return (DDI_SUCCESS);
39821Sap25164 
39921Sap25164 }
40021Sap25164 
40121Sap25164 
40221Sap25164 /*
40321Sap25164  * dcam_getinfo
40421Sap25164  */
40521Sap25164 /* ARGSUSED */
40621Sap25164 int
dcam_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)40721Sap25164 dcam_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
40821Sap25164 {
40921Sap25164 	dev_t		 dev;
41021Sap25164 	dcam_state_t	*softc_p;
41121Sap25164 	int		 status;
41221Sap25164 	int		 instance;
41321Sap25164 
41421Sap25164 	switch (cmd) {
41521Sap25164 
41621Sap25164 	case DDI_INFO_DEVT2DEVINFO:
41721Sap25164 		dev	 = (dev_t)arg;
41821Sap25164 		instance = DEV_TO_INSTANCE(dev);
41921Sap25164 		softc_p  = (dcam_state_t *)
42021Sap25164 		    ddi_get_soft_state(dcam_state_p, instance);
42121Sap25164 
42221Sap25164 		if (softc_p == NULL) {
42321Sap25164 			return (DDI_FAILURE);
42421Sap25164 		}
42521Sap25164 
42621Sap25164 		*result = (void *)softc_p->dip;
42721Sap25164 		status  = DDI_SUCCESS;
42821Sap25164 		break;
42921Sap25164 
43021Sap25164 	case DDI_INFO_DEVT2INSTANCE:
43121Sap25164 		dev	 = (dev_t)arg;
43221Sap25164 		instance = DEV_TO_INSTANCE(dev);
43321Sap25164 		*result	 = (void *)(uintptr_t)instance;
43421Sap25164 		status	 = DDI_SUCCESS;
43521Sap25164 		break;
43621Sap25164 
43721Sap25164 	default:
43821Sap25164 		status = DDI_FAILURE;
43921Sap25164 	}
44021Sap25164 
44121Sap25164 	return (status);
44221Sap25164 }
44321Sap25164 
44421Sap25164 
44521Sap25164 /*
44621Sap25164  * dcam_detach
44721Sap25164  */
44821Sap25164 /* ARGSUSED */
44921Sap25164 int
dcam_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)45021Sap25164 dcam_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
45121Sap25164 {
45221Sap25164 	int			 instance;
45321Sap25164 	dcam_state_t		*softc_p;
45421Sap25164 
45521Sap25164 	instance = ddi_get_instance(dip);
45621Sap25164 
45721Sap25164 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
45821Sap25164 	if (softc_p == NULL) {
45921Sap25164 		return (DDI_FAILURE);
46021Sap25164 	}
46121Sap25164 
46221Sap25164 
46321Sap25164 	switch (cmd) {
46421Sap25164 
46521Sap25164 	case DDI_SUSPEND:
46621Sap25164 		mutex_enter(&softc_p->softc_mutex);
46721Sap25164 
46821Sap25164 		softc_p->suspended = 1;
46921Sap25164 
47021Sap25164 		if (softc_p->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
47121Sap25164 			(void) dcam_frame_rcv_stop(softc_p);
47221Sap25164 		}
47321Sap25164 
47421Sap25164 		mutex_exit(&softc_p->softc_mutex);
47521Sap25164 		return (DDI_SUCCESS);
47621Sap25164 
47721Sap25164 
47821Sap25164 	case DDI_DETACH:
47921Sap25164 		/*
48021Sap25164 		 * power management stuff
48121Sap25164 		 */
48221Sap25164 		(void) pm_lower_power(dip, 0, 0);
48321Sap25164 		(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, "pm-components");
48421Sap25164 
48521Sap25164 		/*
48621Sap25164 		 * deregister with 1394 DDI framework
48721Sap25164 		 */
48821Sap25164 		if (t1394_detach(&softc_p->sl_handle, 0) != DDI_SUCCESS) {
48921Sap25164 			return (DDI_FAILURE);
49021Sap25164 		}
49121Sap25164 
49221Sap25164 		(void) ddi_remove_event_handler(softc_p->event_id);
49321Sap25164 
49421Sap25164 		/*
49521Sap25164 		 * free state structures, mutexes, condvars;
49621Sap25164 		 * deregister interrupts
49721Sap25164 		 */
49821Sap25164 		mutex_destroy(&softc_p->softc_mutex);
49921Sap25164 		mutex_destroy(&softc_p->dcam_frame_is_done_mutex);
50021Sap25164 
50121Sap25164 		/*
50221Sap25164 		 * Remove all minor nodes, all dev_t's properties
50321Sap25164 		 */
50421Sap25164 		ddi_remove_minor_node(dip, NULL);
50521Sap25164 
50621Sap25164 		ddi_soft_state_free(dcam_state_p, instance);
50721Sap25164 		ddi_prop_remove_all(dip);
50821Sap25164 
50921Sap25164 		return (DDI_SUCCESS);
51021Sap25164 
51121Sap25164 	default:
51221Sap25164 		return (DDI_FAILURE);
51321Sap25164 
51421Sap25164 	}
51521Sap25164 }
51621Sap25164 
51721Sap25164 
51821Sap25164 /*
51921Sap25164  * dcam_open
52021Sap25164  */
52121Sap25164 /* ARGSUSED */
52221Sap25164 int
dcam_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)52321Sap25164 dcam_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
52421Sap25164 {
52521Sap25164 	dcam_state_t	*softc_p;
52621Sap25164 	int		instance;
52721Sap25164 	int		is_ctrl_file;
52821Sap25164 	uint_t		new_flags;
52921Sap25164 
53021Sap25164 	instance = (int)DEV_TO_INSTANCE(*dev_p);
53121Sap25164 
53221Sap25164 	if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
53321Sap25164 		return (ENXIO);
53421Sap25164 	}
53521Sap25164 
53621Sap25164 	/*
53721Sap25164 	 * if dcam_attach hasn't completed, return error
53821Sap25164 	 * XXX: Check this out
53921Sap25164 	 */
54021Sap25164 	if (!(softc_p->flags & DCAM1394_FLAG_ATTACH_COMPLETE)) {
54121Sap25164 		return (ENXIO);
54221Sap25164 	}
54321Sap25164 
54421Sap25164 	/* disallow block, mount, and layered opens */
54521Sap25164 	if (otyp != OTYP_CHR) {
54621Sap25164 		return (EINVAL);
54721Sap25164 	}
54821Sap25164 
54921Sap25164 	new_flags    = 0;
55021Sap25164 	is_ctrl_file = (getminor(*dev_p) & DCAM1394_MINOR_CTRL) ? 1 : 0;
55121Sap25164 
55221Sap25164 	mutex_enter(&softc_p->softc_mutex);
55321Sap25164 
55421Sap25164 	/*
55521Sap25164 	 * The open is either for the capture file or the control file.
55621Sap25164 	 * If it's the control file construct new flags.
55721Sap25164 	 *
55821Sap25164 	 * If it's the capture file return busy if it's already open,
55921Sap25164 	 * otherwise construct new flags.
56021Sap25164 	 */
56121Sap25164 	if (is_ctrl_file) {
56221Sap25164 		new_flags |= DCAM1394_FLAG_OPEN_CONTROL;
56321Sap25164 	} else {
56421Sap25164 		if (softc_p->flags & DCAM1394_FLAG_OPEN_CAPTURE) {
56521Sap25164 			mutex_exit(&softc_p->softc_mutex);
56621Sap25164 			return (EBUSY);
56721Sap25164 		}
56821Sap25164 
56921Sap25164 		new_flags |= DCAM1394_FLAG_OPEN_CAPTURE;
57021Sap25164 	}
57121Sap25164 
57221Sap25164 	new_flags |= DCAM1394_FLAG_OPEN;
57321Sap25164 	softc_p->flags |= new_flags;
57421Sap25164 
57521Sap25164 	mutex_exit(&softc_p->softc_mutex);
57621Sap25164 
57721Sap25164 	/*
57821Sap25164 	 * power management stuff
57921Sap25164 	 */
58021Sap25164 	if (softc_p->pm_open_count == 0) {
58121Sap25164 		if (ddi_prop_exists(DDI_DEV_T_ANY, softc_p->dip, 0,
58221Sap25164 		    "power-managed?")) {
58321Sap25164 			(void) pm_busy_component(softc_p->dip, 0);
58421Sap25164 			if (softc_p->pm_cable_power == 0) {
58521Sap25164 				int i;
58621Sap25164 
58721Sap25164 				(void) pm_raise_power(softc_p->dip, 0, 1);
58821Sap25164 
58921Sap25164 				/*
59021Sap25164 				 * Wait for the power to be up and stable
59121Sap25164 				 * before proceeding.  100 msecs should
59221Sap25164 				 * certainly be enough, and if we check
59321Sap25164 				 * every msec we'll probably loop just a
59421Sap25164 				 * few times.
59521Sap25164 				 */
59621Sap25164 				for (i = 0; i < 100; i++) {
59721Sap25164 					if (param_power_set(softc_p, 1) == 0) {
59821Sap25164 						break;
59921Sap25164 					}
60021Sap25164 					delay((clock_t)drv_usectohz(1000));
60121Sap25164 				}
60221Sap25164 			}
60321Sap25164 		}
60421Sap25164 	}
60521Sap25164 	softc_p->pm_open_count++;
60621Sap25164 
60721Sap25164 	return (0);
60821Sap25164 }
60921Sap25164 
61021Sap25164 
61121Sap25164 /*
61221Sap25164  * dcam_close
61321Sap25164  */
61421Sap25164 /* ARGSUSED */
61521Sap25164 int
dcam_close(dev_t dev,int flags,int otyp,cred_t * cred_p)61621Sap25164 dcam_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
61721Sap25164 {
61821Sap25164 	int instance;
61921Sap25164 	dcam_state_t *softc;
62021Sap25164 
62121Sap25164 	instance = DEV_TO_INSTANCE(dev);
62221Sap25164 	softc    = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
62321Sap25164 
62421Sap25164 	/*
62521Sap25164 	 * power management stuff
62621Sap25164 	 */
62721Sap25164 	softc->pm_open_count = 0;
62821Sap25164 	if (ddi_prop_exists(DDI_DEV_T_ANY, softc->dip, 0, "power-managed?")) {
62921Sap25164 		(void) pm_idle_component(softc->dip, 0);
63021Sap25164 	}
63121Sap25164 
63221Sap25164 	mutex_enter(&softc->softc_mutex);
63321Sap25164 
63421Sap25164 	if (getminor(dev) & DCAM1394_MINOR_CTRL) {
63521Sap25164 		softc->flags &= ~DCAM1394_FLAG_OPEN_CONTROL;
63621Sap25164 	} else {
63721Sap25164 		/*
63821Sap25164 		 * If an application which has opened the camera capture
63921Sap25164 		 * device exits without calling DCAM1394_CMD_FRAME_RCV_STOP
64021Sap25164 		 * ioctl, then we need to release resources.
64121Sap25164 		 */
64221Sap25164 		if (softc->flags & DCAM1394_FLAG_FRAME_RCV_INIT) {
64321Sap25164 			(void) dcam_frame_rcv_stop(softc);
64421Sap25164 			softc->flags &= ~DCAM1394_FLAG_FRAME_RCV_INIT;
64521Sap25164 		}
64621Sap25164 
64721Sap25164 		(void) param_power_set(softc, 0);
64821Sap25164 
64921Sap25164 		softc->flags &= ~DCAM1394_FLAG_OPEN_CAPTURE;
65021Sap25164 	}
65121Sap25164 
65221Sap25164 	/*
65321Sap25164 	 * If driver is completely closed, then stabilize the camera
65421Sap25164 	 * and turn off transient flags
65521Sap25164 	 */
65621Sap25164 	if (!(softc->flags &
65721Sap25164 	    (DCAM1394_FLAG_OPEN_CONTROL | DCAM1394_FLAG_OPEN_CAPTURE))) {
65821Sap25164 		softc->flags &= DCAM1394_FLAG_ATTACH_COMPLETE;
65921Sap25164 	}
66021Sap25164 
66121Sap25164 	mutex_exit(&softc->softc_mutex);
66221Sap25164 
66321Sap25164 	return (DDI_SUCCESS);
66421Sap25164 
66521Sap25164 }
66621Sap25164 
66721Sap25164 
66821Sap25164 /*
66921Sap25164  * dcam_read
67021Sap25164  *
67121Sap25164  * If read pointer is not pointing to the same position as write pointer
67221Sap25164  * copy frame data from ring buffer position pointed to by read pointer.
67321Sap25164  *
67421Sap25164  *	If during the course of copying frame data, the device driver
67521Sap25164  *	invalidated this read() request processing operation, restart
67621Sap25164  *	this operation.
67721Sap25164  *
67821Sap25164  *     Increment read pointer and return frame data to user process.
67921Sap25164  *
68021Sap25164  * Else return error
68121Sap25164  *
68221Sap25164  */
68321Sap25164 /* ARGSUSED */
68421Sap25164 int
dcam_read(dev_t dev,struct uio * uio_p,cred_t * cred_p)68521Sap25164 dcam_read(dev_t dev, struct uio *uio_p, cred_t *cred_p)
68621Sap25164 {
68721Sap25164 	buff_info_t	*buff_info_p;
68821Sap25164 	dcam_state_t	*softc_p;
68921Sap25164 	hrtime_t	 timestamp;
69021Sap25164 	int		 index, instance;
69121Sap25164 	int		 read_ptr_id;
69221Sap25164 	size_t		 read_ptr_pos, write_ptr_pos;
69321Sap25164 	int		 read_req_invalid;
69421Sap25164 	ring_buff_t	*ring_buff_p;
69521Sap25164 	uchar_t		*frame_data_p;
69621Sap25164 	uint_t		 seq_num;
69721Sap25164 	unsigned long	 user_frame_buff_addr;
69821Sap25164 	uint_t		 vid_mode;
69921Sap25164 	int		 gotten_addr_flag;
70021Sap25164 
70121Sap25164 	instance = DEV_TO_INSTANCE(dev);
70221Sap25164 
70321Sap25164 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
70421Sap25164 	if (softc_p == NULL) {
70521Sap25164 		return (ENXIO);
70621Sap25164 	}
70721Sap25164 
70821Sap25164 	if ((ring_buff_p = softc_p->ring_buff_p) == NULL) {
70921Sap25164 		return (EAGAIN);
71021Sap25164 	}
71121Sap25164 
71221Sap25164 	read_ptr_id = 0;
71321Sap25164 
71421Sap25164 	mutex_enter(&softc_p->dcam_frame_is_done_mutex);
71521Sap25164 
71621Sap25164 	softc_p->reader_flags[read_ptr_id] |= DCAM1394_FLAG_READ_REQ_PROC;
71721Sap25164 
71821Sap25164 	user_frame_buff_addr = 0;
71921Sap25164 	gotten_addr_flag = 0;
72021Sap25164 
72121Sap25164 	do {
72221Sap25164 		read_ptr_pos = ring_buff_read_ptr_pos_get(ring_buff_p,
72321Sap25164 		    read_ptr_id);
72421Sap25164 
72521Sap25164 		write_ptr_pos = ring_buff_write_ptr_pos_get(ring_buff_p);
72621Sap25164 
72721Sap25164 		if (read_ptr_pos != write_ptr_pos) {
72821Sap25164 			/*
72921Sap25164 			 * Since the app wants realtime video, set the read
73021Sap25164 			 * pointer to the newest data.
73121Sap25164 			 */
73221Sap25164 			if (write_ptr_pos == 0) {
73321Sap25164 				read_ptr_pos = ring_buff_p->num_buffs - 1;
73421Sap25164 			} else {
73521Sap25164 				read_ptr_pos = write_ptr_pos - 1;
73621Sap25164 			}
73721Sap25164 
73821Sap25164 			/*
73921Sap25164 			 * copy frame data from ring buffer position pointed
74021Sap25164 			 * to by read pointer
74121Sap25164 			 */
74221Sap25164 			index = 0;
74321Sap25164 			buff_info_p =
744*7656SSherry.Moore@Sun.COM 			    &(ring_buff_p->buff_info_array_p[read_ptr_pos]);
74521Sap25164 
74621Sap25164 			vid_mode = softc_p->cur_vid_mode;
74721Sap25164 			seq_num  = buff_info_p->seq_num;
74821Sap25164 			timestamp = buff_info_p->timestamp;
74921Sap25164 			frame_data_p = (uchar_t *)buff_info_p->kaddr_p;
75021Sap25164 
75121Sap25164 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
75221Sap25164 
75321Sap25164 			/*
75421Sap25164 			 * Fix for bug #4424042
75521Sap25164 			 * don't lock this section
75621Sap25164 			 */
75721Sap25164 
75821Sap25164 			if (byte_copy_to_user_buff((uchar_t *)&vid_mode,
75921Sap25164 			    uio_p, sizeof (uint_t), index, &index)) {
76021Sap25164 
76121Sap25164 				return (EFAULT);
76221Sap25164 			}
76321Sap25164 
76421Sap25164 			if (byte_copy_to_user_buff((uchar_t *)&seq_num,
76521Sap25164 			    uio_p, sizeof (unsigned int), index, &index)) {
76621Sap25164 
76721Sap25164 				return (EFAULT);
76821Sap25164 			}
76921Sap25164 
77021Sap25164 			if (byte_copy_to_user_buff((uchar_t *)&timestamp,
77121Sap25164 			    uio_p, sizeof (hrtime_t), index, &index)) {
77221Sap25164 
77321Sap25164 				return (EFAULT);
77421Sap25164 			}
77521Sap25164 
77621Sap25164 			/*
77721Sap25164 			 * get buff pointer; do ddi_copyout()
77821Sap25164 			 * get user buffer address only once
77921Sap25164 			 */
78021Sap25164 			if (!gotten_addr_flag) {
78121Sap25164 				if (byte_copy_from_user_buff(
78221Sap25164 				    (uchar_t *)&user_frame_buff_addr, uio_p,
78321Sap25164 				    softc_p->usr_model, index, &index)) {
78421Sap25164 
78521Sap25164 					return (EFAULT);
78621Sap25164 				}
78721Sap25164 
78821Sap25164 #ifdef _MULTI_DATAMODEL
78921Sap25164 				if (softc_p->usr_model == ILP32_PTR_SIZE) {
79021Sap25164 					user_frame_buff_addr =
79121Sap25164 					    ((user_frame_buff_addr >> 32) &
79221Sap25164 					    0xffffffffULL) |
79321Sap25164 					    ((user_frame_buff_addr << 32) &
79421Sap25164 					    0xffffffff00000000ULL);
79521Sap25164 				}
79621Sap25164 #endif /* _MULTI_DATAMODEL */
79721Sap25164 
79821Sap25164 				gotten_addr_flag = 1;
79921Sap25164 			}
80021Sap25164 
80121Sap25164 			if (ddi_copyout(
80221Sap25164 			    (caddr_t)frame_data_p,
80321Sap25164 			    (caddr_t)user_frame_buff_addr,
80421Sap25164 			    g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode],
80521Sap25164 			    0)) {
80621Sap25164 				return (EFAULT);
80721Sap25164 			}
80821Sap25164 
80921Sap25164 			/*
81021Sap25164 			 * if during the course of copying frame data,
81121Sap25164 			 * the device driver invalidated this read()
81221Sap25164 			 * request processing operation; restart this
81321Sap25164 			 * operation
81421Sap25164 			 */
81521Sap25164 
81621Sap25164 			mutex_enter(&softc_p->dcam_frame_is_done_mutex);
81721Sap25164 
81821Sap25164 			read_req_invalid = softc_p->reader_flags[read_ptr_id] &
81921Sap25164 			    DCAM1394_FLAG_READ_REQ_INVALID;
82021Sap25164 
82121Sap25164 			softc_p->reader_flags[read_ptr_id] &=
82221Sap25164 			    ~(DCAM1394_FLAG_READ_REQ_INVALID);
82321Sap25164 
82421Sap25164 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
82521Sap25164 
82621Sap25164 		} else {
82721Sap25164 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
82821Sap25164 			return (EAGAIN);
82921Sap25164 		}
83021Sap25164 
83121Sap25164 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
83221Sap25164 	} while (read_req_invalid);
83321Sap25164 
83421Sap25164 	/*
83521Sap25164 	 * return number of bytes actually written to user space
83621Sap25164 	 */
83721Sap25164 	uio_p->uio_resid -= g_vid_mode_frame_num_bytes[softc_p->cur_vid_mode];
83821Sap25164 
83921Sap25164 	softc_p->reader_flags[read_ptr_id] &= ~(DCAM1394_FLAG_READ_REQ_PROC);
84021Sap25164 
84121Sap25164 	/* increment read pointer */
84221Sap25164 	ring_buff_read_ptr_incr(ring_buff_p, read_ptr_id);
84321Sap25164 
84421Sap25164 	mutex_exit(&softc_p->dcam_frame_is_done_mutex);
84521Sap25164 
84621Sap25164 	return (0);
84721Sap25164 }
84821Sap25164 
84921Sap25164 
85021Sap25164 /*
85121Sap25164  * dcam_ioctl
85221Sap25164  */
85321Sap25164 /* ARGSUSED */
85421Sap25164 int
dcam_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rvalp)85521Sap25164 dcam_ioctl(dev_t dev, int cmd, intptr_t  arg, int mode, cred_t *cred_p,
85621Sap25164     int *rvalp)
85721Sap25164 {
85821Sap25164 	dcam_state_t		*softc_p;
85921Sap25164 	dcam1394_param_list_t	*param_list;
86021Sap25164 	dcam1394_reg_io_t	 dcam_reg_io;
86121Sap25164 	int			 instance, is_ctrl_file, rc, i;
86221Sap25164 
86321Sap25164 	rc = 0;
86421Sap25164 	param_list = (dcam1394_param_list_t *)0;
86521Sap25164 
86621Sap25164 	instance = DEV_TO_INSTANCE(dev);
86721Sap25164 
86821Sap25164 	if ((softc_p = ddi_get_soft_state(dcam_state_p, instance)) == NULL) {
86921Sap25164 		rc = ENXIO;
87021Sap25164 		goto done;
87121Sap25164 	}
87221Sap25164 
87321Sap25164 	/*
87421Sap25164 	 * determine user applications data model
87521Sap25164 	 */
87621Sap25164 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32)
87721Sap25164 		softc_p->usr_model = ILP32_PTR_SIZE;
87821Sap25164 	else
87921Sap25164 		softc_p->usr_model = LP64_PTR_SIZE;
88021Sap25164 
88121Sap25164 
88221Sap25164 	switch (cmd) {
88321Sap25164 
88421Sap25164 	case DCAM1394_CMD_REG_READ:
88521Sap25164 		if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
88621Sap25164 		    sizeof (dcam1394_reg_io_t), mode)) {
88721Sap25164 			rc = EFAULT;
88821Sap25164 			goto done;
88921Sap25164 		}
89021Sap25164 
89121Sap25164 		if (dcam_reg_read(softc_p, &dcam_reg_io)) {
89221Sap25164 			rc = EFAULT;
89321Sap25164 			goto done;
89421Sap25164 		}
89521Sap25164 
89621Sap25164 		if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
89721Sap25164 		    sizeof (dcam1394_reg_io_t), mode)) {
89821Sap25164 			rc = EFAULT;
89921Sap25164 			goto done;
90021Sap25164 		}
90121Sap25164 		break;
90221Sap25164 
90321Sap25164 	case DCAM1394_CMD_REG_WRITE:
90421Sap25164 		if (ddi_copyin((caddr_t)arg, &dcam_reg_io,
90521Sap25164 		    sizeof (dcam1394_reg_io_t), mode)) {
90621Sap25164 			rc = EFAULT;
90721Sap25164 			goto done;
90821Sap25164 		}
90921Sap25164 
91021Sap25164 		if (dcam_reg_write(softc_p, &dcam_reg_io)) {
91121Sap25164 			rc = EFAULT;
91221Sap25164 			goto done;
91321Sap25164 		}
91421Sap25164 
91521Sap25164 		if (ddi_copyout(&dcam_reg_io, (caddr_t)arg,
91621Sap25164 		    sizeof (dcam1394_reg_io_t), mode)) {
91721Sap25164 			rc = EFAULT;
91821Sap25164 			goto done;
91921Sap25164 		}
92021Sap25164 		break;
92121Sap25164 
92221Sap25164 	case DCAM1394_CMD_CAM_RESET:
92321Sap25164 		if (dcam_reset(softc_p)) {
92421Sap25164 			rc = EIO;
92521Sap25164 			goto done;
92621Sap25164 		}
92721Sap25164 		break;
92821Sap25164 
92921Sap25164 	case DCAM1394_CMD_PARAM_GET:
93021Sap25164 		param_list = (dcam1394_param_list_t *)
93121Sap25164 		    kmem_alloc(sizeof (dcam1394_param_list_t), KM_SLEEP);
93221Sap25164 
93321Sap25164 		if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
93421Sap25164 		    sizeof (dcam1394_param_list_t), mode)) {
93521Sap25164 			rc = EFAULT;
93621Sap25164 			goto done;
93721Sap25164 		}
93821Sap25164 
93921Sap25164 		if (dcam1394_ioctl_param_get(softc_p, *param_list)) {
94021Sap25164 			rc = EINVAL;
94121Sap25164 		}
94221Sap25164 
94321Sap25164 		if (ddi_copyout((caddr_t)param_list, (caddr_t)arg,
94421Sap25164 		    sizeof (dcam1394_param_list_t), mode)) {
94521Sap25164 			rc = EFAULT;
94621Sap25164 			goto done;
94721Sap25164 		}
94821Sap25164 		break;
94921Sap25164 
95021Sap25164 	case DCAM1394_CMD_PARAM_SET:
95121Sap25164 		param_list = (dcam1394_param_list_t *)
95221Sap25164 		    kmem_alloc((size_t)sizeof (dcam1394_param_list_t),
95321Sap25164 		    KM_SLEEP);
95421Sap25164 
95521Sap25164 		if (ddi_copyin((caddr_t)arg, (caddr_t)param_list,
95621Sap25164 		    sizeof (dcam1394_param_list_t), mode)) {
95721Sap25164 			rc = EFAULT;
95821Sap25164 			goto done;
95921Sap25164 		}
96021Sap25164 
96121Sap25164 		is_ctrl_file = (getminor(dev) & DCAM1394_MINOR_CTRL) ? 1:0;
96221Sap25164 
96321Sap25164 		if (dcam1394_ioctl_param_set(softc_p, is_ctrl_file,
96421Sap25164 		    *param_list)) {
96521Sap25164 			rc = EINVAL;
96621Sap25164 		}
96721Sap25164 
96821Sap25164 		if (is_ctrl_file) {
96921Sap25164 			mutex_enter(&softc_p->dcam_frame_is_done_mutex);
97021Sap25164 			softc_p->param_status |= DCAM1394_STATUS_PARAM_CHANGE;
97121Sap25164 			mutex_exit(&softc_p->dcam_frame_is_done_mutex);
97221Sap25164 		}
97321Sap25164 
97421Sap25164 		if (ddi_copyout(param_list, (caddr_t)arg,
97521Sap25164 		    sizeof (dcam1394_param_list_t), mode)) {
97621Sap25164 			rc = EFAULT;
97721Sap25164 			goto done;
97821Sap25164 		}
97921Sap25164 		break;
98021Sap25164 
98121Sap25164 	case DCAM1394_CMD_FRAME_RCV_START:
98221Sap25164 		if (dcam1394_ioctl_frame_rcv_start(softc_p)) {
98321Sap25164 			rc = ENXIO;
98421Sap25164 		}
98521Sap25164 		break;
98621Sap25164 
98721Sap25164 	case DCAM1394_CMD_FRAME_RCV_STOP:
98821Sap25164 		if (dcam_frame_rcv_stop(softc_p)) {
98921Sap25164 			rc = ENXIO;
99021Sap25164 		}
99121Sap25164 		break;
99221Sap25164 
99321Sap25164 	case DCAM1394_CMD_RING_BUFF_FLUSH:
99421Sap25164 		if (softc_p->ring_buff_p == NULL) {
99521Sap25164 			rc = EAGAIN;
99621Sap25164 			break;
99721Sap25164 		}
99821Sap25164 
99921Sap25164 		/*
100021Sap25164 		 * the simplest way to flush ring_buff is to empty it
100121Sap25164 		 */
100221Sap25164 		for (i = 0; i < softc_p->ring_buff_p->num_read_ptrs; i++) {
100321Sap25164 			softc_p->ring_buff_p->read_ptr_pos[i] =
100421Sap25164 			    softc_p->ring_buff_p->write_ptr_pos;
100521Sap25164 
100621Sap25164 			/*
100721Sap25164 			 * if device driver is processing a user
100821Sap25164 			 * process's read() request
100921Sap25164 			 */
101021Sap25164 			if (softc_p->reader_flags[i] &
101121Sap25164 			    DCAM1394_FLAG_READ_REQ_PROC) {
101221Sap25164 
101321Sap25164 				/*
101421Sap25164 				 * invalidate the read() request processing
101521Sap25164 				 * operation
101621Sap25164 				 */
101721Sap25164 				softc_p->reader_flags[i] |=
101821Sap25164 				    DCAM1394_FLAG_READ_REQ_INVALID;
101921Sap25164 			}
102021Sap25164 		}
102121Sap25164 		break;
102221Sap25164 
102321Sap25164 	case DCAM1394_CMD_FRAME_SEQ_NUM_COUNT_RESET:
102421Sap25164 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
102521Sap25164 		softc_p->seq_count = 0;
102621Sap25164 		mutex_exit(&softc_p->dcam_frame_is_done_mutex);
102721Sap25164 		break;
102821Sap25164 
102921Sap25164 	default:
103021Sap25164 		rc = EIO;
103121Sap25164 		break;
103221Sap25164 
103321Sap25164 	}
103421Sap25164 
103521Sap25164 done:
103621Sap25164 	if (param_list)
103721Sap25164 		kmem_free(param_list, sizeof (dcam1394_param_list_t));
103821Sap25164 
103921Sap25164 	return (rc);
104021Sap25164 }
104121Sap25164 
104221Sap25164 
104321Sap25164 /*
104421Sap25164  * dcam_chpoll
104521Sap25164  */
104621Sap25164 /* ARGSUSED */
104721Sap25164 int
dcam_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)104821Sap25164 dcam_chpoll(dev_t dev, short events, int anyyet, short *reventsp,
104921Sap25164     struct pollhead **phpp)
105021Sap25164 {
105121Sap25164 	dcam_state_t	*softc_p;
105221Sap25164 	int		 instance, ring_buff_has_data, read_ptr_id;
105321Sap25164 	size_t		 read_ptr_pos, write_ptr_pos;
105421Sap25164 	short		 revent;
105521Sap25164 
105621Sap25164 	instance = DEV_TO_INSTANCE(dev);
105721Sap25164 
105821Sap25164 	softc_p = (dcam_state_t *)ddi_get_soft_state(dcam_state_p, instance);
105921Sap25164 	if (softc_p == NULL) {
106021Sap25164 		return (ENXIO);
106121Sap25164 	}
106221Sap25164 
106321Sap25164 	read_ptr_id	= 0;
106421Sap25164 	revent		= 0;
106521Sap25164 
106621Sap25164 	if (softc_p->ring_buff_p == NULL) {
106721Sap25164 		ring_buff_has_data = 0;
106821Sap25164 	} else {
106921Sap25164 		mutex_enter(&softc_p->dcam_frame_is_done_mutex);
107021Sap25164 
107121Sap25164 		read_ptr_pos =
107221Sap25164 		    ring_buff_read_ptr_pos_get(softc_p->ring_buff_p,
107321Sap25164 		    read_ptr_id);
107421Sap25164 
107521Sap25164 		write_ptr_pos =
107621Sap25164 		    ring_buff_write_ptr_pos_get(softc_p->ring_buff_p);
107721Sap25164 
107821Sap25164 		if (read_ptr_pos != write_ptr_pos) {
107921Sap25164 			ring_buff_has_data = 1;
108021Sap25164 		} else {
108121Sap25164 			ring_buff_has_data = 0;
108221Sap25164 		}
108321Sap25164 
108421Sap25164 		mutex_exit(&softc_p->dcam_frame_is_done_mutex);
108521Sap25164 	}
108621Sap25164 
108721Sap25164 	/*
108821Sap25164 	 * now check for events
108921Sap25164 	 */
109021Sap25164 	if ((events & POLLRDNORM) && ring_buff_has_data) {
109121Sap25164 		revent |= POLLRDNORM;
109221Sap25164 	}
109321Sap25164 
109421Sap25164 	if ((events & POLLPRI) && softc_p->param_status) {
109521Sap25164 		revent |= POLLPRI;
109621Sap25164 	}
109721Sap25164 
109821Sap25164 	/* if no events have occurred */
109921Sap25164 	if (revent == 0) {
110021Sap25164 		if (!anyyet) {
110121Sap25164 			*phpp = &softc_p->dcam_pollhead;
110221Sap25164 		}
110321Sap25164 	}
110421Sap25164 
110521Sap25164 	*reventsp = revent;
110621Sap25164 
110721Sap25164 	return (0);
110821Sap25164 }
110921Sap25164 
111021Sap25164 
111121Sap25164 /*
111221Sap25164  * dcam_bus_reset_notify
111321Sap25164  */
111421Sap25164 /* ARGSUSED */
111521Sap25164 void
dcam_bus_reset_notify(dev_info_t * dip,ddi_eventcookie_t ev_cookie,void * arg,void * impl_data)111621Sap25164 dcam_bus_reset_notify(dev_info_t *dip, ddi_eventcookie_t ev_cookie, void *arg,
111721Sap25164     void *impl_data)
111821Sap25164 {
111921Sap25164 
112021Sap25164 	dcam_state_t 		*softc_p;
112121Sap25164 	t1394_localinfo_t 	*localinfo = impl_data;
112221Sap25164 	t1394_targetinfo_t 	targetinfo;
112321Sap25164 
112421Sap25164 	softc_p = arg;
112521Sap25164 
112621Sap25164 	/*
112721Sap25164 	 * this is needed to handle LG camera "changing GUID" bug
112821Sap25164 	 * XXX: What's this about?
112921Sap25164 	 */
113021Sap25164 	if ((dip == NULL) || (arg == NULL) || (impl_data == NULL) ||
113121Sap25164 	    (softc_p->sl_handle == NULL)) {
113221Sap25164 		return;
113321Sap25164 	}
113421Sap25164 
113521Sap25164 	localinfo = impl_data;
113621Sap25164 
113721Sap25164 	/*
113821Sap25164 	 * simply return if no target info
113921Sap25164 	 */
114021Sap25164 	if (t1394_get_targetinfo(softc_p->sl_handle,
114121Sap25164 	    localinfo->bus_generation, 0, &targetinfo) != DDI_SUCCESS)
114221Sap25164 		return;
114321Sap25164 
114421Sap25164 	if (localinfo->local_nodeID == softc_p->targetinfo.target_nodeID) {
114521Sap25164 		softc_p->param_status |= DCAM1394_STATUS_CAM_UNPLUG;
114621Sap25164 	} else {
114721Sap25164 		softc_p->param_status &= ~DCAM1394_STATUS_CAM_UNPLUG;
114821Sap25164 	}
114921Sap25164 
115021Sap25164 	/* struct copies */
115121Sap25164 	softc_p->attachinfo.localinfo = *localinfo;
115221Sap25164 
115321Sap25164 	if (targetinfo.target_nodeID != T1394_INVALID_NODEID) {
115421Sap25164 		softc_p->targetinfo.current_max_payload =
115521Sap25164 		    targetinfo.current_max_payload;
115621Sap25164 
115721Sap25164 		softc_p->targetinfo.current_max_speed =
115821Sap25164 		    targetinfo.current_max_speed;
115921Sap25164 
116021Sap25164 		softc_p->targetinfo.target_nodeID =
116121Sap25164 		    targetinfo.target_nodeID;
116221Sap25164 	}
116321Sap25164 }
116421Sap25164 
116521Sap25164 
116621Sap25164 /*
116721Sap25164  * byte_copy_to_user_buff
116821Sap25164  */
116921Sap25164 static int
byte_copy_to_user_buff(uchar_t * src_addr_p,struct uio * uio_p,size_t num_bytes,int start_index,int * end_index_p)117021Sap25164 byte_copy_to_user_buff(uchar_t *src_addr_p, struct uio *uio_p, size_t num_bytes,
117121Sap25164     int start_index, int *end_index_p)
117221Sap25164 {
117321Sap25164 	int	 index;
117421Sap25164 	size_t	 len;
117521Sap25164 	uchar_t	*u8_p;
117621Sap25164 
117721Sap25164 	index = start_index;
117821Sap25164 	u8_p  = (uchar_t *)src_addr_p;
117921Sap25164 
118021Sap25164 	while (num_bytes) {
118121Sap25164 
118221Sap25164 		len = num_bytes;
118321Sap25164 
118421Sap25164 		if (uiomove(u8_p, len, UIO_READ, uio_p)) {
118521Sap25164 			return (-1);
118621Sap25164 		}
118721Sap25164 
118821Sap25164 		index++;
118921Sap25164 		u8_p		+= len;
119021Sap25164 		num_bytes	-= len;
119121Sap25164 	}
119221Sap25164 
119321Sap25164 	*end_index_p = index;
119421Sap25164 
119521Sap25164 	return (0);
119621Sap25164 }
119721Sap25164 
119821Sap25164 
119921Sap25164 /*
120021Sap25164  * byte_copy_from_user_buff
120121Sap25164  */
120221Sap25164 static int
byte_copy_from_user_buff(uchar_t * dst_addr_p,struct uio * uio_p,size_t num_bytes,int start_index,int * end_index_p)120321Sap25164 byte_copy_from_user_buff(uchar_t *dst_addr_p, struct uio *uio_p,
120421Sap25164     size_t num_bytes, int start_index, int *end_index_p)
120521Sap25164 {
120621Sap25164 	int	 index;
120721Sap25164 	size_t	 len;
120821Sap25164 	uchar_t	*u8_p;
120921Sap25164 
121021Sap25164 	index = start_index;
121121Sap25164 	u8_p  = (uchar_t *)dst_addr_p;
121221Sap25164 
121321Sap25164 	while (num_bytes) {
121421Sap25164 		len = num_bytes;
121521Sap25164 
121621Sap25164 		if (uiomove(u8_p, len, UIO_WRITE, uio_p)) {
121721Sap25164 			return (-1);
121821Sap25164 
121921Sap25164 		}
122021Sap25164 
122121Sap25164 		index++;
122221Sap25164 		u8_p		+= len;
122321Sap25164 		num_bytes	-= len;
122421Sap25164 
122521Sap25164 	}
122621Sap25164 
122721Sap25164 	*end_index_p = index;
122821Sap25164 
122921Sap25164 	return (0);
123021Sap25164 }
123121Sap25164 
123221Sap25164 
123321Sap25164 /*
123421Sap25164  * dcam_reset()
123521Sap25164  */
123621Sap25164 static int
dcam_reset(dcam_state_t * softc_p)123721Sap25164 dcam_reset(dcam_state_t *softc_p)
123821Sap25164 {
123921Sap25164 	dcam1394_reg_io_t dcam_reg_io;
124021Sap25164 
124121Sap25164 	dcam_reg_io.offs = DCAM1394_REG_OFFS_INITIALIZE;
124221Sap25164 	dcam_reg_io.val  = DCAM1394_REG_VAL_INITIALIZE_ASSERT;
124321Sap25164 
124421Sap25164 	if (dcam_reg_write(softc_p, &dcam_reg_io)) {
124521Sap25164 		return (-1);
124621Sap25164 	}
124721Sap25164 
124821Sap25164 	/*
124921Sap25164 	 * If the camera has a TI VSP, tweak the iris feature
125021Sap25164 	 * to "on" and value 4.
125121Sap25164 	 */
125221Sap25164 	dcam_reg_io.offs = DCAM1394_REG_OFFS_FEATURE_CSR_BASE +
1253*7656SSherry.Moore@Sun.COM 	    DCAM1394_REG_OFFS_IRIS_CSR;
125421Sap25164 	dcam_reg_io.val  = 0x82000004;
125521Sap25164 
125621Sap25164 	if (dcam_reg_write(softc_p, &dcam_reg_io)) {
125721Sap25164 		return (-1);
125821Sap25164 	}
125921Sap25164 
126021Sap25164 	return (0);
126121Sap25164 }
1262