xref: /illumos-gate/usr/src/uts/common/io/usb/hubd/hubd.c (revision 9a5d73e03cd3312ddb571a748c40a63c58bd66e5)
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  * skeleton hub driver, the actual code is in hubdi.c
29  * as it is shared between the root hub and the other hub instances
30  */
31 #if defined(lint) && !defined(DEBUG)
32 #define	DEBUG	1
33 #endif
34 
35 #include <sys/usb/usba/usbai_version.h>
36 #include <sys/usb/usba.h>
37 #include <sys/usb/usba/hubdi.h>
38 #include <sys/usb/hubd/hub.h>
39 #include <sys/usb/hubd/hubdvar.h>
40 
41 static int hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp);
42 static int hubd_close(dev_t dev, int flag, int otyp, cred_t *credp);
43 static int hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
44 	cred_t *credp, int *rvalp);
45 static int hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
46 	void *arg, void **result);
47 extern int usba_hubdi_power(dev_info_t *dip, int comp, int level);
48 
49 
50 static struct cb_ops hubd_cb_ops = {
51 	hubd_open,			/* open */
52 	hubd_close,			/* close */
53 	nodev,				/* strategy */
54 	nodev,				/* print */
55 	nodev,				/* dump */
56 	nodev,				/* read */
57 	nodev,				/* write */
58 	hubd_ioctl,			/* ioctl */
59 	nodev,				/* devmap */
60 	nodev,				/* mmap */
61 	nodev,				/* segmap */
62 	nochpoll,			/* poll */
63 	ddi_prop_op,			/* cb_prop_op */
64 	NULL,				/* streamtab */
65 	D_MP				/* Driver compatibility flag */
66 };
67 
68 static struct dev_ops hubd_ops = {
69 	DEVO_REV,		/* devo_rev, */
70 	0,			/* refcnt  */
71 	hubd_info,		/* info */
72 	nulldev,		/* identify */
73 	nulldev,		/* probe */
74 	usba_hubdi_attach,	/* attach */
75 	usba_hubdi_detach,	/* detach */
76 	nodev,			/* reset */
77 	&hubd_cb_ops,		/* driver operations */
78 	&usba_hubdi_busops,	/* bus operations */
79 	usba_hubdi_power,	/* power */
80 	ddi_quiesce_not_needed,		/* quiesce */
81 };
82 
83 static struct modldrv modldrv = {
84 	&mod_driverops, /* Type of module. This one is a driver */
85 	"USB Hub Driver", /* Name of the module. */
86 	&hubd_ops,	/* driver ops */
87 };
88 
89 static struct modlinkage modlinkage = {
90 	MODREV_1, (void *)&modldrv, NULL
91 };
92 
93 
94 extern void *hubd_statep;
95 
96 int
97 _init(void)
98 {
99 	int rval;
100 
101 	/* Initialize the soft state structures */
102 	if ((rval = ddi_soft_state_init(&hubd_statep,
103 	    sizeof (hubd_t), HUBD_INITIAL_SOFT_SPACE)) != 0) {
104 		return (rval);
105 	}
106 
107 	if ((rval = mod_install(&modlinkage)) != 0) {
108 		ddi_soft_state_fini(&hubd_statep);
109 
110 		return (rval);
111 	}
112 
113 	return (rval);
114 }
115 
116 
117 int
118 _fini(void)
119 {
120 	int rval = mod_remove(&modlinkage);
121 	if (rval == 0) {
122 		ddi_soft_state_fini(&hubd_statep);
123 	}
124 
125 	return (rval);
126 }
127 
128 
129 int
130 _info(struct modinfo *modinfop)
131 {
132 	return (mod_info(&modlinkage, modinfop));
133 }
134 
135 
136 static dev_info_t *
137 hubd_get_dip(dev_t dev)
138 {
139 	minor_t minor = getminor(dev);
140 	int instance = (int)minor & ~HUBD_IS_ROOT_HUB;
141 	hubd_t *hubd = ddi_get_soft_state(hubd_statep, instance);
142 
143 	if (hubd) {
144 		return (hubd->h_dip);
145 	} else {
146 		return (NULL);
147 	}
148 }
149 
150 /*
151  * info handler
152  */
153 /*ARGSUSED*/
154 int
155 hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
156 	void *arg, void **result)
157 {
158 	dev_t dev;
159 	int instance;
160 	int error = DDI_FAILURE;
161 
162 	switch (infocmd) {
163 	case DDI_INFO_DEVT2DEVINFO:
164 		*result = (void *)hubd_get_dip((dev_t)arg);
165 		if (*result != NULL) {
166 			error = DDI_SUCCESS;
167 		}
168 		break;
169 	case DDI_INFO_DEVT2INSTANCE:
170 		dev = (dev_t)arg;
171 		instance = HUBD_UNIT(dev);
172 		*result = (void *)(intptr_t)instance;
173 		error = DDI_SUCCESS;
174 		break;
175 	default:
176 		break;
177 	}
178 	return (error);
179 }
180 
181 static int
182 hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp)
183 {
184 	dev_info_t *dip = hubd_get_dip(*devp);
185 
186 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
187 }
188 
189 
190 static int
191 hubd_close(dev_t dev, int flag, int otyp, cred_t *credp)
192 {
193 	dev_info_t *dip = hubd_get_dip(dev);
194 
195 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
196 }
197 
198 
199 static int
200 hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
201 	cred_t *credp, int *rvalp)
202 {
203 	dev_info_t *dip = hubd_get_dip(dev);
204 
205 	return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode,
206 	    credp, rvalp));
207 }
208