xref: /illumos-gate/usr/src/uts/common/io/usb/hubd/hubd.c (revision 24da5b34f49324ed742a340010ed5bd3d4e06625)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * skeleton hub driver, the actual code is in hubdi.c
31  * as it is shared between the root hub and the other hub instances
32  */
33 #if defined(lint) && !defined(DEBUG)
34 #define	DEBUG	1
35 #endif
36 
37 #include <sys/usb/usba/usbai_version.h>
38 #include <sys/usb/usba.h>
39 #include <sys/usb/usba/hubdi.h>
40 #include <sys/usb/hubd/hub.h>
41 #include <sys/usb/hubd/hubdvar.h>
42 
43 static int hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp);
44 static int hubd_close(dev_t dev, int flag, int otyp, cred_t *credp);
45 static int hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
46 	cred_t *credp, int *rvalp);
47 static int hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
48 	void *arg, void **result);
49 extern int usba_hubdi_power(dev_info_t *dip, int comp, int level);
50 
51 
52 static struct cb_ops hubd_cb_ops = {
53 	hubd_open,			/* open */
54 	hubd_close,			/* close */
55 	nodev,				/* strategy */
56 	nodev,				/* print */
57 	nodev,				/* dump */
58 	nodev,				/* read */
59 	nodev,				/* write */
60 	hubd_ioctl,			/* ioctl */
61 	nodev,				/* devmap */
62 	nodev,				/* mmap */
63 	nodev,				/* segmap */
64 	nochpoll,			/* poll */
65 	ddi_prop_op,			/* cb_prop_op */
66 	NULL,				/* streamtab */
67 	D_MP				/* Driver compatibility flag */
68 };
69 
70 static struct dev_ops hubd_ops = {
71 	DEVO_REV,		/* devo_rev, */
72 	0,			/* refcnt  */
73 	hubd_info,		/* info */
74 	nulldev,		/* identify */
75 	nulldev,		/* probe */
76 	usba_hubdi_attach,	/* attach */
77 	usba_hubdi_detach,	/* detach */
78 	nodev,			/* reset */
79 	&hubd_cb_ops,		/* driver operations */
80 	&usba_hubdi_busops,	/* bus operations */
81 	usba_hubdi_power	/* power */
82 };
83 
84 static struct modldrv modldrv = {
85 	&mod_driverops, /* Type of module. This one is a driver */
86 	"USB Hub Driver %I%", /* Name of the module. */
87 	&hubd_ops,	/* driver ops */
88 };
89 
90 static struct modlinkage modlinkage = {
91 	MODREV_1, (void *)&modldrv, NULL
92 };
93 
94 
95 extern void *hubd_statep;
96 
97 int
98 _init(void)
99 {
100 	int rval;
101 
102 	/* Initialize the soft state structures */
103 	if ((rval = ddi_soft_state_init(&hubd_statep,
104 	    sizeof (hubd_t), HUBD_INITIAL_SOFT_SPACE)) != 0) {
105 		return (rval);
106 	}
107 
108 	if ((rval = mod_install(&modlinkage)) != 0) {
109 		ddi_soft_state_fini(&hubd_statep);
110 
111 		return (rval);
112 	}
113 
114 	return (rval);
115 }
116 
117 
118 int
119 _fini(void)
120 {
121 	int rval = mod_remove(&modlinkage);
122 	if (rval == 0) {
123 		ddi_soft_state_fini(&hubd_statep);
124 	}
125 
126 	return (rval);
127 }
128 
129 
130 int
131 _info(struct modinfo *modinfop)
132 {
133 	return (mod_info(&modlinkage, modinfop));
134 }
135 
136 
137 static dev_info_t *
138 hubd_get_dip(dev_t dev)
139 {
140 	minor_t minor = getminor(dev);
141 	int instance = (int)minor & ~HUBD_IS_ROOT_HUB;
142 	hubd_t *hubd = ddi_get_soft_state(hubd_statep, instance);
143 
144 	if (hubd) {
145 		return (hubd->h_dip);
146 	} else {
147 		return (NULL);
148 	}
149 }
150 
151 /*
152  * info handler
153  */
154 /*ARGSUSED*/
155 int
156 hubd_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
157 	void *arg, void **result)
158 {
159 	dev_t dev;
160 	int instance;
161 	int error = DDI_FAILURE;
162 
163 	switch (infocmd) {
164 	case DDI_INFO_DEVT2DEVINFO:
165 		*result = (void *)hubd_get_dip((dev_t)arg);
166 		if (*result != NULL) {
167 			error = DDI_SUCCESS;
168 		}
169 		break;
170 	case DDI_INFO_DEVT2INSTANCE:
171 		dev = (dev_t)arg;
172 		instance = HUBD_UNIT(dev);
173 		*result = (void *)(intptr_t)instance;
174 		error = DDI_SUCCESS;
175 		break;
176 	default:
177 		break;
178 	}
179 	return (error);
180 }
181 
182 static int
183 hubd_open(dev_t *devp, int flags, int otyp, cred_t *credp)
184 {
185 	dev_info_t *dip = hubd_get_dip(*devp);
186 
187 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
188 }
189 
190 
191 static int
192 hubd_close(dev_t dev, int flag, int otyp, cred_t *credp)
193 {
194 	dev_info_t *dip = hubd_get_dip(dev);
195 
196 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
197 }
198 
199 
200 static int
201 hubd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
202 	cred_t *credp, int *rvalp)
203 {
204 	dev_info_t *dip = hubd_get_dip(dev);
205 
206 	return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode,
207 						credp, rvalp));
208 }
209