uplcom.c revision 1.11 1 /* $NetBSD: uplcom.c,v 1.11 2001/01/30 13:17:43 ichiro Exp $ */
2 /*
3 * Copyright (c) 2001 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by FUKUHARA ichiro (ichiro (at) ichiro.org).
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the NetBSD
20 * Foundation, Inc. and its contributors.
21 * 4. Neither the name of The NetBSD Foundation nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Simple datasheet
40 * http://www.prolific.com.tw/download/DataSheet/pl2303_ds11.PDF
41 * http://www.nisseisg.co.jp/jyouhou/_cp/@gif/2303.pdf
42 * (english)
43 *
44 */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/ioctl.h>
50 #include <sys/conf.h>
51 #include <sys/tty.h>
52 #include <sys/file.h>
53 #include <sys/select.h>
54 #include <sys/proc.h>
55 #include <sys/vnode.h>
56 #include <sys/device.h>
57 #include <sys/poll.h>
58
59 #include <dev/usb/usb.h>
60 #include <dev/usb/usbcdc.h>
61
62 #include <dev/usb/usbdi.h>
63 #include <dev/usb/usbdi_util.h>
64 #include <dev/usb/usbdevs.h>
65 #include <dev/usb/usb_quirks.h>
66
67 #include <dev/usb/usbdevs.h>
68 #include <dev/usb/ucomvar.h>
69
70 #ifdef UPLCOM_DEBUG
71 #define DPRINTFN(n, x) if (uplcomdebug > (n)) logprintf x
72 int uplcomdebug = 0xff;
73 #else
74 #define DPRINTFN(n, x)
75 #endif
76 #define DPRINTF(x) DPRINTFN(0, x)
77
78 #define UPLCOM_CONFIG_INDEX 0
79 #define UPLCOM_IFACE_INDEX 0
80 #define UPLCOM_SECOND_IFACE_INDEX 1
81 #define UPLCOM_RESET 0
82
83 struct uplcom_softc {
84 USBBASEDEVICE sc_dev; /* base device */
85 usbd_device_handle sc_udev; /* USB device */
86 usbd_interface_handle sc_iface; /* first interface */
87 usbd_interface_handle sc_sec_iface; /* second interface */
88 int sc_iface_number; /* interface number */
89
90 usb_cdc_line_state_t sc_line_state; /* current line state */
91 u_char sc_dtr; /* current DTR state */
92 u_char sc_rts; /* current RTS state */
93
94 device_ptr_t sc_subdev;
95
96 u_char sc_dying;
97 };
98
99 /*
100 * These are the maximum number of bytes transferred per frame.
101 * The output buffer size cannot be increased due to the size encoding.
102 */
103 #define UPLCOMIBUFSIZE 256
104 #define UPLCOMOBUFSIZE 256
105
106 Static usbd_status uplcom_reset(struct uplcom_softc *);
107 Static usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
108 usb_cdc_line_state_t *state);
109
110 Static void uplcom_set(void *, int, int, int);
111 Static void uplcom_dtr(struct uplcom_softc *, int);
112 Static void uplcom_rts(struct uplcom_softc *, int);
113 Static void uplcom_break(struct uplcom_softc *, int);
114 Static void uplcom_set_line_state(struct uplcom_softc *);
115 Static int uplcom_param(void *, int, struct termios *);
116 Static int uplcom_open(void *, int);
117 Static void uplcom_close(void *, int);
118
119 struct ucom_methods uplcom_methods = {
120 NULL,
121 uplcom_set,
122 uplcom_param,
123 NULL,
124 uplcom_open,
125 uplcom_close,
126 NULL,
127 NULL,
128 };
129
130 static const struct uplcom_product {
131 uint16_t vendor;
132 uint16_t product;
133 } uplcom_products [] = {
134 /* I/O DATA USB-RSAQ2 */
135 { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
136 { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
137
138 { 0, 0 }
139 };
140
141 USB_DECLARE_DRIVER(uplcom);
142
143 USB_MATCH(uplcom)
144 {
145 USB_MATCH_START(uplcom, uaa);
146 int i;
147
148 if (uaa->iface != NULL)
149 return (UMATCH_NONE);
150
151 for (i = 0; uplcom_products[i].vendor != 0; i++) {
152 if (uplcom_products[i].vendor == uaa->vendor &&
153 uplcom_products[i].product == uaa->product) {
154 return (UMATCH_VENDOR_PRODUCT);
155 }
156 }
157 return (UMATCH_NONE);
158 }
159
160 USB_ATTACH(uplcom)
161 {
162 USB_ATTACH_START(uplcom, sc, uaa);
163 usbd_device_handle dev = uaa->device;
164 usbd_interface_handle iface;
165 usb_config_descriptor_t *cdesc;
166 usb_interface_descriptor_t *id;
167 usb_endpoint_descriptor_t *ed;
168
169 char devinfo[1024];
170 char *devname = USBDEVNAME(sc->sc_dev);
171 usbd_status err;
172 int i;
173 struct ucom_attach_args uca;
174
175 usbd_devinfo(dev, 0, devinfo);
176 USB_ATTACH_SETUP;
177 printf("%s: %s\n", devname, devinfo);
178
179 sc->sc_udev = dev;
180
181 DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
182
183 /* Move the device into the configured state. */
184 err = usbd_set_config_index(dev, UPLCOM_CONFIG_INDEX, 1);
185 if (err) {
186 printf("\n%s: failed to set configuration, err=%s\n",
187 devname, usbd_errstr(err));
188 USB_ATTACH_ERROR_RETURN;
189 }
190
191 /* get the config descriptor */
192 cdesc = usbd_get_config_descriptor(sc->sc_udev);
193
194 if (cdesc == NULL) {
195 printf("%s: failed to get configuration descriptor\n",
196 USBDEVNAME(sc->sc_dev));
197 USB_ATTACH_ERROR_RETURN;
198 }
199
200 /* get the (first) interface */
201 err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
202 &sc->sc_iface);
203 if (err) {
204 printf("\n%s: failed to get interface, err=%s\n",
205 devname, usbd_errstr(err));
206 USB_ATTACH_ERROR_RETURN;
207 }
208 /*
209 * check second of interface
210 * USB-RSAQ has two interface
211 */
212 if (cdesc->bNumInterface == 2) {
213 err = usbd_device2interface_handle(dev,
214 UPLCOM_SECOND_IFACE_INDEX, &sc->sc_sec_iface);
215 if (err) {
216 printf("\n%s: failed to get second interface, err=%s\n",
217 devname, usbd_errstr(err));
218 USB_ATTACH_ERROR_RETURN;
219 }
220 iface = sc->sc_sec_iface;
221 } else
222 iface = sc->sc_iface;
223
224 /* Find the bulk endpoints */
225
226 id = usbd_get_interface_descriptor(iface);
227 sc->sc_iface_number = id->bInterfaceNumber;
228
229 uca.bulkin = uca.bulkout = -1;
230 for (i = 0; i < id->bNumEndpoints; i++) {
231 ed = usbd_interface2endpoint_descriptor(iface, i);
232 if (ed == NULL) {
233 printf("%s: no endpoint descriptor for %d\n",
234 USBDEVNAME(sc->sc_dev), i);
235 USB_ATTACH_ERROR_RETURN;
236 }
237
238 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
239 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
240 uca.bulkin = ed->bEndpointAddress;
241 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
242 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
243 DPRINTF(("interrupt endpoint addr = 0x%x\n",
244 ed->bEndpointAddress));
245 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
246 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
247 uca.bulkout = ed->bEndpointAddress;
248 }
249 }
250
251 if (uca.bulkin == -1) {
252 printf("%s: Could not find data bulk in\n",
253 USBDEVNAME(sc->sc_dev));
254 USB_ATTACH_ERROR_RETURN;
255 }
256
257 if (uca.bulkout == -1) {
258 printf("%s: Could not find data bulk out\n",
259 USBDEVNAME(sc->sc_dev));
260 USB_ATTACH_ERROR_RETURN;
261 }
262
263 sc->sc_dtr = -1;
264 uca.portno = UCOM_UNK_PORTNO;
265 /* bulkin, bulkout set above */
266 uca.ibufsize = UPLCOMIBUFSIZE;
267 uca.obufsize = UPLCOMOBUFSIZE;
268 uca.ibufsizepad = UPLCOMIBUFSIZE;
269 uca.opkthdrlen = 0;
270 uca.device = dev;
271 uca.iface = iface;
272 uca.methods = &uplcom_methods;
273 uca.arg = sc;
274 uca.info = NULL;
275
276 err = uplcom_reset(sc);
277
278 if (err) {
279 printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev),
280 usbd_errstr(err));
281 USB_ATTACH_ERROR_RETURN;
282 }
283
284 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
285 USBDEV(sc->sc_dev));
286
287 DPRINTF(("uplcom: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
288 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
289
290 USB_ATTACH_SUCCESS_RETURN;
291 }
292
293 USB_DETACH(uplcom)
294 {
295 USB_DETACH_START(uplcom, sc);
296 int rv = 0;
297
298 DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
299 sc->sc_dying = 1;
300 if (sc->sc_subdev != NULL) {
301 rv = config_detach(sc->sc_subdev, flags);
302 sc->sc_subdev = NULL;
303 }
304
305 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
306 USBDEV(sc->sc_dev));
307
308 return (rv);
309 }
310
311 int
312 uplcom_activate(device_ptr_t self, enum devact act)
313 {
314 struct uplcom_softc *sc = (struct uplcom_softc *)self;
315 int rv = 0;
316
317 switch (act) {
318 case DVACT_ACTIVATE:
319 return (EOPNOTSUPP);
320 break;
321
322 case DVACT_DEACTIVATE:
323 if (sc->sc_subdev != NULL)
324 rv = config_deactivate(sc->sc_subdev);
325 sc->sc_dying = 1;
326 break;
327 }
328 return (rv);
329 }
330
331
332 usbd_status
333 uplcom_reset(struct uplcom_softc *sc)
334 {
335 usb_device_request_t req;
336 usbd_status err;
337
338 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
339 req.bRequest = UPLCOM_RESET;
340 USETW(req.wValue, UPLCOM_RESET);
341 USETW(req.wIndex, sc->sc_iface_number);
342 USETW(req.wLength, 0);
343
344 err = usbd_do_request(sc->sc_udev, &req, 0);
345 if (err)
346 return (EIO);
347
348 return (0);
349 }
350
351 void
352 uplcom_set_line_state(struct uplcom_softc *sc)
353 {
354 usb_device_request_t req;
355 int ls;
356
357 ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
358 (sc->sc_rts ? UCDC_LINE_RTS : 0);
359 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
360 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
361 USETW(req.wValue, ls);
362 USETW(req.wIndex, sc->sc_iface_number);
363 USETW(req.wLength, 0);
364
365 (void)usbd_do_request(sc->sc_udev, &req, 0);
366
367 }
368
369 void
370 uplcom_set(void *addr, int portno, int reg, int onoff)
371 {
372 struct uplcom_softc *sc = addr;
373
374 switch (reg) {
375 case UCOM_SET_DTR:
376 uplcom_dtr(sc, onoff);
377 break;
378 case UCOM_SET_RTS:
379 uplcom_rts(sc, onoff);
380 break;
381 case UCOM_SET_BREAK:
382 uplcom_break(sc, onoff);
383 break;
384 default:
385 break;
386 }
387 }
388
389 void
390 uplcom_dtr(struct uplcom_softc *sc, int onoff)
391 {
392
393 DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
394
395 if (sc->sc_dtr == onoff)
396 return;
397 sc->sc_dtr = onoff;
398
399 uplcom_set_line_state(sc);
400 }
401
402 void
403 uplcom_rts(struct uplcom_softc *sc, int onoff)
404 {
405 DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
406
407 if (sc->sc_rts == onoff)
408 return;
409 sc->sc_rts = onoff;
410
411 uplcom_set_line_state(sc);
412 }
413
414 void
415 uplcom_break(struct uplcom_softc *sc, int onoff)
416 {
417 usb_device_request_t req;
418
419 DPRINTF(("uplcom_break: onoff=%d\n", onoff));
420
421 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
422 req.bRequest = UCDC_SEND_BREAK;
423 USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
424 USETW(req.wIndex, sc->sc_iface_number);
425 USETW(req.wLength, 0);
426
427 (void)usbd_do_request(sc->sc_udev, &req, 0);
428 }
429
430 usbd_status
431 uplcom_set_line_coding(struct uplcom_softc *sc, usb_cdc_line_state_t *state)
432 {
433 usb_device_request_t req;
434 usbd_status err;
435
436 DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
437 UGETDW(state->dwDTERate), state->bCharFormat,
438 state->bParityType, state->bDataBits));
439
440 if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
441 DPRINTF(("uplcom_set_line_coding: already set\n"));
442 return (USBD_NORMAL_COMPLETION);
443 }
444
445 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
446 req.bRequest = UCDC_SET_LINE_CODING;
447 USETW(req.wValue, 0);
448 USETW(req.wIndex, sc->sc_iface_number);
449 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
450
451 err = usbd_do_request(sc->sc_udev, &req, state);
452 if (err) {
453 DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
454 usbd_errstr(err)));
455 return (err);
456 }
457
458 sc->sc_line_state = *state;
459
460 return (USBD_NORMAL_COMPLETION);
461 }
462
463 int
464 uplcom_param(void *addr, int portno, struct termios *t)
465 {
466 struct uplcom_softc *sc = addr;
467 usbd_status err;
468 usb_cdc_line_state_t ls;
469
470 DPRINTF(("uplcom_param: sc=%p\n", sc));
471
472 USETDW(ls.dwDTERate, t->c_ospeed);
473 if (ISSET(t->c_cflag, CSTOPB))
474 ls.bCharFormat = UCDC_STOP_BIT_2;
475 else
476 ls.bCharFormat = UCDC_STOP_BIT_1;
477 if (ISSET(t->c_cflag, PARENB)) {
478 if (ISSET(t->c_cflag, PARODD))
479 ls.bParityType = UCDC_PARITY_ODD;
480 else
481 ls.bParityType = UCDC_PARITY_EVEN;
482 } else
483 ls.bParityType = UCDC_PARITY_NONE;
484 switch (ISSET(t->c_cflag, CSIZE)) {
485 case CS5:
486 ls.bDataBits = 5;
487 break;
488 case CS6:
489 ls.bDataBits = 6;
490 break;
491 case CS7:
492 ls.bDataBits = 7;
493 break;
494 case CS8:
495 ls.bDataBits = 8;
496 break;
497 }
498
499 err = uplcom_set_line_coding(sc, &ls);
500 if (err) {
501 DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
502 return (EIO);
503 }
504 return (0);
505 }
506
507 int
508 uplcom_open(void *addr, int portno)
509 {
510 struct uplcom_softc *sc = addr;
511 usbd_status err;
512
513 if (sc->sc_dying)
514 return (EIO);
515
516 err = uplcom_reset(sc);
517 if (err) {
518 printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev),
519 usbd_errstr(err));
520 }
521
522 DPRINTF(("uplcom_open: open\n"));
523
524 return (0);
525 }
526
527 void
528 uplcom_close(void *addr, int portno)
529 {
530 struct uplcom_softc *sc = addr;
531 usbd_status err;
532
533 if (sc->sc_dying)
534 return;
535
536 err = uplcom_reset(sc);
537 if (err) {
538 printf("%s: reset failed, %s\n", USBDEVNAME(sc->sc_dev),
539 usbd_errstr(err));
540 }
541
542 DPRINTF(("uplcom_close: close\n"));
543 }
544