1 /* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */
2
3 #include <sys/cdefs.h>
4 __FBSDID("$FreeBSD$");
5
6 /*-
7 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
8 *
9 * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*-
35 * Copyright (c) 2001 The NetBSD Foundation, Inc.
36 * All rights reserved.
37 *
38 * This code is derived from software contributed to The NetBSD Foundation
39 * by Ichiro FUKUHARA (ichiro@ichiro.org).
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
61 */
62
63 /*
64 * This driver supports several USB-to-RS232 serial adapters driven by
65 * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
66 * bridge chip. The adapters are sold under many different brand
67 * names.
68 *
69 * Datasheets are available at Prolific www site at
70 * http://www.prolific.com.tw. The datasheets don't contain full
71 * programming information for the chip.
72 *
73 * PL-2303HX is probably programmed the same as PL-2303X.
74 *
75 * There are several differences between PL-2303 and PL-2303(H)X.
76 * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
77 * different command for controlling CRTSCTS and needs special
78 * sequence of commands for initialization which aren't also
79 * documented in the datasheet.
80 */
81
82 #include <sys/stdint.h>
83 #include <sys/stddef.h>
84 #include <sys/param.h>
85 #include <sys/queue.h>
86 #include <sys/types.h>
87 #include <sys/systm.h>
88 #include <sys/kernel.h>
89 #include <sys/bus.h>
90 #include <sys/module.h>
91 #include <sys/lock.h>
92 #include <sys/mutex.h>
93 #include <sys/condvar.h>
94 #include <sys/sysctl.h>
95 #include <sys/sx.h>
96 #include <sys/unistd.h>
97 #include <sys/callout.h>
98 #include <sys/malloc.h>
99 #include <sys/priv.h>
100
101 #include <dev/usb/usb.h>
102 #include <dev/usb/usbdi.h>
103 #include <dev/usb/usbdi_util.h>
104 #include <dev/usb/usb_cdc.h>
105 #include "usbdevs.h"
106
107 #define USB_DEBUG_VAR uplcom_debug
108 #include <dev/usb/usb_debug.h>
109 #include <dev/usb/usb_process.h>
110
111 #include <dev/usb/serial/usb_serial.h>
112
113 #ifdef USB_DEBUG
114 static int uplcom_debug = 0;
115
116 static SYSCTL_NODE(_hw_usb, OID_AUTO, uplcom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
117 "USB uplcom");
118 SYSCTL_INT(_hw_usb_uplcom, OID_AUTO, debug, CTLFLAG_RWTUN,
119 &uplcom_debug, 0, "Debug level");
120 #endif
121
122 #define UPLCOM_MODVER 1 /* module version */
123
124 #define UPLCOM_CONFIG_INDEX 0
125 #define UPLCOM_IFACE_INDEX 0
126 #define UPLCOM_SECOND_IFACE_INDEX 1
127
128 #ifndef UPLCOM_INTR_INTERVAL
129 #define UPLCOM_INTR_INTERVAL 0 /* default */
130 #endif
131
132 #define UPLCOM_BULK_BUF_SIZE 1024 /* bytes */
133
134 #define UPLCOM_SET_REQUEST 0x01
135 #define UPLCOM_SET_REQUEST_PL2303HXN 0x80
136 #define UPLCOM_SET_CRTSCTS 0x41
137 #define UPLCOM_SET_CRTSCTS_PL2303X 0x61
138 #define UPLCOM_SET_CRTSCTS_PL2303HXN 0xFA
139 #define UPLCOM_CLEAR_CRTSCTS_PL2303HXN 0xFF
140 #define UPLCOM_CRTSCTS_REG_PL2303HXN 0x0A
141 #define UPLCOM_STATUS_REG_PL2303HX 0x8080
142 #define RSAQ_STATUS_CTS 0x80
143 #define RSAQ_STATUS_OVERRUN_ERROR 0x40
144 #define RSAQ_STATUS_PARITY_ERROR 0x20
145 #define RSAQ_STATUS_FRAME_ERROR 0x10
146 #define RSAQ_STATUS_RING 0x08
147 #define RSAQ_STATUS_BREAK_ERROR 0x04
148 #define RSAQ_STATUS_DSR 0x02
149 #define RSAQ_STATUS_DCD 0x01
150
151 #define TYPE_PL2303 0
152 #define TYPE_PL2303HX 1
153 #define TYPE_PL2303HXD 2
154 #define TYPE_PL2303HXN 3
155
156 #define UPLCOM_STATE_INDEX 8
157
158 enum {
159 UPLCOM_BULK_DT_WR,
160 UPLCOM_BULK_DT_RD,
161 UPLCOM_INTR_DT_RD,
162 UPLCOM_N_TRANSFER,
163 };
164
165 struct uplcom_softc {
166 struct ucom_super_softc sc_super_ucom;
167 struct ucom_softc sc_ucom;
168
169 struct usb_xfer *sc_xfer[UPLCOM_N_TRANSFER];
170 struct usb_device *sc_udev;
171 struct mtx sc_mtx;
172
173 uint16_t sc_line;
174
175 uint8_t sc_lsr; /* local status register */
176 uint8_t sc_msr; /* uplcom status register */
177 uint8_t sc_chiptype; /* type of chip */
178 uint8_t sc_ctrl_iface_no;
179 uint8_t sc_data_iface_no;
180 uint8_t sc_iface_index[2];
181 };
182
183 /* prototypes */
184
185 static usb_error_t uplcom_reset(struct uplcom_softc *, struct usb_device *);
186 static usb_error_t uplcom_pl2303_do(struct usb_device *, uint8_t, uint8_t,
187 uint16_t, uint16_t, uint16_t);
188 static int uplcom_pl2303_init(struct usb_device *, uint8_t);
189 static void uplcom_free(struct ucom_softc *);
190 static void uplcom_cfg_set_dtr(struct ucom_softc *, uint8_t);
191 static void uplcom_cfg_set_rts(struct ucom_softc *, uint8_t);
192 static void uplcom_cfg_set_break(struct ucom_softc *, uint8_t);
193 static int uplcom_pre_param(struct ucom_softc *, struct termios *);
194 static void uplcom_cfg_param(struct ucom_softc *, struct termios *);
195 static void uplcom_start_read(struct ucom_softc *);
196 static void uplcom_stop_read(struct ucom_softc *);
197 static void uplcom_start_write(struct ucom_softc *);
198 static void uplcom_stop_write(struct ucom_softc *);
199 static void uplcom_cfg_get_status(struct ucom_softc *, uint8_t *,
200 uint8_t *);
201 static void uplcom_poll(struct ucom_softc *ucom);
202
203 static device_probe_t uplcom_probe;
204 static device_attach_t uplcom_attach;
205 static device_detach_t uplcom_detach;
206 static void uplcom_free_softc(struct uplcom_softc *);
207
208 static usb_callback_t uplcom_intr_callback;
209 static usb_callback_t uplcom_write_callback;
210 static usb_callback_t uplcom_read_callback;
211
212 static const struct usb_config uplcom_config_data[UPLCOM_N_TRANSFER] = {
213 [UPLCOM_BULK_DT_WR] = {
214 .type = UE_BULK,
215 .endpoint = UE_ADDR_ANY,
216 .direction = UE_DIR_OUT,
217 .bufsize = UPLCOM_BULK_BUF_SIZE,
218 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
219 .callback = &uplcom_write_callback,
220 .if_index = 0,
221 },
222
223 [UPLCOM_BULK_DT_RD] = {
224 .type = UE_BULK,
225 .endpoint = UE_ADDR_ANY,
226 .direction = UE_DIR_IN,
227 .bufsize = UPLCOM_BULK_BUF_SIZE,
228 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
229 .callback = &uplcom_read_callback,
230 .if_index = 0,
231 },
232
233 [UPLCOM_INTR_DT_RD] = {
234 .type = UE_INTERRUPT,
235 .endpoint = UE_ADDR_ANY,
236 .direction = UE_DIR_IN,
237 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
238 .bufsize = 0, /* use wMaxPacketSize */
239 .callback = &uplcom_intr_callback,
240 .if_index = 1,
241 },
242 };
243
244 static struct ucom_callback uplcom_callback = {
245 .ucom_cfg_get_status = &uplcom_cfg_get_status,
246 .ucom_cfg_set_dtr = &uplcom_cfg_set_dtr,
247 .ucom_cfg_set_rts = &uplcom_cfg_set_rts,
248 .ucom_cfg_set_break = &uplcom_cfg_set_break,
249 .ucom_cfg_param = &uplcom_cfg_param,
250 .ucom_pre_param = &uplcom_pre_param,
251 .ucom_start_read = &uplcom_start_read,
252 .ucom_stop_read = &uplcom_stop_read,
253 .ucom_start_write = &uplcom_start_write,
254 .ucom_stop_write = &uplcom_stop_write,
255 .ucom_poll = &uplcom_poll,
256 .ucom_free = &uplcom_free,
257 };
258
259 #define UPLCOM_DEV(v,p) \
260 { USB_VENDOR(USB_VENDOR_##v), USB_PRODUCT(USB_PRODUCT_##v##_##p) }
261
262 static const STRUCT_USB_HOST_ID uplcom_devs[] = {
263 UPLCOM_DEV(ACERP, S81), /* BenQ S81 phone */
264 UPLCOM_DEV(ADLINK, ND6530), /* ADLINK ND-6530 USB-Serial */
265 UPLCOM_DEV(ALCATEL, OT535), /* Alcatel One Touch 535/735 */
266 UPLCOM_DEV(ALCOR, AU9720), /* Alcor AU9720 USB 2.0-RS232 */
267 UPLCOM_DEV(ANCHOR, SERIAL), /* Anchor Serial adapter */
268 UPLCOM_DEV(ATEN, UC232A), /* PLANEX USB-RS232 URS-03 */
269 UPLCOM_DEV(ATEN, UC232B), /* Prolific USB-RS232 Controller D */
270 UPLCOM_DEV(BELKIN, F5U257), /* Belkin F5U257 USB to Serial */
271 UPLCOM_DEV(COREGA, CGUSBRS232R), /* Corega CG-USBRS232R */
272 UPLCOM_DEV(EPSON, CRESSI_EDY), /* Cressi Edy diving computer */
273 UPLCOM_DEV(EPSON, N2ITION3), /* Zeagle N2iTion3 diving computer */
274 UPLCOM_DEV(ELECOM, UCSGT), /* ELECOM UC-SGT Serial Adapter */
275 UPLCOM_DEV(ELECOM, UCSGT0), /* ELECOM UC-SGT Serial Adapter */
276 UPLCOM_DEV(HAL, IMR001), /* HAL Corporation Crossam2+USB */
277 UPLCOM_DEV(HP, LD220), /* HP LD220 POS Display */
278 UPLCOM_DEV(IODATA, USBRSAQ), /* I/O DATA USB-RSAQ */
279 UPLCOM_DEV(IODATA, USBRSAQ5), /* I/O DATA USB-RSAQ5 */
280 UPLCOM_DEV(ITEGNO, WM1080A), /* iTegno WM1080A GSM/GFPRS modem */
281 UPLCOM_DEV(ITEGNO, WM2080A), /* iTegno WM2080A CDMA modem */
282 UPLCOM_DEV(LEADTEK, 9531), /* Leadtek 9531 GPS */
283 UPLCOM_DEV(MICROSOFT, 700WX), /* Microsoft Palm 700WX */
284 UPLCOM_DEV(MOBILEACTION, MA620), /* Mobile Action MA-620 Infrared Adapter */
285 UPLCOM_DEV(NETINDEX, WS002IN), /* Willcom W-S002IN */
286 UPLCOM_DEV(NOKIA2, CA42), /* Nokia CA-42 cable */
287 UPLCOM_DEV(OTI, DKU5), /* OTI DKU-5 cable */
288 UPLCOM_DEV(PANASONIC, TYTP50P6S), /* Panasonic TY-TP50P6-S flat screen */
289 UPLCOM_DEV(PLX, CA42), /* PLX CA-42 clone cable */
290 UPLCOM_DEV(PROLIFIC, ALLTRONIX_GPRS), /* Alltronix ACM003U00 modem */
291 UPLCOM_DEV(PROLIFIC, ALDIGA_AL11U), /* AlDiga AL-11U modem */
292 UPLCOM_DEV(PROLIFIC, DCU11), /* DCU-11 Phone Cable */
293 UPLCOM_DEV(PROLIFIC, HCR331), /* HCR331 Card Reader */
294 UPLCOM_DEV(PROLIFIC, MICROMAX_610U), /* Micromax 610U modem */
295 UPLCOM_DEV(PROLIFIC, MOTOROLA), /* Motorola cable */
296 UPLCOM_DEV(PROLIFIC, PHAROS), /* Prolific Pharos */
297 UPLCOM_DEV(PROLIFIC, PL2303), /* Generic adapter */
298 UPLCOM_DEV(PROLIFIC, PL2303GC), /* Generic adapter (PL2303HXN, type GC) */
299 UPLCOM_DEV(PROLIFIC, PL2303GB), /* Generic adapter (PL2303HXN, type GB) */
300 UPLCOM_DEV(PROLIFIC, PL2303GT), /* Generic adapter (PL2303HXN, type GT) */
301 UPLCOM_DEV(PROLIFIC, PL2303GL), /* Generic adapter (PL2303HXN, type GL) */
302 UPLCOM_DEV(PROLIFIC, PL2303GE), /* Generic adapter (PL2303HXN, type GE) */
303 UPLCOM_DEV(PROLIFIC, PL2303GS), /* Generic adapter (PL2303HXN, type GS) */
304 UPLCOM_DEV(PROLIFIC, RSAQ2), /* I/O DATA USB-RSAQ2 */
305 UPLCOM_DEV(PROLIFIC, RSAQ3), /* I/O DATA USB-RSAQ3 */
306 UPLCOM_DEV(PROLIFIC, UIC_MSR206), /* UIC MSR206 Card Reader */
307 UPLCOM_DEV(PROLIFIC2, PL2303), /* Prolific adapter */
308 UPLCOM_DEV(RADIOSHACK, USBCABLE), /* Radio Shack USB Adapter */
309 UPLCOM_DEV(RATOC, REXUSB60), /* RATOC REX-USB60 */
310 UPLCOM_DEV(SAGEM, USBSERIAL), /* Sagem USB-Serial Controller */
311 UPLCOM_DEV(SAMSUNG, I330), /* Samsung I330 phone cradle */
312 UPLCOM_DEV(SANWA, KB_USB2), /* Sanwa KB-USB2 Multimeter cable */
313 UPLCOM_DEV(SIEMENS3, EF81), /* Siemens EF81 */
314 UPLCOM_DEV(SIEMENS3, SX1), /* Siemens SX1 */
315 UPLCOM_DEV(SIEMENS3, X65), /* Siemens X65 */
316 UPLCOM_DEV(SIEMENS3, X75), /* Siemens X75 */
317 UPLCOM_DEV(SITECOM, SERIAL), /* Sitecom USB to Serial */
318 UPLCOM_DEV(SMART, PL2303), /* SMART Technologies USB to Serial */
319 UPLCOM_DEV(SONY, QN3), /* Sony QN3 phone cable */
320 UPLCOM_DEV(SONYERICSSON, DATAPILOT), /* Sony Ericsson Datapilot */
321 UPLCOM_DEV(SONYERICSSON, DCU10), /* Sony Ericsson DCU-10 Cable */
322 UPLCOM_DEV(SOURCENEXT, KEIKAI8), /* SOURCENEXT KeikaiDenwa 8 */
323 UPLCOM_DEV(SOURCENEXT, KEIKAI8_CHG), /* SOURCENEXT KeikaiDenwa 8 with charger */
324 UPLCOM_DEV(SPEEDDRAGON, MS3303H), /* Speed Dragon USB-Serial */
325 UPLCOM_DEV(SYNTECH, CPT8001C), /* Syntech CPT-8001C Barcode scanner */
326 UPLCOM_DEV(TDK, UHA6400), /* TDK USB-PHS Adapter UHA6400 */
327 UPLCOM_DEV(TDK, UPA9664), /* TDK USB-PHS Adapter UPA9664 */
328 UPLCOM_DEV(TRIPPLITE, U209), /* Tripp-Lite U209-000-R USB to Serial */
329 UPLCOM_DEV(YCCABLE, PL2303), /* YC Cable USB-Serial */
330 };
331 #undef UPLCOM_DEV
332
333 static device_method_t uplcom_methods[] = {
334 DEVMETHOD(device_probe, uplcom_probe),
335 DEVMETHOD(device_attach, uplcom_attach),
336 DEVMETHOD(device_detach, uplcom_detach),
337 DEVMETHOD_END
338 };
339
340 static driver_t uplcom_driver = {
341 .name = "uplcom",
342 .methods = uplcom_methods,
343 .size = sizeof(struct uplcom_softc),
344 };
345
346 DRIVER_MODULE(uplcom, uhub, uplcom_driver, NULL, NULL);
347 MODULE_DEPEND(uplcom, ucom, 1, 1, 1);
348 MODULE_DEPEND(uplcom, usb, 1, 1, 1);
349 MODULE_VERSION(uplcom, UPLCOM_MODVER);
350 USB_PNP_HOST_INFO(uplcom_devs);
351
352 static int
353 uplcom_probe(device_t dev)
354 {
355 struct usb_attach_arg *uaa = device_get_ivars(dev);
356
357 DPRINTFN(11, "\n");
358
359 if (uaa->usb_mode != USB_MODE_HOST) {
360 return (ENXIO);
361 }
362 if (uaa->info.bConfigIndex != UPLCOM_CONFIG_INDEX) {
363 return (ENXIO);
364 }
365 if (uaa->info.bIfaceIndex != UPLCOM_IFACE_INDEX) {
366 return (ENXIO);
367 }
368 return (usbd_lookup_id_by_uaa(uplcom_devs, sizeof(uplcom_devs), uaa));
369 }
370
371 static int
372 uplcom_attach(device_t dev)
373 {
374 struct usb_attach_arg *uaa = device_get_ivars(dev);
375 struct uplcom_softc *sc = device_get_softc(dev);
376 struct usb_interface *iface;
377 struct usb_interface_descriptor *id;
378 struct usb_device_descriptor *dd;
379 int error;
380
381 struct usb_device_request req;
382 usb_error_t err;
383 uint8_t buf[4];
384
385 DPRINTFN(11, "\n");
386
387 device_set_usb_desc(dev);
388 mtx_init(&sc->sc_mtx, "uplcom", NULL, MTX_DEF);
389 ucom_ref(&sc->sc_super_ucom);
390
391 DPRINTF("sc = %p\n", sc);
392
393 sc->sc_udev = uaa->device;
394
395 dd = usbd_get_device_descriptor(sc->sc_udev);
396
397 switch (UGETW(dd->bcdDevice)) {
398 case 0x0300:
399 sc->sc_chiptype = TYPE_PL2303HX;
400 /* or TA, that is HX with external crystal */
401 break;
402 case 0x0400:
403 sc->sc_chiptype = TYPE_PL2303HXD;
404 /* or EA, that is HXD with ESD protection */
405 /* or RA, that has internal voltage level converter that works only up to 1Mbaud (!) */
406 break;
407 case 0x0500:
408 sc->sc_chiptype = TYPE_PL2303HXD;
409 /* in fact it's TB, that is HXD with external crystal */
410 break;
411 default:
412 /* NOTE: I have no info about the bcdDevice for the base PL2303 (up to 1.2Mbaud,
413 only fixed rates) and for PL2303SA (8-pin chip, up to 115200 baud */
414 /* Determine the chip type. This algorithm is taken from Linux. */
415 if (dd->bDeviceClass == 0x02)
416 sc->sc_chiptype = TYPE_PL2303;
417 else if (dd->bMaxPacketSize == 0x40)
418 sc->sc_chiptype = TYPE_PL2303HX;
419 else
420 sc->sc_chiptype = TYPE_PL2303;
421 break;
422 }
423
424 /*
425 * The new chip revision PL2303HXN is only compatible with the new
426 * UPLCOM_SET_REQUEST_PL2303HXN command. Issuing the old command
427 * UPLCOM_SET_REQUEST to the new chip raises an error. Thus, PL2303HX
428 * and PL2303HXN can be distinguished by issuing an old-style request
429 * (on a status register) to the new chip and checking the error.
430 */
431 if (sc->sc_chiptype == TYPE_PL2303HX) {
432 req.bmRequestType = UT_READ_VENDOR_DEVICE;
433 req.bRequest = UPLCOM_SET_REQUEST;
434 USETW(req.wValue, UPLCOM_STATUS_REG_PL2303HX);
435 req.wIndex[0] = sc->sc_data_iface_no;
436 req.wIndex[1] = 0;
437 USETW(req.wLength, 1);
438 err = usbd_do_request(sc->sc_udev, NULL, &req, buf);
439 if (err)
440 sc->sc_chiptype = TYPE_PL2303HXN;
441 }
442
443 switch (sc->sc_chiptype) {
444 case TYPE_PL2303:
445 DPRINTF("chiptype: 2303\n");
446 break;
447 case TYPE_PL2303HX:
448 DPRINTF("chiptype: 2303HX/TA\n");
449 break;
450 case TYPE_PL2303HXN:
451 DPRINTF("chiptype: 2303HXN\n");
452 break;
453 case TYPE_PL2303HXD:
454 DPRINTF("chiptype: 2303HXD/TB/RA/EA\n");
455 break;
456 default:
457 DPRINTF("chiptype: unknown %d\n", sc->sc_chiptype);
458 break;
459 }
460
461 /*
462 * USB-RSAQ1 has two interface
463 *
464 * USB-RSAQ1 | USB-RSAQ2
465 * -----------------+-----------------
466 * Interface 0 |Interface 0
467 * Interrupt(0x81) | Interrupt(0x81)
468 * -----------------+ BulkIN(0x02)
469 * Interface 1 | BulkOUT(0x83)
470 * BulkIN(0x02) |
471 * BulkOUT(0x83) |
472 */
473
474 sc->sc_ctrl_iface_no = uaa->info.bIfaceNum;
475 sc->sc_iface_index[1] = UPLCOM_IFACE_INDEX;
476
477 iface = usbd_get_iface(uaa->device, UPLCOM_SECOND_IFACE_INDEX);
478 if (iface) {
479 id = usbd_get_interface_descriptor(iface);
480 if (id == NULL) {
481 device_printf(dev, "no interface descriptor (2)\n");
482 goto detach;
483 }
484 sc->sc_data_iface_no = id->bInterfaceNumber;
485 sc->sc_iface_index[0] = UPLCOM_SECOND_IFACE_INDEX;
486 usbd_set_parent_iface(uaa->device,
487 UPLCOM_SECOND_IFACE_INDEX, uaa->info.bIfaceIndex);
488 } else {
489 sc->sc_data_iface_no = sc->sc_ctrl_iface_no;
490 sc->sc_iface_index[0] = UPLCOM_IFACE_INDEX;
491 }
492
493 error = usbd_transfer_setup(uaa->device,
494 sc->sc_iface_index, sc->sc_xfer, uplcom_config_data,
495 UPLCOM_N_TRANSFER, sc, &sc->sc_mtx);
496 if (error) {
497 DPRINTF("one or more missing USB endpoints, "
498 "error=%s\n", usbd_errstr(error));
499 goto detach;
500 }
501 error = uplcom_reset(sc, uaa->device);
502 if (error) {
503 device_printf(dev, "reset failed, error=%s\n",
504 usbd_errstr(error));
505 goto detach;
506 }
507
508 if (sc->sc_chiptype == TYPE_PL2303) {
509 /* HX variants seem to lock up after a clear stall request. */
510 mtx_lock(&sc->sc_mtx);
511 usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
512 usbd_xfer_set_stall(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
513 mtx_unlock(&sc->sc_mtx);
514 } else if (sc->sc_chiptype == TYPE_PL2303HX ||
515 sc->sc_chiptype == TYPE_PL2303HXD) {
516 /* reset upstream data pipes */
517 if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
518 UPLCOM_SET_REQUEST, 8, 0, 0) ||
519 uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
520 UPLCOM_SET_REQUEST, 9, 0, 0)) {
521 goto detach;
522 }
523 } else if (sc->sc_chiptype == TYPE_PL2303HXN) {
524 /* reset upstream data pipes */
525 if (uplcom_pl2303_do(sc->sc_udev, UT_WRITE_VENDOR_DEVICE,
526 UPLCOM_SET_REQUEST_PL2303HXN, 0x07, 0x03, 0)) {
527 goto detach;
528 }
529 }
530
531 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc,
532 &uplcom_callback, &sc->sc_mtx);
533 if (error) {
534 goto detach;
535 }
536 /*
537 * do the initialization during attach so that the system does not
538 * sleep during open:
539 */
540 if (uplcom_pl2303_init(uaa->device, sc->sc_chiptype)) {
541 device_printf(dev, "init failed\n");
542 goto detach;
543 }
544 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
545
546 return (0);
547
548 detach:
549 uplcom_detach(dev);
550 return (ENXIO);
551 }
552
553 static int
554 uplcom_detach(device_t dev)
555 {
556 struct uplcom_softc *sc = device_get_softc(dev);
557
558 DPRINTF("sc=%p\n", sc);
559
560 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom);
561 usbd_transfer_unsetup(sc->sc_xfer, UPLCOM_N_TRANSFER);
562
563 device_claim_softc(dev);
564
565 uplcom_free_softc(sc);
566
567 return (0);
568 }
569
570 UCOM_UNLOAD_DRAIN(uplcom);
571
572 static void
573 uplcom_free_softc(struct uplcom_softc *sc)
574 {
575 if (ucom_unref(&sc->sc_super_ucom)) {
576 mtx_destroy(&sc->sc_mtx);
577 device_free_softc(sc);
578 }
579 }
580
581 static void
582 uplcom_free(struct ucom_softc *ucom)
583 {
584 uplcom_free_softc(ucom->sc_parent);
585 }
586
587 static usb_error_t
588 uplcom_reset(struct uplcom_softc *sc, struct usb_device *udev)
589 {
590 struct usb_device_request req;
591
592 if (sc->sc_chiptype == TYPE_PL2303HXN) {
593 /* PL2303HXN doesn't need this reset sequence */
594 return (0);
595 }
596
597 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
598 req.bRequest = UPLCOM_SET_REQUEST;
599 USETW(req.wValue, 0);
600 req.wIndex[0] = sc->sc_data_iface_no;
601 req.wIndex[1] = 0;
602 USETW(req.wLength, 0);
603
604 return (usbd_do_request(udev, NULL, &req, NULL));
605 }
606
607 static usb_error_t
608 uplcom_pl2303_do(struct usb_device *udev, uint8_t req_type, uint8_t request,
609 uint16_t value, uint16_t index, uint16_t length)
610 {
611 struct usb_device_request req;
612 usb_error_t err;
613 uint8_t buf[4];
614
615 req.bmRequestType = req_type;
616 req.bRequest = request;
617 USETW(req.wValue, value);
618 USETW(req.wIndex, index);
619 USETW(req.wLength, length);
620
621 err = usbd_do_request(udev, NULL, &req, buf);
622 if (err) {
623 DPRINTF("error=%s\n", usbd_errstr(err));
624 return (1);
625 }
626 return (0);
627 }
628
629 static int
630 uplcom_pl2303_init(struct usb_device *udev, uint8_t chiptype)
631 {
632 int err;
633
634 if (chiptype == TYPE_PL2303HXN) {
635 /* PL2303HXN doesn't need this initialization sequence */
636 return (0);
637 }
638
639 if (uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
640 || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 0, 0)
641 || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
642 || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
643 || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
644 || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x0404, 1, 0)
645 || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8484, 0, 1)
646 || uplcom_pl2303_do(udev, UT_READ_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0x8383, 0, 1)
647 || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 0, 1, 0)
648 || uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 1, 0, 0))
649 return (EIO);
650
651 if (chiptype != TYPE_PL2303)
652 err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x44, 0);
653 else
654 err = uplcom_pl2303_do(udev, UT_WRITE_VENDOR_DEVICE, UPLCOM_SET_REQUEST, 2, 0x24, 0);
655 if (err)
656 return (EIO);
657
658 return (0);
659 }
660
661 static void
662 uplcom_cfg_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
663 {
664 struct uplcom_softc *sc = ucom->sc_parent;
665 struct usb_device_request req;
666
667 DPRINTF("onoff = %d\n", onoff);
668
669 if (onoff)
670 sc->sc_line |= UCDC_LINE_DTR;
671 else
672 sc->sc_line &= ~UCDC_LINE_DTR;
673
674 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
675 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
676 USETW(req.wValue, sc->sc_line);
677 req.wIndex[0] = sc->sc_data_iface_no;
678 req.wIndex[1] = 0;
679 USETW(req.wLength, 0);
680
681 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
682 &req, NULL, 0, 1000);
683 }
684
685 static void
686 uplcom_cfg_set_rts(struct ucom_softc *ucom, uint8_t onoff)
687 {
688 struct uplcom_softc *sc = ucom->sc_parent;
689 struct usb_device_request req;
690
691 DPRINTF("onoff = %d\n", onoff);
692
693 if (onoff)
694 sc->sc_line |= UCDC_LINE_RTS;
695 else
696 sc->sc_line &= ~UCDC_LINE_RTS;
697
698 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
699 req.bRequest = UCDC_SET_CONTROL_LINE_STATE;
700 USETW(req.wValue, sc->sc_line);
701 req.wIndex[0] = sc->sc_data_iface_no;
702 req.wIndex[1] = 0;
703 USETW(req.wLength, 0);
704
705 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
706 &req, NULL, 0, 1000);
707 }
708
709 static void
710 uplcom_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
711 {
712 struct uplcom_softc *sc = ucom->sc_parent;
713 struct usb_device_request req;
714 uint16_t temp;
715
716 DPRINTF("onoff = %d\n", onoff);
717
718 temp = (onoff ? UCDC_BREAK_ON : UCDC_BREAK_OFF);
719
720 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
721 req.bRequest = UCDC_SEND_BREAK;
722 USETW(req.wValue, temp);
723 req.wIndex[0] = sc->sc_data_iface_no;
724 req.wIndex[1] = 0;
725 USETW(req.wLength, 0);
726
727 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
728 &req, NULL, 0, 1000);
729 }
730
731 /*
732 * NOTE: These baud rates are officially supported, they can be written
733 * directly into dwDTERate register.
734 *
735 * Free baudrate setting is not supported by the base PL2303, and on
736 * other models it requires writing a divisor value to dwDTERate instead
737 * of the raw baudrate. The formula for divisor calculation is not published
738 * by the vendor, so it is speculative, though the official product homepage
739 * refers to the Linux module source as a reference implementation.
740 */
741 static const uint32_t uplcom_rates[] = {
742 /*
743 * Basic 'standard' speed rates, supported by all models
744 * NOTE: 900 and 56000 actually works as well
745 */
746 75, 150, 300, 600, 900, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
747 19200, 28800, 38400, 56000, 57600, 115200,
748 /*
749 * Advanced speed rates up to 6Mbs, supported by HX/TA and HXD/TB/EA/RA
750 * NOTE: regardless of the spec, 256000 does not work
751 */
752 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400,
753 806400, 921600, 1228800, 2457600, 3000000, 6000000,
754 /*
755 * Advanced speed rates up to 12, supported by HXD/TB/EA/RA
756 */
757 12000000
758 };
759
760 #define N_UPLCOM_RATES nitems(uplcom_rates)
761
762 static int
763 uplcom_baud_supported(unsigned speed)
764 {
765 int i;
766 for (i = 0; i < N_UPLCOM_RATES; i++) {
767 if (uplcom_rates[i] == speed)
768 return 1;
769 }
770 return 0;
771 }
772
773 static int
774 uplcom_pre_param(struct ucom_softc *ucom, struct termios *t)
775 {
776 struct uplcom_softc *sc = ucom->sc_parent;
777
778 DPRINTF("\n");
779
780 /**
781 * Check requested baud rate.
782 *
783 * The PL2303 can only set specific baud rates, up to 1228800 baud.
784 * The PL2303HX can set any baud rate up to 6Mb.
785 * The PL2303HX rev. D and PL2303HXN can set any baud rate up to 12Mb.
786 *
787 */
788
789 /* accept raw divisor data, if someone wants to do the math in user domain */
790 if (t->c_ospeed & 0x80000000)
791 return 0;
792 switch (sc->sc_chiptype) {
793 case TYPE_PL2303HXN:
794 if (t->c_ospeed <= 12000000)
795 return (0);
796 break;
797 case TYPE_PL2303HXD:
798 if (t->c_ospeed <= 12000000)
799 return (0);
800 break;
801 case TYPE_PL2303HX:
802 if (t->c_ospeed <= 6000000)
803 return (0);
804 break;
805 default:
806 if (uplcom_baud_supported(t->c_ospeed))
807 return (0);
808 break;
809 }
810
811 DPRINTF("uplcom_param: bad baud rate (%d)\n", t->c_ospeed);
812 return (EIO);
813 }
814
815 static unsigned
816 uplcom_encode_baud_rate_divisor(uint8_t *buf, unsigned baud)
817 {
818 unsigned baseline, mantissa, exponent;
819
820 /* Determine the baud rate divisor. This algorithm is taken from Linux. */
821 /*
822 * Apparently the formula is:
823 * baudrate = baseline / (mantissa * 4^exponent)
824 * where
825 * mantissa = buf[8:0]
826 * exponent = buf[11:9]
827 */
828 if (baud == 0)
829 baud = 1;
830 baseline = 383385600;
831 mantissa = baseline / baud;
832 if (mantissa == 0)
833 mantissa = 1;
834 exponent = 0;
835 while (mantissa >= 512) {
836 if (exponent < 7) {
837 mantissa >>= 2; /* divide by 4 */
838 exponent++;
839 } else {
840 /* Exponent is maxed. Trim mantissa and leave. This gives approx. 45.8 baud */
841 mantissa = 511;
842 break;
843 }
844 }
845
846 buf[3] = 0x80;
847 buf[2] = 0;
848 buf[1] = exponent << 1 | mantissa >> 8;
849 buf[0] = mantissa & 0xff;
850
851 /* Calculate and return the exact baud rate. */
852 baud = (baseline / mantissa) >> (exponent << 1);
853 DPRINTF("real baud rate will be %u\n", baud);
854
855 return baud;
856 }
857 static void
858 uplcom_cfg_param(struct ucom_softc *ucom, struct termios *t)
859 {
860 struct uplcom_softc *sc = ucom->sc_parent;
861 struct usb_cdc_line_state ls;
862 struct usb_device_request req;
863
864 DPRINTF("sc = %p\n", sc);
865
866 memset(&ls, 0, sizeof(ls));
867
868 /*
869 * NOTE: If unsupported baud rates are set directly, the PL2303* uses 9600 baud.
870 */
871 if ((t->c_ospeed & 0x80000000) || uplcom_baud_supported(t->c_ospeed))
872 USETDW(ls.dwDTERate, t->c_ospeed);
873 else
874 t->c_ospeed = uplcom_encode_baud_rate_divisor((uint8_t*)&ls.dwDTERate, t->c_ospeed);
875
876 if (t->c_cflag & CSTOPB) {
877 if ((t->c_cflag & CSIZE) == CS5) {
878 /*
879 * NOTE: Comply with "real" UARTs / RS232:
880 * use 1.5 instead of 2 stop bits with 5 data bits
881 */
882 ls.bCharFormat = UCDC_STOP_BIT_1_5;
883 } else {
884 ls.bCharFormat = UCDC_STOP_BIT_2;
885 }
886 } else {
887 ls.bCharFormat = UCDC_STOP_BIT_1;
888 }
889
890 if (t->c_cflag & PARENB) {
891 if (t->c_cflag & PARODD) {
892 ls.bParityType = UCDC_PARITY_ODD;
893 } else {
894 ls.bParityType = UCDC_PARITY_EVEN;
895 }
896 } else {
897 ls.bParityType = UCDC_PARITY_NONE;
898 }
899
900 switch (t->c_cflag & CSIZE) {
901 case CS5:
902 ls.bDataBits = 5;
903 break;
904 case CS6:
905 ls.bDataBits = 6;
906 break;
907 case CS7:
908 ls.bDataBits = 7;
909 break;
910 case CS8:
911 ls.bDataBits = 8;
912 break;
913 }
914
915 DPRINTF("rate=0x%08x fmt=%d parity=%d bits=%d\n",
916 UGETDW(ls.dwDTERate), ls.bCharFormat,
917 ls.bParityType, ls.bDataBits);
918
919 req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
920 req.bRequest = UCDC_SET_LINE_CODING;
921 USETW(req.wValue, 0);
922 req.wIndex[0] = sc->sc_data_iface_no;
923 req.wIndex[1] = 0;
924 USETW(req.wLength, UCDC_LINE_STATE_LENGTH);
925
926 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
927 &req, &ls, 0, 1000);
928
929 if (t->c_cflag & CRTSCTS) {
930 DPRINTF("crtscts = on\n");
931
932 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
933 if (sc->sc_chiptype == TYPE_PL2303HXN) {
934 req.bRequest = UPLCOM_SET_REQUEST_PL2303HXN;
935 USETW(req.wValue, UPLCOM_CRTSCTS_REG_PL2303HXN);
936 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303HXN);
937 } else {
938 req.bRequest = UPLCOM_SET_REQUEST;
939 USETW(req.wValue, 0);
940 if (sc->sc_chiptype != TYPE_PL2303)
941 USETW(req.wIndex, UPLCOM_SET_CRTSCTS_PL2303X);
942 else
943 USETW(req.wIndex, UPLCOM_SET_CRTSCTS);
944 }
945 USETW(req.wLength, 0);
946
947 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
948 &req, NULL, 0, 1000);
949 } else {
950 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
951 if (sc->sc_chiptype == TYPE_PL2303HXN) {
952 req.bRequest = UPLCOM_SET_REQUEST_PL2303HXN;
953 USETW(req.wValue, UPLCOM_CRTSCTS_REG_PL2303HXN);
954 USETW(req.wIndex, UPLCOM_CLEAR_CRTSCTS_PL2303HXN);
955 }
956 else {
957 req.bRequest = UPLCOM_SET_REQUEST;
958 USETW(req.wValue, 0);
959 USETW(req.wIndex, 0);
960 }
961 USETW(req.wLength, 0);
962 ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
963 &req, NULL, 0, 1000);
964 }
965 }
966
967 static void
968 uplcom_start_read(struct ucom_softc *ucom)
969 {
970 struct uplcom_softc *sc = ucom->sc_parent;
971
972 /* start interrupt endpoint */
973 usbd_transfer_start(sc->sc_xfer[UPLCOM_INTR_DT_RD]);
974
975 /* start read endpoint */
976 usbd_transfer_start(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
977 }
978
979 static void
980 uplcom_stop_read(struct ucom_softc *ucom)
981 {
982 struct uplcom_softc *sc = ucom->sc_parent;
983
984 /* stop interrupt endpoint */
985 usbd_transfer_stop(sc->sc_xfer[UPLCOM_INTR_DT_RD]);
986
987 /* stop read endpoint */
988 usbd_transfer_stop(sc->sc_xfer[UPLCOM_BULK_DT_RD]);
989 }
990
991 static void
992 uplcom_start_write(struct ucom_softc *ucom)
993 {
994 struct uplcom_softc *sc = ucom->sc_parent;
995
996 usbd_transfer_start(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
997 }
998
999 static void
1000 uplcom_stop_write(struct ucom_softc *ucom)
1001 {
1002 struct uplcom_softc *sc = ucom->sc_parent;
1003
1004 usbd_transfer_stop(sc->sc_xfer[UPLCOM_BULK_DT_WR]);
1005 }
1006
1007 static void
1008 uplcom_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
1009 {
1010 struct uplcom_softc *sc = ucom->sc_parent;
1011
1012 DPRINTF("\n");
1013
1014 *lsr = sc->sc_lsr;
1015 *msr = sc->sc_msr;
1016 }
1017
1018 static void
1019 uplcom_intr_callback(struct usb_xfer *xfer, usb_error_t error)
1020 {
1021 struct uplcom_softc *sc = usbd_xfer_softc(xfer);
1022 struct usb_page_cache *pc;
1023 uint8_t buf[9];
1024 int actlen;
1025
1026 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1027
1028 switch (USB_GET_STATE(xfer)) {
1029 case USB_ST_TRANSFERRED:
1030
1031 DPRINTF("actlen = %u\n", actlen);
1032
1033 if (actlen >= 9) {
1034 pc = usbd_xfer_get_frame(xfer, 0);
1035 usbd_copy_out(pc, 0, buf, sizeof(buf));
1036
1037 DPRINTF("status = 0x%02x\n", buf[UPLCOM_STATE_INDEX]);
1038
1039 sc->sc_lsr = 0;
1040 sc->sc_msr = 0;
1041
1042 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_CTS) {
1043 sc->sc_msr |= SER_CTS;
1044 }
1045 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_OVERRUN_ERROR) {
1046 sc->sc_lsr |= ULSR_OE;
1047 }
1048 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_PARITY_ERROR) {
1049 sc->sc_lsr |= ULSR_PE;
1050 }
1051 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_FRAME_ERROR) {
1052 sc->sc_lsr |= ULSR_FE;
1053 }
1054 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_RING) {
1055 sc->sc_msr |= SER_RI;
1056 }
1057 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_BREAK_ERROR) {
1058 sc->sc_lsr |= ULSR_BI;
1059 }
1060 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DSR) {
1061 sc->sc_msr |= SER_DSR;
1062 }
1063 if (buf[UPLCOM_STATE_INDEX] & RSAQ_STATUS_DCD) {
1064 sc->sc_msr |= SER_DCD;
1065 }
1066 ucom_status_change(&sc->sc_ucom);
1067 }
1068 case USB_ST_SETUP:
1069 tr_setup:
1070 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1071 usbd_transfer_submit(xfer);
1072 return;
1073
1074 default: /* Error */
1075 if (error != USB_ERR_CANCELLED) {
1076 /* try to clear stall first */
1077 usbd_xfer_set_stall(xfer);
1078 goto tr_setup;
1079 }
1080 return;
1081 }
1082 }
1083
1084 static void
1085 uplcom_write_callback(struct usb_xfer *xfer, usb_error_t error)
1086 {
1087 struct uplcom_softc *sc = usbd_xfer_softc(xfer);
1088 struct usb_page_cache *pc;
1089 uint32_t actlen;
1090
1091 switch (USB_GET_STATE(xfer)) {
1092 case USB_ST_SETUP:
1093 case USB_ST_TRANSFERRED:
1094 tr_setup:
1095 pc = usbd_xfer_get_frame(xfer, 0);
1096 if (ucom_get_data(&sc->sc_ucom, pc, 0,
1097 UPLCOM_BULK_BUF_SIZE, &actlen)) {
1098 DPRINTF("actlen = %d\n", actlen);
1099
1100 usbd_xfer_set_frame_len(xfer, 0, actlen);
1101 usbd_transfer_submit(xfer);
1102 }
1103 return;
1104
1105 default: /* Error */
1106 if (error != USB_ERR_CANCELLED) {
1107 /* try to clear stall first */
1108 usbd_xfer_set_stall(xfer);
1109 goto tr_setup;
1110 }
1111 return;
1112 }
1113 }
1114
1115 static void
1116 uplcom_read_callback(struct usb_xfer *xfer, usb_error_t error)
1117 {
1118 struct uplcom_softc *sc = usbd_xfer_softc(xfer);
1119 struct usb_page_cache *pc;
1120 int actlen;
1121
1122 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
1123
1124 switch (USB_GET_STATE(xfer)) {
1125 case USB_ST_TRANSFERRED:
1126 pc = usbd_xfer_get_frame(xfer, 0);
1127 ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
1128
1129 case USB_ST_SETUP:
1130 tr_setup:
1131 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
1132 usbd_transfer_submit(xfer);
1133 return;
1134
1135 default: /* Error */
1136 if (error != USB_ERR_CANCELLED) {
1137 /* try to clear stall first */
1138 usbd_xfer_set_stall(xfer);
1139 goto tr_setup;
1140 }
1141 return;
1142 }
1143 }
1144
1145 static void
1146 uplcom_poll(struct ucom_softc *ucom)
1147 {
1148 struct uplcom_softc *sc = ucom->sc_parent;
1149 usbd_transfer_poll(sc->sc_xfer, UPLCOM_N_TRANSFER);
1150 }
Cache object: eb9cda1340e0f880bececf4bd5a697ed
|