xref: /illumos-gate/usr/src/uts/common/io/usb/hubd/hubd.c (revision f6f4cb8ada400367a1921f6b93fb9e02f53ac5e6)
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 };
81 
82 static struct modldrv modldrv = {
83 	&mod_driverops, /* Type of module. This one is a driver */
84 	"USB Hub Driver", /* Name of the module. */
85 	&hubd_ops,	/* driver ops */
86 };
87 
88 static struct modlinkage modlinkage = {
89 	MODREV_1, (void *)&modldrv, NULL
90 };
91 
92 
93 extern void *hubd_statep;
94 
95 int
96 _init(void)
97 {
98 	int rval;
99 
100 	/* Initialize the soft state structures */
101 	if ((rval = ddi_soft_state_init(&hubd_statep,
102 	    sizeof (hubd_t), HUBD_INITIAL_SOFT_SPACE)) != 0) {
103 		return (rval);
104 	}
105 
106 	if ((rval = mod_install(&modlinkage)) != 0) {
107 		ddi_soft_state_fini(&hubd_statep);
108 
109 		return (rval);
110 	}
111 
112 	return (rval);
113 }
114 
115 
116 int
117 _fini(void)
118 {
119 	int rval = mod_remove(&modlinkage);
120 	if (rval == 0) {
121 		ddi_soft_state_fini(&hubd_statep);
122 	}
123 
124 	return (rval);
125 }
126 
127 
128 int
129 _info(struct modinfo *modinfop)
130 {
131 	return (mod_info(&modlinkage, modinfop));
132 }
133 
134 
135 static dev_info_t *
136 hubd_get_dip(dev_t dev)
137 {
138 	minor_t minor = getminor(dev);
139 	int instance = (int)minor & ~HUBD_IS_ROOT_HUB;
140 	hubd_t *hubd = ddi_get_soft_state(hubd_statep, instance);
141 
142 	if (hubd) {
143 		return (hubd->h_dip);
144 	} else {
145 		return (NULL);
146 	}
147 }
148 
149 /*
150  * info handler
151  */
152 /*ARGSUSED*/
153 int
154 hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
155 	void *arg, void **result)
156 {
157 	dev_t dev;
158 	int instance;
159 	int error = DDI_FAILURE;
160 
161 	switch (infocmd) {
162 	case DDI_INFO_DEVT2DEVINFO:
163 		*result = (void *)hubd_get_dip((dev_t)arg);
164 		if (*result != NULL) {
165 			error = DDI_SUCCESS;
166 		}
167 		break;
168 	case DDI_INFO_DEVT2INSTANCE:
169 		dev = (dev_t)arg;
170 		instance = HUBD_UNIT(dev);
171 		*result = (void *)(intptr_t)instance;
172 		error = DDI_SUCCESS;
173 		break;
174 	default:
175 		break;
176 	}
177 	return (error);
178 }
179 
180 static int
181 hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp)
182 {
183 	dev_info_t *dip = hubd_get_dip(*devp);
184 
185 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
186 }
187 
188 
189 static int
190 hubd_close(dev_t dev, int flag, int otyp, cred_t *credp)
191 {
192 	dev_info_t *dip = hubd_get_dip(dev);
193 
194 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
195 }
196 
197 
198 static int
199 hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
200 	cred_t *credp, int *rvalp)
201 {
202 	dev_info_t *dip = hubd_get_dip(dev);
203 
204 	return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode,
205 	    credp, rvalp));
206 }
207