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