1 /* $NetBSD: uftdi.c,v 1.43 2009/09/23 19:07:19 plunky Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: uftdi.c,v 1.43 2009/09/23 19:07:19 plunky Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
42 #include <dev/usb/usb.h>
44 #include <dev/usb/usbdi.h>
45 #include <dev/usb/usbdi_util.h>
46 #include <dev/usb/usbdevs.h>
48 #include <dev/usb/ucomvar.h>
50 #include <dev/usb/uftdireg.h>
53 #define DPRINTF(x) if (uftdidebug) printf x
54 #define DPRINTFN(n,x) if (uftdidebug>(n)) printf x
61 #define UFTDI_CONFIG_INDEX 0
62 #define UFTDI_IFACE_INDEX 0
63 #define UFTDI_MAX_PORTS 4
66 * These are the maximum number of bytes transferred per frame.
67 * The output buffer size cannot be increased due to the size encoding.
69 #define UFTDIIBUFSIZE 64
70 #define UFTDIOBUFSIZE 64
73 USBBASEDEVICE sc_dev
; /* base device */
74 usbd_device_handle sc_udev
; /* device */
75 usbd_interface_handle sc_iface
[UFTDI_MAX_PORTS
]; /* interface */
77 enum uftdi_type sc_type
;
85 device_ptr_t sc_subdev
[UFTDI_MAX_PORTS
];
93 Static
void uftdi_get_status(void *, int portno
, u_char
*lsr
, u_char
*msr
);
94 Static
void uftdi_set(void *, int, int, int);
95 Static
int uftdi_param(void *, int, struct termios
*);
96 Static
int uftdi_open(void *sc
, int portno
);
97 Static
void uftdi_read(void *sc
, int portno
, u_char
**ptr
,u_int32_t
*count
);
98 Static
void uftdi_write(void *sc
, int portno
, u_char
*to
, u_char
*from
,
100 Static
void uftdi_break(void *sc
, int portno
, int onoff
);
102 struct ucom_methods uftdi_methods
= {
114 * The devices default to UFTDI_TYPE_8U232AM.
115 * Remember to update USB_ATTACH if it should be UFTDI_TYPE_SIO instead
117 static const struct usb_devno uftdi_devs
[] = {
118 { USB_VENDOR_BBELECTRONICS
, USB_PRODUCT_BBELECTRONICS_USOTL4
},
119 { USB_VENDOR_FALCOM
, USB_PRODUCT_FALCOM_TWIST
},
120 { USB_VENDOR_FALCOM
, USB_PRODUCT_FALCOM_SAMBA
},
121 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_SERIAL_2232C
},
122 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_SERIAL_4232H
},
123 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_SERIAL_8U100AX
},
124 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_SERIAL_8U232AM
},
125 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_KW
},
126 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_YS
},
127 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_Y6
},
128 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_Y8
},
129 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_IC
},
130 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_DB9
},
131 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_RS232
},
132 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_MHAM_Y9
},
133 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_COASTAL_TNCX
},
134 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_SEMC_DSS20
},
135 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_LK202_24_USB
},
136 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_LK204_24_USB
},
137 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_MX200_USB
},
138 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_MX4_MX5_USB
},
139 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_CFA_631
},
140 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_CFA_632
},
141 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_CFA_633
},
142 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_CFA_634
},
143 { USB_VENDOR_FTDI
, USB_PRODUCT_FTDI_LCD_CFA_635
},
144 { USB_VENDOR_INTREPIDCS
, USB_PRODUCT_INTREPIDCS_VALUECAN
},
145 { USB_VENDOR_INTREPIDCS
, USB_PRODUCT_INTREPIDCS_NEOVI
},
146 { USB_VENDOR_RATOC
, USB_PRODUCT_RATOC_REXUSB60F
},
147 { USB_VENDOR_SEALEVEL
, USB_PRODUCT_SEALEVEL_USBSERIAL
},
148 { USB_VENDOR_SEALEVEL
, USB_PRODUCT_SEALEVEL_SEAPORT4P1
},
149 { USB_VENDOR_SEALEVEL
, USB_PRODUCT_SEALEVEL_SEAPORT4P2
},
150 { USB_VENDOR_SEALEVEL
, USB_PRODUCT_SEALEVEL_SEAPORT4P3
},
151 { USB_VENDOR_SEALEVEL
, USB_PRODUCT_SEALEVEL_SEAPORT4P4
},
152 { USB_VENDOR_SIIG2
, USB_PRODUCT_SIIG2_US2308
},
154 #define uftdi_lookup(v, p) usb_lookup(uftdi_devs, v, p)
156 int uftdi_match(device_t
, cfdata_t
, void *);
157 void uftdi_attach(device_t
, device_t
, void *);
158 void uftdi_childdet(device_t
, device_t
);
159 int uftdi_detach(device_t
, int);
160 int uftdi_activate(device_t
, enum devact
);
161 extern struct cfdriver uftdi_cd
;
162 CFATTACH_DECL2_NEW(uftdi
, sizeof(struct uftdi_softc
), uftdi_match
,
163 uftdi_attach
, uftdi_detach
, uftdi_activate
, NULL
, uftdi_childdet
);
167 USB_MATCH_START(uftdi
, uaa
);
169 DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n",
170 uaa
->vendor
, uaa
->product
));
172 return (uftdi_lookup(uaa
->vendor
, uaa
->product
) != NULL
?
173 UMATCH_VENDOR_PRODUCT
: UMATCH_NONE
);
178 USB_ATTACH_START(uftdi
, sc
, uaa
);
179 usbd_device_handle dev
= uaa
->device
;
180 usbd_interface_handle iface
;
181 usb_device_descriptor_t
*ddesc
;
182 usb_interface_descriptor_t
*id
;
183 usb_endpoint_descriptor_t
*ed
;
185 const char *devname
= device_xname(self
);
188 struct ucom_attach_args uca
;
190 DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc
));
195 devinfop
= usbd_devinfo_alloc(dev
, 0);
196 aprint_normal_dev(self
, "%s\n", devinfop
);
197 usbd_devinfo_free(devinfop
);
199 /* Move the device into the configured state. */
200 err
= usbd_set_config_index(dev
, UFTDI_CONFIG_INDEX
, 1);
202 aprint_error("\n%s: failed to set configuration, err=%s\n",
203 devname
, usbd_errstr(err
));
210 sc
->sc_type
= UFTDI_TYPE_8U232AM
; /* most devices are post-8U232AM */
212 if (uaa
->vendor
== USB_VENDOR_FTDI
213 && uaa
->product
== USB_PRODUCT_FTDI_SERIAL_8U100AX
) {
214 sc
->sc_type
= UFTDI_TYPE_SIO
;
218 ddesc
= usbd_get_device_descriptor(dev
);
219 sc
->sc_chiptype
= UGETW(ddesc
->bcdDevice
);
220 switch (sc
->sc_chiptype
) {
221 case 0x500: /* 2232D */
222 case 0x700: /* 2232H */
225 case 0x800: /* 4232H */
228 case 0x200: /* 232/245AM */
229 case 0x400: /* 232/245BL */
230 case 0x600: /* 232/245R */
235 for (idx
= UFTDI_IFACE_INDEX
; idx
< sc
->sc_numports
; idx
++) {
236 err
= usbd_device2interface_handle(dev
, idx
, &iface
);
239 "\n%s: failed to get interface idx=%d, err=%s\n",
240 devname
, idx
, usbd_errstr(err
));
244 id
= usbd_get_interface_descriptor(iface
);
246 sc
->sc_iface
[idx
] = iface
;
248 uca
.bulkin
= uca
.bulkout
= -1;
249 for (i
= 0; i
< id
->bNumEndpoints
; i
++) {
251 ed
= usbd_interface2endpoint_descriptor(iface
, i
);
253 aprint_error_dev(self
,
254 "could not read endpoint descriptor: %s\n",
259 addr
= ed
->bEndpointAddress
;
260 dir
= UE_GET_DIR(ed
->bEndpointAddress
);
261 attr
= ed
->bmAttributes
& UE_XFERTYPE
;
262 if (dir
== UE_DIR_IN
&& attr
== UE_BULK
)
264 else if (dir
== UE_DIR_OUT
&& attr
== UE_BULK
)
267 aprint_error_dev(self
,
268 "unexpected endpoint\n");
272 if (uca
.bulkin
== -1) {
273 aprint_error_dev(self
,
274 "Could not find data bulk in\n");
277 if (uca
.bulkout
== -1) {
278 aprint_error_dev(self
,
279 "Could not find data bulk out\n");
283 uca
.portno
= FTDI_PIT_SIOA
+ idx
;
284 /* bulkin, bulkout set above */
285 uca
.ibufsize
= UFTDIIBUFSIZE
;
286 uca
.obufsize
= UFTDIOBUFSIZE
- sc
->sc_hdrlen
;
287 uca
.ibufsizepad
= UFTDIIBUFSIZE
;
288 uca
.opkthdrlen
= sc
->sc_hdrlen
;
291 uca
.methods
= &uftdi_methods
;
295 DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca
.bulkin
, uca
.bulkout
));
296 sc
->sc_subdev
[idx
] = config_found_sm_loc(self
, "ucombus", NULL
,
297 &uca
, ucomprint
, ucomsubmatch
);
300 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
303 USB_ATTACH_SUCCESS_RETURN
;
306 DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
308 USB_ATTACH_ERROR_RETURN
;
312 uftdi_activate(device_t self
, enum devact act
)
314 struct uftdi_softc
*sc
= device_private(self
);
317 case DVACT_DEACTIVATE
:
326 uftdi_childdet(device_t self
, device_t child
)
329 struct uftdi_softc
*sc
= device_private(self
);
331 for (i
= 0; i
< sc
->sc_numports
; i
++) {
332 if (sc
->sc_subdev
[i
] == child
)
335 KASSERT(i
< sc
->sc_numports
);
336 sc
->sc_subdev
[i
] = NULL
;
340 uftdi_detach(device_t self
, int flags
)
342 struct uftdi_softc
*sc
= device_private(self
);
345 DPRINTF(("uftdi_detach: sc=%p flags=%d\n", sc
, flags
));
347 for (i
=0; i
< sc
->sc_numports
; i
++) {
348 if (sc
->sc_subdev
[i
] != NULL
)
349 config_detach(sc
->sc_subdev
[i
], flags
);
352 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
359 uftdi_open(void *vsc
, int portno
)
361 struct uftdi_softc
*sc
= vsc
;
362 usb_device_request_t req
;
366 DPRINTF(("uftdi_open: sc=%p\n", sc
));
371 /* Perform a full reset on the device */
372 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
373 req
.bRequest
= FTDI_SIO_RESET
;
374 USETW(req
.wValue
, FTDI_SIO_RESET_SIO
);
375 USETW(req
.wIndex
, portno
);
376 USETW(req
.wLength
, 0);
377 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);
381 /* Set 9600 baud, 2 stop bits, no parity, 8 bits */
383 t
.c_cflag
= CSTOPB
| CS8
;
384 (void)uftdi_param(sc
, portno
, &t
);
386 /* Turn on RTS/CTS flow control */
387 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
388 req
.bRequest
= FTDI_SIO_SET_FLOW_CTRL
;
389 USETW(req
.wValue
, 0);
390 USETW2(req
.wIndex
, FTDI_SIO_RTS_CTS_HS
, portno
);
391 USETW(req
.wLength
, 0);
392 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);
400 uftdi_read(void *vsc
, int portno
, u_char
**ptr
, u_int32_t
*count
)
402 struct uftdi_softc
*sc
= vsc
;
405 DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc
, portno
,
408 msr
= FTDI_GET_MSR(*ptr
);
409 lsr
= FTDI_GET_LSR(*ptr
);
413 DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]="
414 "0x%02x\n", sc
, portno
, *count
, (*ptr
)[2]));
417 if (sc
->sc_msr
!= msr
||
418 (sc
->sc_lsr
& FTDI_LSR_MASK
) != (lsr
& FTDI_LSR_MASK
)) {
419 DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) "
420 "lsr=0x%02x(0x%02x)\n", msr
, sc
->sc_msr
,
424 ucom_status_change(device_private(sc
->sc_subdev
[portno
-1]));
427 /* Pick up status and adjust data part. */
433 uftdi_write(void *vsc
, int portno
, u_char
*to
, u_char
*from
, u_int32_t
*count
)
435 struct uftdi_softc
*sc
= vsc
;
437 DPRINTFN(10,("uftdi_write: sc=%p, port=%d count=%u data[0]=0x%02x\n",
438 vsc
, portno
, *count
, from
[0]));
440 /* Make length tag and copy data */
441 if (sc
->sc_hdrlen
> 0)
442 *to
= FTDI_OUT_TAG(*count
, portno
);
444 memcpy(to
+ sc
->sc_hdrlen
, from
, *count
);
445 *count
+= sc
->sc_hdrlen
;
449 uftdi_set(void *vsc
, int portno
, int reg
, int onoff
)
451 struct uftdi_softc
*sc
= vsc
;
452 usb_device_request_t req
;
455 DPRINTF(("uftdi_set: sc=%p, port=%d reg=%d onoff=%d\n", vsc
, portno
,
460 ctl
= onoff
? FTDI_SIO_SET_DTR_HIGH
: FTDI_SIO_SET_DTR_LOW
;
463 ctl
= onoff
? FTDI_SIO_SET_RTS_HIGH
: FTDI_SIO_SET_RTS_LOW
;
466 uftdi_break(sc
, portno
, onoff
);
471 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
472 req
.bRequest
= FTDI_SIO_MODEM_CTRL
;
473 USETW(req
.wValue
, ctl
);
474 USETW(req
.wIndex
, portno
);
475 USETW(req
.wLength
, 0);
476 DPRINTFN(2,("uftdi_set: reqtype=0x%02x req=0x%02x value=0x%04x "
477 "index=0x%04x len=%d\n", req
.bmRequestType
, req
.bRequest
,
478 UGETW(req
.wValue
), UGETW(req
.wIndex
), UGETW(req
.wLength
)));
479 (void)usbd_do_request(sc
->sc_udev
, &req
, NULL
);
483 uftdi_param(void *vsc
, int portno
, struct termios
*t
)
485 struct uftdi_softc
*sc
= vsc
;
486 usb_device_request_t req
;
488 int rate
, data
, flow
;
490 DPRINTF(("uftdi_param: sc=%p\n", sc
));
495 switch (sc
->sc_type
) {
497 switch (t
->c_ospeed
) {
498 case 300: rate
= ftdi_sio_b300
; break;
499 case 600: rate
= ftdi_sio_b600
; break;
500 case 1200: rate
= ftdi_sio_b1200
; break;
501 case 2400: rate
= ftdi_sio_b2400
; break;
502 case 4800: rate
= ftdi_sio_b4800
; break;
503 case 9600: rate
= ftdi_sio_b9600
; break;
504 case 19200: rate
= ftdi_sio_b19200
; break;
505 case 38400: rate
= ftdi_sio_b38400
; break;
506 case 57600: rate
= ftdi_sio_b57600
; break;
507 case 115200: rate
= ftdi_sio_b115200
; break;
513 case UFTDI_TYPE_8U232AM
:
514 switch(t
->c_ospeed
) {
515 case 300: rate
= ftdi_8u232am_b300
; break;
516 case 600: rate
= ftdi_8u232am_b600
; break;
517 case 1200: rate
= ftdi_8u232am_b1200
; break;
518 case 2400: rate
= ftdi_8u232am_b2400
; break;
519 case 4800: rate
= ftdi_8u232am_b4800
; break;
520 case 9600: rate
= ftdi_8u232am_b9600
; break;
521 case 19200: rate
= ftdi_8u232am_b19200
; break;
522 case 38400: rate
= ftdi_8u232am_b38400
; break;
523 case 57600: rate
= ftdi_8u232am_b57600
; break;
524 case 115200: rate
= ftdi_8u232am_b115200
; break;
525 case 230400: rate
= ftdi_8u232am_b230400
; break;
526 case 460800: rate
= ftdi_8u232am_b460800
; break;
527 case 921600: rate
= ftdi_8u232am_b921600
; break;
536 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
537 req
.bRequest
= FTDI_SIO_SET_BAUD_RATE
;
538 USETW(req
.wValue
, rate
);
539 USETW(req
.wIndex
, portno
);
540 USETW(req
.wLength
, 0);
541 DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
542 "index=0x%04x len=%d\n", req
.bmRequestType
, req
.bRequest
,
543 UGETW(req
.wValue
), UGETW(req
.wIndex
), UGETW(req
.wLength
)));
544 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);
548 if (ISSET(t
->c_cflag
, CSTOPB
))
549 data
= FTDI_SIO_SET_DATA_STOP_BITS_2
;
551 data
= FTDI_SIO_SET_DATA_STOP_BITS_1
;
552 if (ISSET(t
->c_cflag
, PARENB
)) {
553 if (ISSET(t
->c_cflag
, PARODD
))
554 data
|= FTDI_SIO_SET_DATA_PARITY_ODD
;
556 data
|= FTDI_SIO_SET_DATA_PARITY_EVEN
;
558 data
|= FTDI_SIO_SET_DATA_PARITY_NONE
;
559 switch (ISSET(t
->c_cflag
, CSIZE
)) {
561 data
|= FTDI_SIO_SET_DATA_BITS(5);
564 data
|= FTDI_SIO_SET_DATA_BITS(6);
567 data
|= FTDI_SIO_SET_DATA_BITS(7);
570 data
|= FTDI_SIO_SET_DATA_BITS(8);
575 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
576 req
.bRequest
= FTDI_SIO_SET_DATA
;
577 USETW(req
.wValue
, data
);
578 USETW(req
.wIndex
, portno
);
579 USETW(req
.wLength
, 0);
580 DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
581 "index=0x%04x len=%d\n", req
.bmRequestType
, req
.bRequest
,
582 UGETW(req
.wValue
), UGETW(req
.wIndex
), UGETW(req
.wLength
)));
583 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);
587 if (ISSET(t
->c_cflag
, CRTSCTS
)) {
588 flow
= FTDI_SIO_RTS_CTS_HS
;
589 USETW(req
.wValue
, 0);
590 } else if (ISSET(t
->c_iflag
, IXON
|IXOFF
)) {
591 flow
= FTDI_SIO_XON_XOFF_HS
;
592 USETW2(req
.wValue
, t
->c_cc
[VSTOP
], t
->c_cc
[VSTART
]);
594 flow
= FTDI_SIO_DISABLE_FLOW_CTRL
;
595 USETW(req
.wValue
, 0);
597 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
598 req
.bRequest
= FTDI_SIO_SET_FLOW_CTRL
;
599 USETW2(req
.wIndex
, flow
, portno
);
600 USETW(req
.wLength
, 0);
601 err
= usbd_do_request(sc
->sc_udev
, &req
, NULL
);
609 uftdi_get_status(void *vsc
, int portno
, u_char
*lsr
, u_char
*msr
)
611 struct uftdi_softc
*sc
= vsc
;
613 DPRINTF(("uftdi_status: msr=0x%02x lsr=0x%02x\n",
614 sc
->sc_msr
, sc
->sc_lsr
));
623 uftdi_break(void *vsc
, int portno
, int onoff
)
625 struct uftdi_softc
*sc
= vsc
;
626 usb_device_request_t req
;
629 DPRINTF(("uftdi_break: sc=%p, port=%d onoff=%d\n", vsc
, portno
,
633 data
= sc
->last_lcr
| FTDI_SIO_SET_BREAK
;
638 req
.bmRequestType
= UT_WRITE_VENDOR_DEVICE
;
639 req
.bRequest
= FTDI_SIO_SET_DATA
;
640 USETW(req
.wValue
, data
);
641 USETW(req
.wIndex
, portno
);
642 USETW(req
.wLength
, 0);
643 (void)usbd_do_request(sc
->sc_udev
, &req
, NULL
);