1 /* $NetBSD: uplcom.c,v 1.21 2001/11/13 06:24:56 lukem Exp $ */
4 * Copyright (c) 2001-2003, 2005 Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Copyright (c) 2001 The NetBSD Foundation, Inc.
31 * All rights reserved.
33 * This code is derived from software contributed to The NetBSD Foundation
34 * by Ichiro FUKUHARA (ichiro@ichiro.org).
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
45 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 * POSSIBILITY OF SUCH DAMAGE.
59 * This driver supports several USB-to-RS232 serial adapters driven by
60 * Prolific PL-2303, PL-2303X and probably PL-2303HX USB-to-RS232
61 * bridge chip. The adapters are sold under many different brand
64 * Datasheets are available at Prolific www site at
65 * http://www.prolific.com.tw. The datasheets don't contain full
66 * programming information for the chip.
68 * PL-2303HX is probably programmed the same as PL-2303X.
70 * There are several differences between PL-2303 and PL-2303(H)X.
71 * PL-2303(H)X can do higher bitrate in bulk mode, has _probably_
72 * different command for controlling CRTSCTS and needs special
73 * sequence of commands for initialization which aren't also
74 * documented in the datasheet.
77 #include <sys/stdint.h>
78 #include <sys/param.h>
79 #include <sys/queue.h>
80 #include <sys/types.h>
81 #include <sys/systm.h>
82 #include <sys/kernel.h>
84 #include <sys/module.h>
86 #include <sys/condvar.h>
87 #include <sys/sysctl.h>
88 #include <sys/unistd.h>
89 #include <sys/callout.h>
90 #include <sys/malloc.h>
92 #include <sys/serial.h>
94 #include <bus/u4b/usb.h>
95 #include <bus/u4b/usbdi.h>
96 #include <bus/u4b/usbdi_util.h>
97 #include <bus/u4b/usb_cdc.h>
100 #define USB_DEBUG_VAR uplcom_debug
101 #include <bus/u4b/usb_debug.h>
102 #include <bus/u4b/usb_process.h>
104 #include <bus/u4b/serial/usb_serial.h>
107 static int uplcom_debug
= 0;
109 static SYSCTL_NODE(_hw_usb
, OID_AUTO
, uplcom
, CTLFLAG_RW
, 0, "USB uplcom");
110 SYSCTL_INT(_hw_usb_uplcom
, OID_AUTO
, debug
, CTLFLAG_RW
,
111 &uplcom_debug
, 0, "Debug level");
114 #define UPLCOM_MODVER 1 /* module version */
116 #define UPLCOM_CONFIG_INDEX 0
117 #define UPLCOM_IFACE_INDEX 0
118 #define UPLCOM_SECOND_IFACE_INDEX 1
120 #ifndef UPLCOM_INTR_INTERVAL
121 #define UPLCOM_INTR_INTERVAL 0 /* default */
124 #define UPLCOM_BULK_BUF_SIZE 1024 /* bytes */
126 #define UPLCOM_SET_REQUEST 0x01
127 #define UPLCOM_SET_CRTSCTS 0x41
128 #define UPLCOM_SET_CRTSCTS_PL2303X 0x61
129 #define RSAQ_STATUS_CTS 0x80
130 #define RSAQ_STATUS_DSR 0x02
131 #define RSAQ_STATUS_DCD 0x01
133 #define TYPE_PL2303 0
134 #define TYPE_PL2303HX 1
143 struct uplcom_softc
{
144 struct ucom_super_softc sc_super_ucom
;
145 struct ucom_softc sc_ucom
;
147 struct usb_xfer
*sc_xfer
[UPLCOM_N_TRANSFER
];
148 struct usb_device
*sc_udev
;
153 uint8_t sc_lsr
; /* local status register */
154 uint8_t sc_msr
; /* uplcom status register */
155 uint8_t sc_chiptype
; /* type of chip */
156 uint8_t sc_ctrl_iface_no
;
157 uint8_t sc_data_iface_no
;
158 uint8_t sc_iface_index
[2];
163 static usb_error_t
uplcom_reset(struct uplcom_softc
*, struct usb_device
*);
164 static usb_error_t
uplcom_pl2303_do(struct usb_device
*, int8_t, uint8_t,
165 uint16_t, uint16_t, uint16_t);
166 static int uplcom_pl2303_init(struct usb_device
*, uint8_t);
167 static void uplcom_cfg_set_dtr(struct ucom_softc
*, uint8_t);
168 static void uplcom_cfg_set_rts(struct ucom_softc
*, uint8_t);
169 static void uplcom_cfg_set_break(struct ucom_softc
*, uint8_t);
170 static int uplcom_pre_param(struct ucom_softc
*, struct termios
*);
171 static void uplcom_cfg_param(struct ucom_softc
*, struct termios
*);
172 static void uplcom_start_read(struct ucom_softc
*);
173 static void uplcom_stop_read(struct ucom_softc
*);
174 static void uplcom_start_write(struct ucom_softc
*);
175 static void uplcom_stop_write(struct ucom_softc
*);
176 static void uplcom_cfg_get_status(struct ucom_softc
*, uint8_t *,
178 static void uplcom_poll(struct ucom_softc
*ucom
);
180 static device_probe_t uplcom_probe
;
181 static device_attach_t uplcom_attach
;
182 static device_detach_t uplcom_detach
;
184 static usb_callback_t uplcom_intr_callback
;
185 static usb_callback_t uplcom_write_callback
;
186 static usb_callback_t uplcom_read_callback
;
188 static const struct usb_config uplcom_config_data
[UPLCOM_N_TRANSFER
] = {
190 [UPLCOM_BULK_DT_WR
] = {
192 .endpoint
= UE_ADDR_ANY
,
193 .direction
= UE_DIR_OUT
,
194 .bufsize
= UPLCOM_BULK_BUF_SIZE
,
195 .flags
= {.pipe_bof
= 1,.force_short_xfer
= 1,},
196 .callback
= &uplcom_write_callback
,
200 [UPLCOM_BULK_DT_RD
] = {
202 .endpoint
= UE_ADDR_ANY
,
203 .direction
= UE_DIR_IN
,
204 .bufsize
= UPLCOM_BULK_BUF_SIZE
,
205 .flags
= {.pipe_bof
= 1,.short_xfer_ok
= 1,},
206 .callback
= &uplcom_read_callback
,
210 [UPLCOM_INTR_DT_RD
] = {
211 .type
= UE_INTERRUPT
,
212 .endpoint
= UE_ADDR_ANY
,
213 .direction
= UE_DIR_IN
,
214 .flags
= {.pipe_bof
= 1,.short_xfer_ok
= 1,},
215 .bufsize
= 0, /* use wMaxPacketSize */
216 .callback
= &uplcom_intr_callback
,
221 static struct ucom_callback uplcom_callback
= {
222 .ucom_cfg_get_status
= &uplcom_cfg_get_status
,
223 .ucom_cfg_set_dtr
= &uplcom_cfg_set_dtr
,
224 .ucom_cfg_set_rts
= &uplcom_cfg_set_rts
,
225 .ucom_cfg_set_break
= &uplcom_cfg_set_break
,
226 .ucom_cfg_param
= &uplcom_cfg_param
,
227 .ucom_pre_param
= &uplcom_pre_param
,
228 .ucom_start_read
= &uplcom_start_read
,
229 .ucom_stop_read
= &uplcom_stop_read
,
230 .ucom_start_write
= &uplcom_start_write
,
231 .ucom_stop_write
= &uplcom_stop_write
,
232 .ucom_poll
= &uplcom_poll
,
235 #define UPLCOM_DEV(v,p) \
236 { USB_VENDOR(USB_VENDOR_##v), USB_PRODUCT(USB_PRODUCT_##v##_##p) }
238 static const STRUCT_USB_HOST_ID uplcom_devs
[] = {
239 UPLCOM_DEV(ACERP
, S81
), /* BenQ S81 phone */
240 UPLCOM_DEV(ADLINK
, ND6530
), /* ADLINK ND-6530 USB-Serial */
241 UPLCOM_DEV(ALCATEL
, OT535
), /* Alcatel One Touch 535/735 */
242 UPLCOM_DEV(ALCOR
, AU9720
), /* Alcor AU9720 USB 2.0-RS232 */
243 UPLCOM_DEV(ANCHOR
, SERIAL
), /* Anchor Serial adapter */
244 UPLCOM_DEV(ATEN
, UC232A
), /* PLANEX USB-RS232 URS-03 */
245 UPLCOM_DEV(BELKIN
, F5U257
), /* Belkin F5U257 USB to Serial */
246 UPLCOM_DEV(COREGA
, CGUSBRS232R
), /* Corega CG-USBRS232R */
247 UPLCOM_DEV(EPSON
, CRESSI_EDY
), /* Cressi Edy diving computer */
248 UPLCOM_DEV(EPSON
, N2ITION3
), /* Zeagle N2iTion3 diving computer */
249 UPLCOM_DEV(ELECOM
, UCSGT
), /* ELECOM UC-SGT Serial Adapter */
250 UPLCOM_DEV(ELECOM
, UCSGT0
), /* ELECOM UC-SGT Serial Adapter */
251 UPLCOM_DEV(HAL
, IMR001
), /* HAL Corporation Crossam2+USB */
252 UPLCOM_DEV(HP
, LD220
), /* HP LD220 POS Display */
253 UPLCOM_DEV(IODATA
, USBRSAQ
), /* I/O DATA USB-RSAQ */
254 UPLCOM_DEV(IODATA
, USBRSAQ5
), /* I/O DATA USB-RSAQ5 */
255 UPLCOM_DEV(ITEGNO
, WM1080A
), /* iTegno WM1080A GSM/GFPRS modem */
256 UPLCOM_DEV(ITEGNO
, WM2080A
), /* iTegno WM2080A CDMA modem */
257 UPLCOM_DEV(LEADTEK
, 9531), /* Leadtek 9531 GPS */
258 UPLCOM_DEV(MICROSOFT
, 700WX
), /* Microsoft Palm 700WX */
259 UPLCOM_DEV(MOBILEACTION
, MA620
), /* Mobile Action MA-620 Infrared Adapter */
260 UPLCOM_DEV(NETINDEX
, WS002IN
), /* Willcom W-S002IN */
261 UPLCOM_DEV(NOKIA2
, CA42
), /* Nokia CA-42 cable */
262 UPLCOM_DEV(OTI
, DKU5
), /* OTI DKU-5 cable */
263 UPLCOM_DEV(PANASONIC
, TYTP50P6S
), /* Panasonic TY-TP50P6-S flat screen */
264 UPLCOM_DEV(PLX
, CA42
), /* PLX CA-42 clone cable */
265 UPLCOM_DEV(PROLIFIC
, ALLTRONIX_GPRS
), /* Alltronix ACM003U00 modem */
266 UPLCOM_DEV(PROLIFIC
, ALDIGA_AL11U
), /* AlDiga AL-11U modem */
267 UPLCOM_DEV(PROLIFIC
, DCU11
), /* DCU-11 Phone Cable */
268 UPLCOM_DEV(PROLIFIC
, HCR331
), /* HCR331 Card Reader */
269 UPLCOM_DEV(PROLIFIC
, MICROMAX_610U
), /* Micromax 610U modem */
270 UPLCOM_DEV(PROLIFIC
, PHAROS
), /* Prolific Pharos */
271 UPLCOM_DEV(PROLIFIC
, PL2303
), /* Generic adapter */
272 UPLCOM_DEV(PROLIFIC
, RSAQ2
), /* I/O DATA USB-RSAQ2 */
273 UPLCOM_DEV(PROLIFIC
, RSAQ3
), /* I/O DATA USB-RSAQ3 */
274 UPLCOM_DEV(PROLIFIC
, UIC_MSR206
), /* UIC MSR206 Card Reader */
275 UPLCOM_DEV(PROLIFIC2
, PL2303
), /* Prolific adapter */
276 UPLCOM_DEV(RADIOSHACK
, USBCABLE
), /* Radio Shack USB Adapter */
277 UPLCOM_DEV(RATOC
, REXUSB60
), /* RATOC REX-USB60 */
278 UPLCOM_DEV(SAGEM
, USBSERIAL
), /* Sagem USB-Serial Controller */
279 UPLCOM_DEV(SAMSUNG
, I330
), /* Samsung I330 phone cradle */
280 UPLCOM_DEV(SANWA
, KB_USB2
), /* Sanwa KB-USB2 Multimeter cable */
281 UPLCOM_DEV(SIEMENS3
, EF81
), /* Siemens EF81 */
282 UPLCOM_DEV(SIEMENS3
, SX1
), /* Siemens SX1 */
283 UPLCOM_DEV(SIEMENS3
, X65
), /* Siemens X65 */
284 UPLCOM_DEV(SIEMENS3
, X75
), /* Siemens X75 */
285 UPLCOM_DEV(SITECOM
, SERIAL
), /* Sitecom USB to Serial */
286 UPLCOM_DEV(SMART
, PL2303
), /* SMART Technologies USB to Serial */
287 UPLCOM_DEV(SONY
, QN3
), /* Sony QN3 phone cable */
288 UPLCOM_DEV(SONYERICSSON
, DATAPILOT
), /* Sony Ericsson Datapilot */
289 UPLCOM_DEV(SONYERICSSON
, DCU10
), /* Sony Ericsson DCU-10 Cable */
290 UPLCOM_DEV(SOURCENEXT
, KEIKAI8
), /* SOURCENEXT KeikaiDenwa 8 */
291 UPLCOM_DEV(SOURCENEXT
, KEIKAI8_CHG
), /* SOURCENEXT KeikaiDenwa 8 with charger */
292 UPLCOM_DEV(SPEEDDRAGON
, MS3303H
), /* Speed Dragon USB-Serial */
293 UPLCOM_DEV(SYNTECH
, CPT8001C
), /* Syntech CPT-8001C Barcode scanner */
294 UPLCOM_DEV(TDK
, UHA6400
), /* TDK USB-PHS Adapter UHA6400 */
295 UPLCOM_DEV(TDK
, UPA9664
), /* TDK USB-PHS Adapter UPA9664 */
296 UPLCOM_DEV(TRIPPLITE
, U209
), /* Tripp-Lite U209-000-R USB to Serial */
297 UPLCOM_DEV(YCCABLE
, PL2303
), /* YC Cable USB-Serial */
301 static device_method_t uplcom_methods
[] = {
302 DEVMETHOD(device_probe
, uplcom_probe
),
303 DEVMETHOD(device_attach
, uplcom_attach
),
304 DEVMETHOD(device_detach
, uplcom_detach
),
308 static devclass_t uplcom_devclass
;
310 static driver_t uplcom_driver
= {
312 .methods
= uplcom_methods
,
313 .size
= sizeof(struct uplcom_softc
),
316 DRIVER_MODULE(uplcom
, uhub
, uplcom_driver
, uplcom_devclass
, NULL
, NULL
);
317 MODULE_DEPEND(uplcom
, ucom
, 1, 1, 1);
318 MODULE_DEPEND(uplcom
, usb
, 1, 1, 1);
319 MODULE_VERSION(uplcom
, UPLCOM_MODVER
);
322 uplcom_probe(device_t dev
)
324 struct usb_attach_arg
*uaa
= device_get_ivars(dev
);
328 if (uaa
->usb_mode
!= USB_MODE_HOST
) {
331 if (uaa
->info
.bConfigIndex
!= UPLCOM_CONFIG_INDEX
) {
334 if (uaa
->info
.bIfaceIndex
!= UPLCOM_IFACE_INDEX
) {
337 return (usbd_lookup_id_by_uaa(uplcom_devs
, sizeof(uplcom_devs
), uaa
));
341 uplcom_attach(device_t dev
)
343 struct usb_attach_arg
*uaa
= device_get_ivars(dev
);
344 struct uplcom_softc
*sc
= device_get_softc(dev
);
345 struct usb_interface
*iface
;
346 struct usb_interface_descriptor
*id
;
347 struct usb_device_descriptor
*dd
;
352 device_set_usb_desc(dev
);
353 lockinit(&sc
->sc_lock
, "uplcom", 0, LK_CANRECURSE
);
355 DPRINTF("sc = %p\n", sc
);
357 sc
->sc_udev
= uaa
->device
;
359 /* Determine the chip type. This algorithm is taken from Linux. */
360 dd
= usbd_get_device_descriptor(sc
->sc_udev
);
361 if (dd
->bDeviceClass
== 0x02)
362 sc
->sc_chiptype
= TYPE_PL2303
;
363 else if (dd
->bMaxPacketSize
== 0x40)
364 sc
->sc_chiptype
= TYPE_PL2303HX
;
366 sc
->sc_chiptype
= TYPE_PL2303
;
368 DPRINTF("chiptype: %s\n",
369 (sc
->sc_chiptype
== TYPE_PL2303HX
) ?
373 * USB-RSAQ1 has two interface
375 * USB-RSAQ1 | USB-RSAQ2
376 * -----------------+-----------------
377 * Interface 0 |Interface 0
378 * Interrupt(0x81) | Interrupt(0x81)
379 * -----------------+ BulkIN(0x02)
380 * Interface 1 | BulkOUT(0x83)
385 sc
->sc_ctrl_iface_no
= uaa
->info
.bIfaceNum
;
386 sc
->sc_iface_index
[1] = UPLCOM_IFACE_INDEX
;
388 iface
= usbd_get_iface(uaa
->device
, UPLCOM_SECOND_IFACE_INDEX
);
390 id
= usbd_get_interface_descriptor(iface
);
392 device_printf(dev
, "no interface descriptor (2)\n");
395 sc
->sc_data_iface_no
= id
->bInterfaceNumber
;
396 sc
->sc_iface_index
[0] = UPLCOM_SECOND_IFACE_INDEX
;
397 usbd_set_parent_iface(uaa
->device
,
398 UPLCOM_SECOND_IFACE_INDEX
, uaa
->info
.bIfaceIndex
);
400 sc
->sc_data_iface_no
= sc
->sc_ctrl_iface_no
;
401 sc
->sc_iface_index
[0] = UPLCOM_IFACE_INDEX
;
404 error
= usbd_transfer_setup(uaa
->device
,
405 sc
->sc_iface_index
, sc
->sc_xfer
, uplcom_config_data
,
406 UPLCOM_N_TRANSFER
, sc
, &sc
->sc_lock
);
408 DPRINTF("one or more missing USB endpoints, "
409 "error=%s\n", usbd_errstr(error
));
412 error
= uplcom_reset(sc
, uaa
->device
);
414 device_printf(dev
, "reset failed, error=%s\n",
418 /* clear stall at first run */
419 lockmgr(&sc
->sc_lock
, LK_EXCLUSIVE
);
420 usbd_xfer_set_stall(sc
->sc_xfer
[UPLCOM_BULK_DT_WR
]);
421 usbd_xfer_set_stall(sc
->sc_xfer
[UPLCOM_BULK_DT_RD
]);
422 lockmgr(&sc
->sc_lock
, LK_RELEASE
);
424 error
= ucom_attach(&sc
->sc_super_ucom
, &sc
->sc_ucom
, 1, sc
,
425 &uplcom_callback
, &sc
->sc_lock
);
430 * do the initialization during attach so that the system does not
433 if (uplcom_pl2303_init(uaa
->device
, sc
->sc_chiptype
)) {
434 device_printf(dev
, "init failed\n");
437 ucom_set_pnpinfo_usb(&sc
->sc_super_ucom
, dev
);
447 uplcom_detach(device_t dev
)
449 struct uplcom_softc
*sc
= device_get_softc(dev
);
451 DPRINTF("sc=%p\n", sc
);
453 ucom_detach(&sc
->sc_super_ucom
, &sc
->sc_ucom
);
454 usbd_transfer_unsetup(sc
->sc_xfer
, UPLCOM_N_TRANSFER
);
455 lockuninit(&sc
->sc_lock
);
461 uplcom_reset(struct uplcom_softc
*sc
, struct usb_device
*udev
)
463 struct usb_device_request req
;
465 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
466 req
.bRequest
= UPLCOM_SET_REQUEST
;
467 USETW(req
.wValue
, 0);
468 req
.wIndex
[0] = sc
->sc_data_iface_no
;
470 USETW(req
.wLength
, 0);
472 return (usbd_do_request(udev
, NULL
, &req
, NULL
));
476 uplcom_pl2303_do(struct usb_device
*udev
, int8_t req_type
, uint8_t request
,
477 uint16_t value
, uint16_t index
, uint16_t length
)
479 struct usb_device_request req
;
483 req
.bmRequestType
= req_type
;
484 req
.bRequest
= request
;
485 USETW(req
.wValue
, value
);
486 USETW(req
.wIndex
, index
);
487 USETW(req
.wLength
, length
);
489 err
= usbd_do_request(udev
, NULL
, &req
, buf
);
491 DPRINTF("error=%s\n", usbd_errstr(err
));
498 uplcom_pl2303_init(struct usb_device
*udev
, uint8_t chiptype
)
502 if (uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8484, 0, 1)
503 || uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x0404, 0, 0)
504 || uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8484, 0, 1)
505 || uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8383, 0, 1)
506 || uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8484, 0, 1)
507 || uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x0404, 1, 0)
508 || uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8484, 0, 1)
509 || uplcom_pl2303_do(udev
, UT_READ_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0x8383, 0, 1)
510 || uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 0, 1, 0)
511 || uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 1, 0, 0))
514 if (chiptype
== TYPE_PL2303HX
)
515 err
= uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 2, 0x44, 0);
517 err
= uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 2, 0x24, 0);
521 if (uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 8, 0, 0)
522 || uplcom_pl2303_do(udev
, UT_WRITE_VENDOR_DEVICE
, UPLCOM_SET_REQUEST
, 9, 0, 0))
528 uplcom_cfg_set_dtr(struct ucom_softc
*ucom
, uint8_t onoff
)
530 struct uplcom_softc
*sc
= ucom
->sc_parent
;
531 struct usb_device_request req
;
533 DPRINTF("onoff = %d\n", onoff
);
536 sc
->sc_line
|= UCDC_LINE_DTR
;
538 sc
->sc_line
&= ~UCDC_LINE_DTR
;
540 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
541 req
.bRequest
= UCDC_SET_CONTROL_LINE_STATE
;
542 USETW(req
.wValue
, sc
->sc_line
);
543 req
.wIndex
[0] = sc
->sc_data_iface_no
;
545 USETW(req
.wLength
, 0);
547 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
548 &req
, NULL
, 0, 1000);
552 uplcom_cfg_set_rts(struct ucom_softc
*ucom
, uint8_t onoff
)
554 struct uplcom_softc
*sc
= ucom
->sc_parent
;
555 struct usb_device_request req
;
557 DPRINTF("onoff = %d\n", onoff
);
560 sc
->sc_line
|= UCDC_LINE_RTS
;
562 sc
->sc_line
&= ~UCDC_LINE_RTS
;
564 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
565 req
.bRequest
= UCDC_SET_CONTROL_LINE_STATE
;
566 USETW(req
.wValue
, sc
->sc_line
);
567 req
.wIndex
[0] = sc
->sc_data_iface_no
;
569 USETW(req
.wLength
, 0);
571 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
572 &req
, NULL
, 0, 1000);
576 uplcom_cfg_set_break(struct ucom_softc
*ucom
, uint8_t onoff
)
578 struct uplcom_softc
*sc
= ucom
->sc_parent
;
579 struct usb_device_request req
;
582 DPRINTF("onoff = %d\n", onoff
);
584 temp
= (onoff
? UCDC_BREAK_ON
: UCDC_BREAK_OFF
);
586 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
587 req
.bRequest
= UCDC_SEND_BREAK
;
588 USETW(req
.wValue
, temp
);
589 req
.wIndex
[0] = sc
->sc_data_iface_no
;
591 USETW(req
.wLength
, 0);
593 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
594 &req
, NULL
, 0, 1000);
597 static const int32_t uplcom_rates
[] = {
598 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400,
599 19200, 28800, 38400, 57600, 115200,
601 * Higher speeds are probably possible. PL2303X supports up to
602 * 6Mb and can set any rate
604 230400, 460800, 614400, 921600, 1228800
608 uplcom_pre_param(struct ucom_softc
*ucom
, struct termios
*t
)
610 struct uplcom_softc
*sc
= ucom
->sc_parent
;
616 * Check requested baud rate.
618 * The PL2303 can only set specific baud rates, up to 1228800 baud.
619 * The PL2303X can set any baud rate up to 6Mb.
620 * The PL2303HX rev. D can set any baud rate up to 12Mb.
622 * XXX: We currently cannot identify the PL2303HX rev. D, so treat
623 * it the same as the PL2303X.
625 if (sc
->sc_chiptype
!= TYPE_PL2303HX
) {
626 for (i
= 0; i
< NELEM(uplcom_rates
); i
++) {
627 if (uplcom_rates
[i
] == t
->c_ospeed
)
631 if (t
->c_ospeed
<= 6000000)
635 DPRINTF("uplcom_param: bad baud rate (%d)\n", t
->c_ospeed
);
640 uplcom_cfg_param(struct ucom_softc
*ucom
, struct termios
*t
)
642 struct uplcom_softc
*sc
= ucom
->sc_parent
;
643 struct usb_cdc_line_state ls
;
644 struct usb_device_request req
;
646 DPRINTF("sc = %p\n", sc
);
648 memset(&ls
, 0, sizeof(ls
));
650 USETDW(ls
.dwDTERate
, t
->c_ospeed
);
652 if (t
->c_cflag
& CSTOPB
) {
653 ls
.bCharFormat
= UCDC_STOP_BIT_2
;
655 ls
.bCharFormat
= UCDC_STOP_BIT_1
;
658 if (t
->c_cflag
& PARENB
) {
659 if (t
->c_cflag
& PARODD
) {
660 ls
.bParityType
= UCDC_PARITY_ODD
;
662 ls
.bParityType
= UCDC_PARITY_EVEN
;
665 ls
.bParityType
= UCDC_PARITY_NONE
;
668 switch (t
->c_cflag
& CSIZE
) {
683 DPRINTF("rate=%d fmt=%d parity=%d bits=%d\n",
684 UGETDW(ls
.dwDTERate
), ls
.bCharFormat
,
685 ls
.bParityType
, ls
.bDataBits
);
687 req
.bmRequestType
= UT_WRITE_CLASS_INTERFACE
;
688 req
.bRequest
= UCDC_SET_LINE_CODING
;
689 USETW(req
.wValue
, 0);
690 req
.wIndex
[0] = sc
->sc_data_iface_no
;
692 USETW(req
.wLength
, UCDC_LINE_STATE_LENGTH
);
694 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
697 if (t
->c_cflag
& CRTSCTS
) {
699 DPRINTF("crtscts = on\n");
701 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
702 req
.bRequest
= UPLCOM_SET_REQUEST
;
703 USETW(req
.wValue
, 0);
704 if (sc
->sc_chiptype
== TYPE_PL2303HX
)
705 USETW(req
.wIndex
, UPLCOM_SET_CRTSCTS_PL2303X
);
707 USETW(req
.wIndex
, UPLCOM_SET_CRTSCTS
);
708 USETW(req
.wLength
, 0);
710 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
711 &req
, NULL
, 0, 1000);
713 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
714 req
.bRequest
= UPLCOM_SET_REQUEST
;
715 USETW(req
.wValue
, 0);
716 USETW(req
.wIndex
, 0);
717 USETW(req
.wLength
, 0);
718 ucom_cfg_do_request(sc
->sc_udev
, &sc
->sc_ucom
,
719 &req
, NULL
, 0, 1000);
724 uplcom_start_read(struct ucom_softc
*ucom
)
726 struct uplcom_softc
*sc
= ucom
->sc_parent
;
728 /* start interrupt endpoint */
729 usbd_transfer_start(sc
->sc_xfer
[UPLCOM_INTR_DT_RD
]);
731 /* start read endpoint */
732 usbd_transfer_start(sc
->sc_xfer
[UPLCOM_BULK_DT_RD
]);
736 uplcom_stop_read(struct ucom_softc
*ucom
)
738 struct uplcom_softc
*sc
= ucom
->sc_parent
;
740 /* stop interrupt endpoint */
741 usbd_transfer_stop(sc
->sc_xfer
[UPLCOM_INTR_DT_RD
]);
743 /* stop read endpoint */
744 usbd_transfer_stop(sc
->sc_xfer
[UPLCOM_BULK_DT_RD
]);
748 uplcom_start_write(struct ucom_softc
*ucom
)
750 struct uplcom_softc
*sc
= ucom
->sc_parent
;
752 usbd_transfer_start(sc
->sc_xfer
[UPLCOM_BULK_DT_WR
]);
756 uplcom_stop_write(struct ucom_softc
*ucom
)
758 struct uplcom_softc
*sc
= ucom
->sc_parent
;
760 usbd_transfer_stop(sc
->sc_xfer
[UPLCOM_BULK_DT_WR
]);
764 uplcom_cfg_get_status(struct ucom_softc
*ucom
, uint8_t *lsr
, uint8_t *msr
)
766 struct uplcom_softc
*sc
= ucom
->sc_parent
;
775 uplcom_intr_callback(struct usb_xfer
*xfer
, usb_error_t error
)
777 struct uplcom_softc
*sc
= usbd_xfer_softc(xfer
);
778 struct usb_page_cache
*pc
;
782 usbd_xfer_status(xfer
, &actlen
, NULL
, NULL
, NULL
);
784 switch (USB_GET_STATE(xfer
)) {
785 case USB_ST_TRANSFERRED
:
787 DPRINTF("actlen = %u\n", actlen
);
791 pc
= usbd_xfer_get_frame(xfer
, 0);
792 usbd_copy_out(pc
, 0, buf
, sizeof(buf
));
794 DPRINTF("status = 0x%02x\n", buf
[8]);
799 if (buf
[8] & RSAQ_STATUS_CTS
) {
800 sc
->sc_msr
|= SER_CTS
;
802 if (buf
[8] & RSAQ_STATUS_DSR
) {
803 sc
->sc_msr
|= SER_DSR
;
805 if (buf
[8] & RSAQ_STATUS_DCD
) {
806 sc
->sc_msr
|= SER_DCD
;
808 ucom_status_change(&sc
->sc_ucom
);
812 usbd_xfer_set_frame_len(xfer
, 0, usbd_xfer_max_len(xfer
));
813 usbd_transfer_submit(xfer
);
817 if (error
!= USB_ERR_CANCELLED
) {
818 /* try to clear stall first */
819 usbd_xfer_set_stall(xfer
);
827 uplcom_write_callback(struct usb_xfer
*xfer
, usb_error_t error
)
829 struct uplcom_softc
*sc
= usbd_xfer_softc(xfer
);
830 struct usb_page_cache
*pc
;
833 switch (USB_GET_STATE(xfer
)) {
835 case USB_ST_TRANSFERRED
:
837 pc
= usbd_xfer_get_frame(xfer
, 0);
838 if (ucom_get_data(&sc
->sc_ucom
, pc
, 0,
839 UPLCOM_BULK_BUF_SIZE
, &actlen
)) {
841 DPRINTF("actlen = %d\n", actlen
);
843 usbd_xfer_set_frame_len(xfer
, 0, actlen
);
844 usbd_transfer_submit(xfer
);
849 if (error
!= USB_ERR_CANCELLED
) {
850 /* try to clear stall first */
851 usbd_xfer_set_stall(xfer
);
859 uplcom_read_callback(struct usb_xfer
*xfer
, usb_error_t error
)
861 struct uplcom_softc
*sc
= usbd_xfer_softc(xfer
);
862 struct usb_page_cache
*pc
;
865 usbd_xfer_status(xfer
, &actlen
, NULL
, NULL
, NULL
);
867 switch (USB_GET_STATE(xfer
)) {
868 case USB_ST_TRANSFERRED
:
869 pc
= usbd_xfer_get_frame(xfer
, 0);
870 ucom_put_data(&sc
->sc_ucom
, pc
, 0, actlen
);
874 usbd_xfer_set_frame_len(xfer
, 0, usbd_xfer_max_len(xfer
));
875 usbd_transfer_submit(xfer
);
879 if (error
!= USB_ERR_CANCELLED
) {
880 /* try to clear stall first */
881 usbd_xfer_set_stall(xfer
);
889 uplcom_poll(struct ucom_softc
*ucom
)
891 struct uplcom_softc
*sc
= ucom
->sc_parent
;
892 usbd_transfer_poll(sc
->sc_xfer
, UPLCOM_N_TRANSFER
);