Line data Source code
1 : /* $OpenBSD: uplcom.c,v 1.72 2018/06/18 19:05:24 mikeb Exp $ */
2 : /* $NetBSD: uplcom.c,v 1.29 2002/09/23 05:51:23 simonb Exp $ */
3 : /*
4 : * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 : * All rights reserved.
6 : *
7 : * This code is derived from software contributed to The NetBSD Foundation
8 : * by Ichiro FUKUHARA (ichiro@ichiro.org).
9 : *
10 : * Redistribution and use in source and binary forms, with or without
11 : * modification, are permitted provided that the following conditions
12 : * are met:
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : * 2. Redistributions in binary form must reproduce the above copyright
16 : * notice, this list of conditions and the following disclaimer in the
17 : * documentation and/or other materials provided with the distribution.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 : * POSSIBILITY OF SUCH DAMAGE.
30 : */
31 :
32 : /*
33 : * Simple datasheet
34 : * http://www.prolific.com.tw/PDF/PL-2303%20Market%20Spec.pdf
35 : * http://www.hitachi-hitec.com/jyouhou/prolific/2303.pdf
36 : * (english)
37 : *
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/kernel.h>
43 : #include <sys/malloc.h>
44 : #include <sys/ioctl.h>
45 : #include <sys/conf.h>
46 : #include <sys/tty.h>
47 : #include <sys/selinfo.h>
48 : #include <sys/device.h>
49 : #include <sys/poll.h>
50 :
51 : #include <dev/usb/usb.h>
52 : #include <dev/usb/usbcdc.h>
53 :
54 : #include <dev/usb/usbdi.h>
55 : #include <dev/usb/usbdi_util.h>
56 : #include <dev/usb/usbdevs.h>
57 :
58 : #include <dev/usb/ucomvar.h>
59 :
60 : #ifdef UPLCOM_DEBUG
61 : #define DPRINTFN(n, x) do { if (uplcomdebug > (n)) printf x; } while (0)
62 : int uplcomdebug = 0;
63 : #else
64 : #define DPRINTFN(n, x)
65 : #endif
66 : #define DPRINTF(x) DPRINTFN(0, x)
67 :
68 : #define UPLCOM_IFACE_INDEX 0
69 : #define UPLCOM_SECOND_IFACE_INDEX 1
70 :
71 : #define UPLCOM_SET_REQUEST 0x01
72 : #define UPLCOM_SET_CRTSCTS 0x41
73 : #define UPLCOM_HX_SET_CRTSCTS 0x61
74 : #define RSAQ_STATUS_CTS 0x80
75 : #define RSAQ_STATUS_DSR 0x02
76 : #define RSAQ_STATUS_DCD 0x01
77 :
78 : struct uplcom_softc {
79 : struct device sc_dev; /* base device */
80 : struct usbd_device *sc_udev; /* USB device */
81 : struct usbd_interface *sc_iface; /* interface */
82 : int sc_iface_number; /* interface number */
83 :
84 : struct usbd_interface *sc_intr_iface; /* interrupt interface */
85 : int sc_intr_number; /* interrupt number */
86 : struct usbd_pipe *sc_intr_pipe; /* interrupt pipe */
87 : u_char *sc_intr_buf; /* interrupt buffer */
88 : int sc_isize;
89 :
90 : struct usb_cdc_line_state sc_line_state;/* current line state */
91 : int sc_dtr; /* current DTR state */
92 : int sc_rts; /* current RTS state */
93 :
94 : struct device *sc_subdev; /* ucom device */
95 :
96 : u_char sc_lsr; /* Local status register */
97 : u_char sc_msr; /* uplcom status register */
98 : int sc_type_hx; /* HX variant */
99 : };
100 :
101 : /*
102 : * These are the maximum number of bytes transferred per frame.
103 : * The output buffer size cannot be increased due to the size encoding.
104 : */
105 : #define UPLCOMIBUFSIZE 256
106 : #define UPLCOMOBUFSIZE 256
107 :
108 : usbd_status uplcom_reset(struct uplcom_softc *);
109 : usbd_status uplcom_set_line_coding(struct uplcom_softc *sc,
110 : struct usb_cdc_line_state *state);
111 : usbd_status uplcom_set_crtscts(struct uplcom_softc *);
112 : void uplcom_intr(struct usbd_xfer *, void *, usbd_status);
113 :
114 : void uplcom_set(void *, int, int, int);
115 : void uplcom_dtr(struct uplcom_softc *, int);
116 : void uplcom_rts(struct uplcom_softc *, int);
117 : void uplcom_break(struct uplcom_softc *, int);
118 : void uplcom_set_line_state(struct uplcom_softc *);
119 : void uplcom_get_status(void *, int portno, u_char *lsr, u_char *msr);
120 : int uplcom_param(void *, int, struct termios *);
121 : int uplcom_open(void *, int);
122 : void uplcom_close(void *, int);
123 :
124 : struct ucom_methods uplcom_methods = {
125 : uplcom_get_status,
126 : uplcom_set,
127 : uplcom_param,
128 : NULL,
129 : uplcom_open,
130 : uplcom_close,
131 : NULL,
132 : NULL,
133 : };
134 :
135 : static const struct usb_devno uplcom_devs[] = {
136 : { USB_VENDOR_ALCATEL, USB_PRODUCT_ALCATEL_OT535 },
137 : { USB_VENDOR_ANCHOR, USB_PRODUCT_ANCHOR_SERIAL },
138 : { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC232A },
139 : { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U257 },
140 : { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT },
141 : { USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_UCSGT0 },
142 : { USB_VENDOR_HAL, USB_PRODUCT_HAL_IMR001 },
143 : { USB_VENDOR_HP, USB_PRODUCT_HP_LD220 },
144 : { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ },
145 : { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBRSAQ5 },
146 : { USB_VENDOR_LEADTEK, USB_PRODUCT_LEADTEK_9531 },
147 : { USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_700WX },
148 : { USB_VENDOR_MOBILEACTION, USB_PRODUCT_MOBILEACTION_MA620 },
149 : { USB_VENDOR_NOKIA, USB_PRODUCT_NOKIA_CA42 },
150 : { USB_VENDOR_OTI, USB_PRODUCT_OTI_DKU5 },
151 : { USB_VENDOR_PLX, USB_PRODUCT_PLX_CA42 },
152 : { USB_VENDOR_PANASONIC, USB_PRODUCT_PANASONIC_TYTP50P6S },
153 : { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303 },
154 : { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X },
155 : { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303X2 },
156 : { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_RSAQ2 },
157 : { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2303BENQ },
158 : { USB_VENDOR_PROLIFIC2, USB_PRODUCT_PROLIFIC2_PL2303 },
159 : { USB_VENDOR_RADIOSHACK, USB_PRODUCT_RADIOSHACK_PL2303 },
160 : { USB_VENDOR_RATOC, USB_PRODUCT_RATOC_REXUSB60 },
161 : { USB_VENDOR_SAGEM, USB_PRODUCT_SAGEM_SERIAL },
162 : { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_SX1 },
163 : { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X65 },
164 : { USB_VENDOR_SIEMENS3, USB_PRODUCT_SIEMENS3_X75 },
165 : { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_CN104 },
166 : { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8 },
167 : { USB_VENDOR_SOURCENEXT, USB_PRODUCT_SOURCENEXT_KEIKAI8_CHG },
168 : { USB_VENDOR_SPEEDDRAGON, USB_PRODUCT_SPEEDDRAGON_MS3303H },
169 : { USB_VENDOR_SUSTEEN, USB_PRODUCT_SUSTEEN_DCU11 },
170 : { USB_VENDOR_SYNTECH, USB_PRODUCT_SYNTECH_SERIAL },
171 : { USB_VENDOR_TDK, USB_PRODUCT_TDK_UHA6400 },
172 : { USB_VENDOR_TDK, USB_PRODUCT_TDK_UPA9664 },
173 : { USB_VENDOR_TRIPPLITE, USB_PRODUCT_TRIPPLITE_U209 },
174 : { USB_VENDOR_SMART, USB_PRODUCT_SMART_PL2303 },
175 : { USB_VENDOR_YCCABLE, USB_PRODUCT_YCCABLE_PL2303 }
176 : };
177 : #define uplcom_lookup(v, p) usb_lookup(uplcom_devs, v, p)
178 :
179 : int uplcom_match(struct device *, void *, void *);
180 : void uplcom_attach(struct device *, struct device *, void *);
181 : int uplcom_detach(struct device *, int);
182 :
183 : struct cfdriver uplcom_cd = {
184 : NULL, "uplcom", DV_DULL
185 : };
186 :
187 : const struct cfattach uplcom_ca = {
188 : sizeof(struct uplcom_softc), uplcom_match, uplcom_attach, uplcom_detach
189 : };
190 :
191 : int
192 0 : uplcom_match(struct device *parent, void *match, void *aux)
193 : {
194 0 : struct usb_attach_arg *uaa = aux;
195 :
196 0 : if (uaa->iface == NULL)
197 0 : return (UMATCH_NONE);
198 :
199 0 : return (uplcom_lookup(uaa->vendor, uaa->product) != NULL ?
200 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
201 0 : }
202 :
203 : void
204 0 : uplcom_attach(struct device *parent, struct device *self, void *aux)
205 : {
206 0 : struct uplcom_softc *sc = (struct uplcom_softc *)self;
207 0 : struct usb_attach_arg *uaa = aux;
208 0 : struct usbd_device *dev = uaa->device;
209 : usb_config_descriptor_t *cdesc;
210 : usb_device_descriptor_t *ddesc;
211 : usb_interface_descriptor_t *id;
212 : usb_endpoint_descriptor_t *ed;
213 0 : char *devname = sc->sc_dev.dv_xname;
214 : usbd_status err;
215 : int i;
216 0 : struct ucom_attach_args uca;
217 :
218 0 : sc->sc_udev = dev;
219 :
220 : DPRINTF(("\n\nuplcom attach: sc=%p\n", sc));
221 :
222 : /* initialize endpoints */
223 0 : uca.bulkin = uca.bulkout = -1;
224 0 : sc->sc_intr_number = -1;
225 0 : sc->sc_intr_pipe = NULL;
226 :
227 : /* get the config descriptor */
228 0 : cdesc = usbd_get_config_descriptor(sc->sc_udev);
229 :
230 0 : if (cdesc == NULL) {
231 0 : printf("%s: failed to get configuration descriptor\n",
232 : sc->sc_dev.dv_xname);
233 0 : usbd_deactivate(sc->sc_udev);
234 0 : return;
235 : }
236 :
237 : /* get the device descriptor */
238 0 : ddesc = usbd_get_device_descriptor(sc->sc_udev);
239 0 : if (ddesc == NULL) {
240 0 : printf("%s: failed to get device descriptor\n",
241 : sc->sc_dev.dv_xname);
242 0 : usbd_deactivate(sc->sc_udev);
243 0 : return;
244 : }
245 :
246 : /*
247 : * The Linux driver suggest this will only be true for the HX
248 : * variants. The datasheets disagree.
249 : */
250 0 : if (ddesc->bDeviceClass == 0x02)
251 0 : sc->sc_type_hx = 0;
252 0 : else if (ddesc->bMaxPacketSize == 0x40)
253 0 : sc->sc_type_hx = 1;
254 : else
255 0 : sc->sc_type_hx = 0;
256 :
257 : #ifdef USB_DEBUG
258 : /* print the chip type */
259 : if (sc->sc_type_hx) {
260 : DPRINTF(("uplcom_attach: chiptype 2303X\n"));
261 : } else {
262 : DPRINTF(("uplcom_attach: chiptype 2303\n"));
263 : }
264 : #endif
265 : /* get the (first/common) interface */
266 0 : err = usbd_device2interface_handle(dev, UPLCOM_IFACE_INDEX,
267 0 : &sc->sc_iface);
268 0 : if (err) {
269 0 : printf("\n%s: failed to get interface, err=%s\n",
270 0 : devname, usbd_errstr(err));
271 0 : usbd_deactivate(sc->sc_udev);
272 0 : return;
273 : }
274 :
275 : /* Find the interrupt endpoints */
276 :
277 0 : id = usbd_get_interface_descriptor(sc->sc_iface);
278 0 : sc->sc_iface_number = id->bInterfaceNumber;
279 :
280 0 : for (i = 0; i < id->bNumEndpoints; i++) {
281 0 : ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
282 0 : if (ed == NULL) {
283 0 : printf("%s: no endpoint descriptor for %d\n",
284 : sc->sc_dev.dv_xname, i);
285 0 : usbd_deactivate(sc->sc_udev);
286 0 : return;
287 : }
288 :
289 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
290 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
291 0 : sc->sc_intr_number = ed->bEndpointAddress;
292 0 : sc->sc_isize = UGETW(ed->wMaxPacketSize);
293 0 : }
294 : }
295 :
296 0 : if (sc->sc_intr_number== -1) {
297 0 : printf("%s: Could not find interrupt in\n",
298 : sc->sc_dev.dv_xname);
299 0 : usbd_deactivate(sc->sc_udev);
300 0 : return;
301 : }
302 :
303 : /* keep interface for interrupt */
304 0 : sc->sc_intr_iface = sc->sc_iface;
305 :
306 : /*
307 : * USB-RSAQ1 has two interface
308 : *
309 : * USB-RSAQ1 | USB-RSAQ2
310 : * -----------------+-----------------
311 : * Interface 0 |Interface 0
312 : * Interrupt(0x81) | Interrupt(0x81)
313 : * -----------------+ BulkIN(0x02)
314 : * Interface 1 | BulkOUT(0x83)
315 : * BulkIN(0x02) |
316 : * BulkOUT(0x83) |
317 : */
318 0 : if (cdesc->bNumInterface == 2) {
319 0 : err = usbd_device2interface_handle(dev,
320 : UPLCOM_SECOND_IFACE_INDEX, &sc->sc_iface);
321 0 : if (err) {
322 0 : printf("\n%s: failed to get second interface, err=%s\n",
323 0 : devname, usbd_errstr(err));
324 0 : usbd_deactivate(sc->sc_udev);
325 0 : return;
326 : }
327 : }
328 :
329 : /* Find the bulk{in,out} endpoints */
330 :
331 0 : id = usbd_get_interface_descriptor(sc->sc_iface);
332 0 : sc->sc_iface_number = id->bInterfaceNumber;
333 :
334 0 : for (i = 0; i < id->bNumEndpoints; i++) {
335 0 : ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
336 0 : if (ed == NULL) {
337 0 : printf("%s: no endpoint descriptor for %d\n",
338 : sc->sc_dev.dv_xname, i);
339 0 : usbd_deactivate(sc->sc_udev);
340 0 : return;
341 : }
342 :
343 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
344 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
345 0 : uca.bulkin = ed->bEndpointAddress;
346 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
347 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
348 0 : uca.bulkout = ed->bEndpointAddress;
349 0 : }
350 : }
351 :
352 0 : if (uca.bulkin == -1) {
353 0 : printf("%s: Could not find data bulk in\n",
354 : sc->sc_dev.dv_xname);
355 0 : usbd_deactivate(sc->sc_udev);
356 0 : return;
357 : }
358 :
359 0 : if (uca.bulkout == -1) {
360 0 : printf("%s: Could not find data bulk out\n",
361 : sc->sc_dev.dv_xname);
362 0 : usbd_deactivate(sc->sc_udev);
363 0 : return;
364 : }
365 :
366 0 : sc->sc_dtr = sc->sc_rts = -1;
367 0 : uca.portno = UCOM_UNK_PORTNO;
368 : /* bulkin, bulkout set above */
369 0 : uca.ibufsize = UPLCOMIBUFSIZE;
370 0 : uca.obufsize = UPLCOMOBUFSIZE;
371 0 : uca.ibufsizepad = UPLCOMIBUFSIZE;
372 0 : uca.opkthdrlen = 0;
373 0 : uca.device = dev;
374 0 : uca.iface = sc->sc_iface;
375 0 : uca.methods = &uplcom_methods;
376 0 : uca.arg = sc;
377 0 : uca.info = NULL;
378 :
379 0 : err = uplcom_reset(sc);
380 :
381 0 : if (err) {
382 0 : printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname,
383 0 : usbd_errstr(err));
384 0 : usbd_deactivate(sc->sc_udev);
385 0 : return;
386 : }
387 :
388 : DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
389 : uca.bulkin, uca.bulkout, sc->sc_intr_number ));
390 0 : sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
391 0 : }
392 :
393 : int
394 0 : uplcom_detach(struct device *self, int flags)
395 : {
396 0 : struct uplcom_softc *sc = (struct uplcom_softc *)self;
397 : int rv = 0;
398 :
399 : DPRINTF(("uplcom_detach: sc=%p flags=%d\n", sc, flags));
400 :
401 0 : if (sc->sc_intr_pipe != NULL) {
402 0 : usbd_abort_pipe(sc->sc_intr_pipe);
403 0 : usbd_close_pipe(sc->sc_intr_pipe);
404 0 : free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
405 0 : sc->sc_intr_pipe = NULL;
406 0 : }
407 :
408 0 : if (sc->sc_subdev != NULL) {
409 0 : rv = config_detach(sc->sc_subdev, flags);
410 0 : sc->sc_subdev = NULL;
411 0 : }
412 :
413 0 : return (rv);
414 : }
415 :
416 : usbd_status
417 0 : uplcom_reset(struct uplcom_softc *sc)
418 : {
419 0 : usb_device_request_t req;
420 : usbd_status err;
421 :
422 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
423 0 : req.bRequest = UPLCOM_SET_REQUEST;
424 0 : USETW(req.wValue, 0);
425 0 : USETW(req.wIndex, sc->sc_iface_number);
426 0 : USETW(req.wLength, 0);
427 :
428 0 : err = usbd_do_request(sc->sc_udev, &req, 0);
429 0 : if (err)
430 0 : return (EIO);
431 :
432 0 : return (0);
433 0 : }
434 :
435 : void
436 0 : uplcom_set_line_state(struct uplcom_softc *sc)
437 : {
438 0 : usb_device_request_t req;
439 : int ls;
440 :
441 : /* Make sure we have initialized state for sc_dtr and sc_rts */
442 0 : if (sc->sc_dtr == -1)
443 0 : sc->sc_dtr = 0;
444 0 : if (sc->sc_rts == -1)
445 0 : sc->sc_rts = 0;
446 :
447 0 : ls = (sc->sc_dtr ? UCDC_LINE_DTR : 0) |
448 0 : (sc->sc_rts ? UCDC_LINE_RTS : 0);
449 :
450 0 : req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
451 0 : req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
452 0 : USETW(req.wValue, ls);
453 0 : USETW(req.wIndex, sc->sc_iface_number);
454 0 : USETW(req.wLength, 0);
455 :
456 0 : (void)usbd_do_request(sc->sc_udev, &req, 0);
457 :
458 0 : }
459 :
460 : void
461 0 : uplcom_set(void *addr, int portno, int reg, int onoff)
462 : {
463 0 : struct uplcom_softc *sc = addr;
464 :
465 0 : switch (reg) {
466 : case UCOM_SET_DTR:
467 0 : uplcom_dtr(sc, onoff);
468 0 : break;
469 : case UCOM_SET_RTS:
470 0 : uplcom_rts(sc, onoff);
471 0 : break;
472 : case UCOM_SET_BREAK:
473 0 : uplcom_break(sc, onoff);
474 0 : break;
475 : default:
476 : break;
477 : }
478 0 : }
479 :
480 : void
481 0 : uplcom_dtr(struct uplcom_softc *sc, int onoff)
482 : {
483 :
484 : DPRINTF(("uplcom_dtr: onoff=%d\n", onoff));
485 :
486 0 : if (sc->sc_dtr != -1 && !sc->sc_dtr == !onoff)
487 : return;
488 :
489 0 : sc->sc_dtr = !!onoff;
490 :
491 0 : uplcom_set_line_state(sc);
492 0 : }
493 :
494 : void
495 0 : uplcom_rts(struct uplcom_softc *sc, int onoff)
496 : {
497 : DPRINTF(("uplcom_rts: onoff=%d\n", onoff));
498 :
499 0 : if (sc->sc_rts == -1 && !sc->sc_rts == !onoff)
500 : return;
501 :
502 0 : sc->sc_rts = !!onoff;
503 :
504 0 : uplcom_set_line_state(sc);
505 0 : }
506 :
507 : void
508 0 : uplcom_break(struct uplcom_softc *sc, int onoff)
509 : {
510 0 : usb_device_request_t req;
511 :
512 : DPRINTF(("uplcom_break: onoff=%d\n", onoff));
513 :
514 0 : req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
515 0 : req.bRequest = UCDC_SEND_BREAK;
516 0 : USETW(req.wValue, onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
517 0 : USETW(req.wIndex, sc->sc_iface_number);
518 0 : USETW(req.wLength, 0);
519 :
520 0 : (void)usbd_do_request(sc->sc_udev, &req, 0);
521 0 : }
522 :
523 : usbd_status
524 0 : uplcom_set_crtscts(struct uplcom_softc *sc)
525 : {
526 0 : usb_device_request_t req;
527 : usbd_status err;
528 :
529 : DPRINTF(("uplcom_set_crtscts: on\n"));
530 :
531 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
532 0 : req.bRequest = UPLCOM_SET_REQUEST;
533 0 : USETW(req.wValue, 0);
534 0 : USETW(req.wIndex,
535 : (sc->sc_type_hx ? UPLCOM_HX_SET_CRTSCTS : UPLCOM_SET_CRTSCTS));
536 0 : USETW(req.wLength, 0);
537 :
538 0 : err = usbd_do_request(sc->sc_udev, &req, 0);
539 0 : if (err) {
540 : DPRINTF(("uplcom_set_crtscts: failed, err=%s\n",
541 : usbd_errstr(err)));
542 0 : return (err);
543 : }
544 :
545 0 : return (USBD_NORMAL_COMPLETION);
546 0 : }
547 :
548 : usbd_status
549 0 : uplcom_set_line_coding(struct uplcom_softc *sc,
550 : struct usb_cdc_line_state *state)
551 : {
552 0 : usb_device_request_t req;
553 : usbd_status err;
554 :
555 : DPRINTF(("uplcom_set_line_coding: rate=%d fmt=%d parity=%d bits=%d\n",
556 : UGETDW(state->dwDTERate), state->bCharFormat,
557 : state->bParityType, state->bDataBits));
558 :
559 0 : if (memcmp(state, &sc->sc_line_state, UCDC_LINE_STATE_LENGTH) == 0) {
560 : DPRINTF(("uplcom_set_line_coding: already set\n"));
561 0 : return (USBD_NORMAL_COMPLETION);
562 : }
563 :
564 0 : req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
565 0 : req.bRequest = UCDC_SET_LINE_CODING;
566 0 : USETW(req.wValue, 0);
567 0 : USETW(req.wIndex, sc->sc_iface_number);
568 0 : USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
569 :
570 0 : err = usbd_do_request(sc->sc_udev, &req, state);
571 0 : if (err) {
572 : DPRINTF(("uplcom_set_line_coding: failed, err=%s\n",
573 : usbd_errstr(err)));
574 0 : return (err);
575 : }
576 :
577 0 : sc->sc_line_state = *state;
578 :
579 0 : return (USBD_NORMAL_COMPLETION);
580 0 : }
581 :
582 : int
583 0 : uplcom_param(void *addr, int portno, struct termios *t)
584 : {
585 0 : struct uplcom_softc *sc = addr;
586 : usbd_status err;
587 0 : struct usb_cdc_line_state ls;
588 :
589 : DPRINTF(("uplcom_param: sc=%p\n", sc));
590 :
591 0 : USETDW(ls.dwDTERate, t->c_ospeed);
592 0 : if (ISSET(t->c_cflag, CSTOPB))
593 0 : ls.bCharFormat = UCDC_STOP_BIT_2;
594 : else
595 0 : ls.bCharFormat = UCDC_STOP_BIT_1;
596 0 : if (ISSET(t->c_cflag, PARENB)) {
597 0 : if (ISSET(t->c_cflag, PARODD))
598 0 : ls.bParityType = UCDC_PARITY_ODD;
599 : else
600 0 : ls.bParityType = UCDC_PARITY_EVEN;
601 : } else
602 0 : ls.bParityType = UCDC_PARITY_NONE;
603 0 : switch (ISSET(t->c_cflag, CSIZE)) {
604 : case CS5:
605 0 : ls.bDataBits = 5;
606 0 : break;
607 : case CS6:
608 0 : ls.bDataBits = 6;
609 0 : break;
610 : case CS7:
611 0 : ls.bDataBits = 7;
612 0 : break;
613 : case CS8:
614 0 : ls.bDataBits = 8;
615 0 : break;
616 : }
617 :
618 0 : err = uplcom_set_line_coding(sc, &ls);
619 0 : if (err) {
620 : DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
621 0 : return (EIO);
622 : }
623 :
624 0 : if (ISSET(t->c_cflag, CRTSCTS))
625 0 : uplcom_set_crtscts(sc);
626 :
627 0 : if (sc->sc_rts == -1 || sc->sc_dtr == -1)
628 0 : uplcom_set_line_state(sc);
629 :
630 0 : if (err) {
631 : DPRINTF(("uplcom_param: err=%s\n", usbd_errstr(err)));
632 0 : return (EIO);
633 : }
634 :
635 0 : return (0);
636 0 : }
637 :
638 : int
639 0 : uplcom_open(void *addr, int portno)
640 : {
641 0 : struct uplcom_softc *sc = addr;
642 0 : usb_device_request_t req;
643 : usbd_status uerr;
644 : int err;
645 :
646 0 : if (usbd_is_dying(sc->sc_udev))
647 0 : return (EIO);
648 :
649 : DPRINTF(("uplcom_open: sc=%p\n", sc));
650 :
651 0 : if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
652 0 : sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
653 0 : err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_number,
654 : USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc,
655 0 : sc->sc_intr_buf, sc->sc_isize,
656 : uplcom_intr, USBD_DEFAULT_INTERVAL);
657 0 : if (err) {
658 : DPRINTF(("%s: cannot open interrupt pipe (addr %d)\n",
659 : sc->sc_dev.dv_xname, sc->sc_intr_number));
660 0 : return (EIO);
661 : }
662 : }
663 :
664 0 : if (sc->sc_type_hx == 1) {
665 : /*
666 : * Undocumented (vendor unresponsive) - possibly changes
667 : * flow control semantics. It is needed for HX variant devices.
668 : */
669 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
670 0 : req.bRequest = UPLCOM_SET_REQUEST;
671 0 : USETW(req.wValue, 2);
672 0 : USETW(req.wIndex, 0x44);
673 0 : USETW(req.wLength, 0);
674 :
675 0 : uerr = usbd_do_request(sc->sc_udev, &req, 0);
676 0 : if (uerr)
677 0 : return (EIO);
678 :
679 : /* Reset upstream data pipes */
680 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
681 0 : req.bRequest = UPLCOM_SET_REQUEST;
682 0 : USETW(req.wValue, 8);
683 0 : USETW(req.wIndex, 0);
684 0 : USETW(req.wLength, 0);
685 :
686 0 : uerr = usbd_do_request(sc->sc_udev, &req, 0);
687 0 : if (uerr)
688 0 : return (EIO);
689 :
690 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
691 0 : req.bRequest = UPLCOM_SET_REQUEST;
692 0 : USETW(req.wValue, 9);
693 0 : USETW(req.wIndex, 0);
694 0 : USETW(req.wLength, 0);
695 :
696 0 : uerr = usbd_do_request(sc->sc_udev, &req, 0);
697 0 : if (uerr)
698 0 : return (EIO);
699 : }
700 :
701 0 : return (0);
702 0 : }
703 :
704 : void
705 0 : uplcom_close(void *addr, int portno)
706 : {
707 0 : struct uplcom_softc *sc = addr;
708 : int err;
709 :
710 0 : if (usbd_is_dying(sc->sc_udev))
711 0 : return;
712 :
713 : DPRINTF(("uplcom_close: close\n"));
714 :
715 0 : if (sc->sc_intr_pipe != NULL) {
716 0 : usbd_abort_pipe(sc->sc_intr_pipe);
717 0 : err = usbd_close_pipe(sc->sc_intr_pipe);
718 0 : if (err)
719 0 : printf("%s: close interrupt pipe failed: %s\n",
720 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
721 0 : free(sc->sc_intr_buf, M_USBDEV, sc->sc_isize);
722 0 : sc->sc_intr_pipe = NULL;
723 0 : }
724 0 : }
725 :
726 : void
727 0 : uplcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
728 : {
729 0 : struct uplcom_softc *sc = priv;
730 0 : u_char *buf = sc->sc_intr_buf;
731 : u_char pstatus;
732 :
733 0 : if (usbd_is_dying(sc->sc_udev))
734 0 : return;
735 :
736 0 : if (status != USBD_NORMAL_COMPLETION) {
737 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
738 0 : return;
739 :
740 : DPRINTF(("%s: abnormal status: %s\n", sc->sc_dev.dv_xname,
741 : usbd_errstr(status)));
742 0 : usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
743 0 : return;
744 : }
745 :
746 : DPRINTF(("%s: uplcom status = %02x\n", sc->sc_dev.dv_xname, buf[8]));
747 :
748 0 : sc->sc_lsr = sc->sc_msr = 0;
749 0 : pstatus = buf[8];
750 0 : if (ISSET(pstatus, RSAQ_STATUS_CTS))
751 0 : sc->sc_msr |= UMSR_CTS;
752 : else
753 0 : sc->sc_msr &= ~UMSR_CTS;
754 0 : if (ISSET(pstatus, RSAQ_STATUS_DSR))
755 0 : sc->sc_msr |= UMSR_DSR;
756 : else
757 0 : sc->sc_msr &= ~UMSR_DSR;
758 0 : if (ISSET(pstatus, RSAQ_STATUS_DCD))
759 0 : sc->sc_msr |= UMSR_DCD;
760 : else
761 0 : sc->sc_msr &= ~UMSR_DCD;
762 0 : ucom_status_change((struct ucom_softc *) sc->sc_subdev);
763 0 : }
764 :
765 : void
766 0 : uplcom_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
767 : {
768 0 : struct uplcom_softc *sc = addr;
769 :
770 : DPRINTF(("uplcom_get_status:\n"));
771 :
772 0 : if (lsr != NULL)
773 0 : *lsr = sc->sc_lsr;
774 0 : if (msr != NULL)
775 0 : *msr = sc->sc_msr;
776 0 : }
|