ugensa.c revision 1.16 1 1.16 elric /* $NetBSD: ugensa.c,v 1.16 2008/03/17 02:40:04 elric Exp $ */
2 1.1 elric
3 1.1 elric /*
4 1.1 elric * Copyright (c) 2004, 2005 The NetBSD Foundation, Inc.
5 1.1 elric * All rights reserved.
6 1.1 elric *
7 1.1 elric * This code is derived from software contributed to The NetBSD Foundation
8 1.1 elric * by Roland C. Dowdeswell <elric (at) netbsd.org>.
9 1.1 elric *
10 1.1 elric * Redistribution and use in source and binary forms, with or without
11 1.1 elric * modification, are permitted provided that the following conditions
12 1.1 elric * are met:
13 1.1 elric * 1. Redistributions of source code must retain the above copyright
14 1.1 elric * notice, this list of conditions and the following disclaimer.
15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 elric * notice, this list of conditions and the following disclaimer in the
17 1.1 elric * documentation and/or other materials provided with the distribution.
18 1.1 elric * 3. All advertising materials mentioning features or use of this software
19 1.1 elric * must display the following acknowledgement:
20 1.1 elric * This product includes software developed by the NetBSD
21 1.1 elric * Foundation, Inc. and its contributors.
22 1.1 elric * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 elric * contributors may be used to endorse or promote products derived
24 1.1 elric * from this software without specific prior written permission.
25 1.1 elric *
26 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 elric * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 elric * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 elric * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 elric * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 elric * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 elric * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 elric * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 elric * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 elric * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 elric * POSSIBILITY OF SUCH DAMAGE.
37 1.1 elric */
38 1.1 elric
39 1.13 lukem #include <sys/cdefs.h>
40 1.16 elric __KERNEL_RCSID(0, "$NetBSD: ugensa.c,v 1.16 2008/03/17 02:40:04 elric Exp $");
41 1.13 lukem
42 1.1 elric #include <sys/param.h>
43 1.1 elric #include <sys/systm.h>
44 1.1 elric #include <sys/kernel.h>
45 1.1 elric #include <sys/device.h>
46 1.1 elric #include <sys/conf.h>
47 1.1 elric #include <sys/tty.h>
48 1.1 elric
49 1.1 elric #include <dev/usb/usb.h>
50 1.1 elric
51 1.1 elric #include <dev/usb/usbdi.h>
52 1.1 elric #include <dev/usb/usbdi_util.h>
53 1.1 elric #include <dev/usb/usbdevs.h>
54 1.1 elric
55 1.1 elric #include <dev/usb/ucomvar.h>
56 1.1 elric
57 1.1 elric /* XXXrcd: heh */
58 1.1 elric #define UGENSA_DEBUG 1
59 1.1 elric
60 1.1 elric #ifdef UGENSA_DEBUG
61 1.1 elric #define DPRINTF(x) if (ugensadebug) printf x
62 1.1 elric #define DPRINTFN(n,x) if (ugensadebug>(n)) printf x
63 1.1 elric int ugensadebug = 0;
64 1.1 elric #else
65 1.1 elric #define DPRINTF(x)
66 1.1 elric #define DPRINTFN(n,x)
67 1.1 elric #endif
68 1.1 elric
69 1.1 elric struct ugensa_softc {
70 1.1 elric USBBASEDEVICE sc_dev; /* base device */
71 1.1 elric usbd_device_handle sc_udev; /* device */
72 1.1 elric usbd_interface_handle sc_iface; /* interface */
73 1.1 elric
74 1.15 dyoung device_t sc_subdev;
75 1.1 elric int sc_numcon;
76 1.1 elric
77 1.1 elric u_char sc_dying;
78 1.1 elric };
79 1.1 elric
80 1.1 elric struct ucom_methods ugensa_methods = {
81 1.1 elric NULL,
82 1.1 elric NULL,
83 1.1 elric NULL,
84 1.1 elric NULL,
85 1.1 elric NULL,
86 1.1 elric NULL,
87 1.1 elric NULL,
88 1.1 elric NULL,
89 1.1 elric };
90 1.1 elric
91 1.1 elric #define UGENSA_CONFIG_INDEX 0
92 1.1 elric #define UGENSA_IFACE_INDEX 0
93 1.1 elric #define UGENSA_BUFSIZE 1024
94 1.1 elric
95 1.16 elric struct ugensa_type {
96 1.16 elric struct usb_devno ugensa_dev;
97 1.16 elric u_int16_t ugensa_flags;
98 1.16 elric #define UNTESTED 0x0001
99 1.1 elric };
100 1.16 elric
101 1.16 elric static const struct ugensa_type ugensa_devs[] = {
102 1.16 elric {{ USB_VENDOR_AIRPRIME, USB_PRODUCT_AIRPRIME_PC5220 }, 0 },
103 1.16 elric {{ USB_VENDOR_NOVATEL, USB_PRODUCT_NOVATEL_FLEXPACKGPS }, 0 },
104 1.16 elric {{ USB_VENDOR_QUALCOMM_K, USB_PRODUCT_QUALCOMM_K_CDMA_MSM_K }, 0 },
105 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD580 }, 0 },
106 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD595 }, 0 },
107 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MINI5725}, 0 },
108 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_MERLINV620 }, 0 },
109 1.16 elric {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_HSDPA }, 0 },
110 1.16 elric
111 1.16 elric /*
112 1.16 elric * The following devices are untested, but they are purported to
113 1.16 elric * to work in similar device drivers on other OSes:
114 1.16 elric */
115 1.16 elric
116 1.16 elric {{ USB_VENDOR_ANYDATA, USB_PRODUCT_ANYDATA_ADU_500A }, UNTESTED },
117 1.16 elric {{ USB_VENDOR_DELL, USB_PRODUCT_DELL_W5500 }, UNTESTED },
118 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_EXPRESSCARD }, UNTESTED },
119 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_S720 }, UNTESTED },
120 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_U720 }, UNTESTED },
121 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_XU870 }, UNTESTED },
122 1.16 elric {{ USB_VENDOR_NOVATEL2, USB_PRODUCT_NOVATEL2_ES620 }, UNTESTED },
123 1.16 elric {{ USB_VENDOR_QUALCOMM, USB_PRODUCT_QUALCOMM_MSM_HSDPA }, UNTESTED },
124 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_EM5625 }, UNTESTED },
125 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_AIRCARD875 }, UNTESTED },
126 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5720 }, UNTESTED },
127 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC5725 }, UNTESTED },
128 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755 }, UNTESTED },
129 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_2 }, UNTESTED },
130 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8755_3 }, UNTESTED },
131 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8765 }, UNTESTED },
132 1.16 elric {{ USB_VENDOR_SIERRA, USB_PRODUCT_SIERRA_MC8775 }, UNTESTED }
133 1.16 elric };
134 1.16 elric #define ugensa_lookup(v, p) \
135 1.16 elric ((const struct ugensa_type *)usb_lookup(ugensa_devs, v, p))
136 1.1 elric
137 1.15 dyoung int ugensa_match(device_t, struct cfdata *, void *);
138 1.15 dyoung void ugensa_attach(device_t, device_t, void *);
139 1.15 dyoung void ugensa_childdet(device_t, device_t);
140 1.15 dyoung int ugensa_detach(device_t, int);
141 1.15 dyoung int ugensa_activate(device_t, enum devact);
142 1.15 dyoung extern struct cfdriver ugensa_cd;
143 1.15 dyoung CFATTACH_DECL2(ugensa, sizeof(struct ugensa_softc), ugensa_match,
144 1.15 dyoung ugensa_attach, ugensa_detach, ugensa_activate, NULL, ugensa_childdet);
145 1.1 elric
146 1.1 elric USB_MATCH(ugensa)
147 1.1 elric {
148 1.1 elric USB_MATCH_START(ugensa, uaa);
149 1.1 elric
150 1.1 elric DPRINTFN(20,("ugensa: vendor=0x%x, product=0x%x\n",
151 1.1 elric uaa->vendor, uaa->product));
152 1.1 elric
153 1.1 elric return (ugensa_lookup(uaa->vendor, uaa->product) != NULL ?
154 1.1 elric UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
155 1.1 elric }
156 1.1 elric
157 1.1 elric USB_ATTACH(ugensa)
158 1.1 elric {
159 1.1 elric USB_ATTACH_START(ugensa, sc, uaa);
160 1.1 elric usbd_device_handle dev = uaa->device;
161 1.1 elric usbd_interface_handle iface;
162 1.1 elric usb_interface_descriptor_t *id;
163 1.1 elric usb_endpoint_descriptor_t *ed;
164 1.3 augustss char *devinfop;
165 1.1 elric char *devname = USBDEVNAME(sc->sc_dev);
166 1.1 elric usbd_status err;
167 1.1 elric struct ucom_attach_args uca;
168 1.1 elric int i;
169 1.1 elric
170 1.1 elric DPRINTFN(10,("\nugensa_attach: sc=%p\n", sc));
171 1.1 elric
172 1.1 elric /* Move the device into the configured state. */
173 1.1 elric err = usbd_set_config_index(dev, UGENSA_CONFIG_INDEX, 1);
174 1.1 elric if (err) {
175 1.1 elric printf("\n%s: failed to set configuration, err=%s\n",
176 1.1 elric devname, usbd_errstr(err));
177 1.1 elric goto bad;
178 1.1 elric }
179 1.1 elric
180 1.1 elric err = usbd_device2interface_handle(dev, UGENSA_IFACE_INDEX, &iface);
181 1.1 elric if (err) {
182 1.1 elric printf("\n%s: failed to get interface, err=%s\n",
183 1.1 elric devname, usbd_errstr(err));
184 1.1 elric goto bad;
185 1.1 elric }
186 1.1 elric
187 1.3 augustss devinfop = usbd_devinfo_alloc(dev, 0);
188 1.1 elric USB_ATTACH_SETUP;
189 1.3 augustss printf("%s: %s\n", devname, devinfop);
190 1.3 augustss usbd_devinfo_free(devinfop);
191 1.1 elric
192 1.16 elric if (ugensa_lookup(uaa->vendor, uaa->product)->ugensa_flags & UNTESTED)
193 1.16 elric printf("%s: WARNING: This device is marked as untested. "
194 1.16 elric "Please submit a report via send-pr(1).\n", devname);
195 1.16 elric
196 1.1 elric id = usbd_get_interface_descriptor(iface);
197 1.1 elric
198 1.1 elric sc->sc_udev = dev;
199 1.1 elric sc->sc_iface = iface;
200 1.1 elric
201 1.2 elric uca.info = "Generic Serial Device";
202 1.1 elric uca.ibufsize = UGENSA_BUFSIZE;
203 1.1 elric uca.obufsize = UGENSA_BUFSIZE;
204 1.1 elric uca.ibufsizepad = UGENSA_BUFSIZE;
205 1.7 martin uca.portno = UCOM_UNK_PORTNO;
206 1.1 elric uca.opkthdrlen = 0;
207 1.1 elric uca.device = dev;
208 1.1 elric uca.iface = iface;
209 1.1 elric uca.methods = &ugensa_methods;
210 1.1 elric uca.arg = sc;
211 1.1 elric
212 1.1 elric usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
213 1.1 elric USBDEV(sc->sc_dev));
214 1.1 elric
215 1.1 elric uca.bulkin = uca.bulkout = -1;
216 1.1 elric for (i = 0; i < id->bNumEndpoints; i++) {
217 1.1 elric int addr, dir, attr;
218 1.1 elric
219 1.1 elric ed = usbd_interface2endpoint_descriptor(iface, i);
220 1.1 elric if (ed == NULL) {
221 1.1 elric printf("%s: could not read endpoint descriptor"
222 1.1 elric ": %s\n", devname, usbd_errstr(err));
223 1.1 elric goto bad;
224 1.1 elric }
225 1.1 elric
226 1.1 elric addr = ed->bEndpointAddress;
227 1.1 elric dir = UE_GET_DIR(ed->bEndpointAddress);
228 1.1 elric attr = ed->bmAttributes & UE_XFERTYPE;
229 1.16 elric if (attr == UE_BULK) {
230 1.16 elric if (uca.bulkin == -1 && dir == UE_DIR_IN) {
231 1.16 elric DPRINTF(("%s: Bulk in %d\n", devname, i));
232 1.16 elric uca.bulkin = addr;
233 1.16 elric continue;
234 1.16 elric }
235 1.16 elric if (uca.bulkout == -1 && dir == UE_DIR_OUT) {
236 1.16 elric DPRINTF(("%s: Bulk out %d\n", devname, i));
237 1.16 elric uca.bulkout = addr;
238 1.16 elric continue;
239 1.16 elric }
240 1.16 elric }
241 1.16 elric printf("%s: unexpected endpoint\n", devname);
242 1.1 elric }
243 1.1 elric if (uca.bulkin == -1) {
244 1.1 elric printf("%s: Could not find data bulk in\n",
245 1.1 elric USBDEVNAME(sc->sc_dev));
246 1.1 elric goto bad;
247 1.1 elric }
248 1.1 elric if (uca.bulkout == -1) {
249 1.1 elric printf("%s: Could not find data bulk out\n",
250 1.1 elric USBDEVNAME(sc->sc_dev));
251 1.1 elric goto bad;
252 1.1 elric }
253 1.1 elric
254 1.1 elric DPRINTF(("ugensa: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
255 1.1 elric sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
256 1.1 elric ucomprint, ucomsubmatch);
257 1.1 elric
258 1.14 smb if (!pmf_device_register(self, NULL, NULL))
259 1.14 smb aprint_error_dev(self, "couldn't establish power handler\n");
260 1.1 elric USB_ATTACH_SUCCESS_RETURN;
261 1.1 elric
262 1.1 elric bad:
263 1.1 elric DPRINTF(("ugensa_attach: ATTACH ERROR\n"));
264 1.1 elric sc->sc_dying = 1;
265 1.1 elric USB_ATTACH_ERROR_RETURN;
266 1.1 elric }
267 1.1 elric
268 1.15 dyoung void
269 1.15 dyoung ugensa_childdet(device_t self, device_t child)
270 1.15 dyoung {
271 1.15 dyoung struct ugensa_softc *sc = device_private(self);
272 1.15 dyoung
273 1.15 dyoung KASSERT(sc->sc_subdev == child);
274 1.15 dyoung sc->sc_subdev = NULL;
275 1.15 dyoung }
276 1.15 dyoung
277 1.1 elric int
278 1.15 dyoung ugensa_activate(device_t self, enum devact act)
279 1.1 elric {
280 1.15 dyoung struct ugensa_softc *sc = device_private(self);
281 1.1 elric int rv = 0;
282 1.1 elric
283 1.16 elric DPRINTF(("ugensa_activate: sc=%p\n", sc));
284 1.16 elric
285 1.1 elric switch (act) {
286 1.1 elric case DVACT_ACTIVATE:
287 1.1 elric return (EOPNOTSUPP);
288 1.1 elric break;
289 1.1 elric
290 1.1 elric case DVACT_DEACTIVATE:
291 1.1 elric sc->sc_dying = 1;
292 1.1 elric if (sc->sc_subdev)
293 1.1 elric rv = config_deactivate(sc->sc_subdev);
294 1.1 elric break;
295 1.1 elric }
296 1.1 elric return (rv);
297 1.1 elric }
298 1.1 elric
299 1.1 elric USB_DETACH(ugensa)
300 1.1 elric {
301 1.1 elric USB_DETACH_START(ugensa, sc);
302 1.1 elric int rv = 0;
303 1.1 elric
304 1.1 elric DPRINTF(("ugensa_detach: sc=%p flags=%d\n", sc, flags));
305 1.1 elric
306 1.1 elric sc->sc_dying = 1;
307 1.14 smb pmf_device_deregister(self);
308 1.1 elric
309 1.1 elric if (sc->sc_subdev != NULL)
310 1.1 elric rv = config_detach(sc->sc_subdev, flags);
311 1.1 elric
312 1.1 elric usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
313 1.1 elric USBDEV(sc->sc_dev));
314 1.1 elric
315 1.1 elric return (rv);
316 1.1 elric }
317