This source file includes following definitions.
- uftdi_match
- uftdi_attach
- uftdi_activate
- uftdi_detach
- uftdi_open
- uftdi_read
- uftdi_write
- uftdi_set
- uftdi_param
- uftdi_get_status
- uftdi_break
- uftdi_8u232am_getrate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/device.h>
53 #include <sys/conf.h>
54 #include <sys/tty.h>
55
56 #include <dev/usb/usb.h>
57 #include <dev/usb/usbhid.h>
58
59 #include <dev/usb/usbdi.h>
60 #include <dev/usb/usbdi_util.h>
61 #include <dev/usb/usbdevs.h>
62
63 #include <dev/usb/ucomvar.h>
64
65 #include <dev/usb/uftdireg.h>
66
67 #ifdef UFTDI_DEBUG
68 #define DPRINTF(x) do { if (uftdidebug) printf x; } while (0)
69 #define DPRINTFN(n,x) do { if (uftdidebug>(n)) printf x; } while (0)
70 int uftdidebug = 0;
71 #else
72 #define DPRINTF(x)
73 #define DPRINTFN(n,x)
74 #endif
75
76 #define UFTDI_CONFIG_INDEX 0
77 #define UFTDI_IFACE_INDEX 0
78
79
80
81
82
83
84 #define UFTDIIBUFSIZE 64
85 #define UFTDIOBUFSIZE 64
86
87 struct uftdi_softc {
88 struct device sc_dev;
89 usbd_device_handle sc_udev;
90 usbd_interface_handle sc_iface;
91
92 enum uftdi_type sc_type;
93 u_int sc_hdrlen;
94
95 u_char sc_msr;
96 u_char sc_lsr;
97
98 struct device *sc_subdev;
99
100 u_char sc_dying;
101
102 u_int last_lcr;
103 };
104
105 void uftdi_get_status(void *, int portno, u_char *lsr, u_char *msr);
106 void uftdi_set(void *, int, int, int);
107 int uftdi_param(void *, int, struct termios *);
108 int uftdi_open(void *sc, int portno);
109 void uftdi_read(void *sc, int portno, u_char **ptr,
110 u_int32_t *count);
111 void uftdi_write(void *sc, int portno, u_char *to, u_char *from,
112 u_int32_t *count);
113 void uftdi_break(void *sc, int portno, int onoff);
114 int uftdi_8u232am_getrate(speed_t speed, int *rate);
115
116 struct ucom_methods uftdi_methods = {
117 uftdi_get_status,
118 uftdi_set,
119 uftdi_param,
120 NULL,
121 uftdi_open,
122 NULL,
123 uftdi_read,
124 uftdi_write,
125 };
126
127 int uftdi_match(struct device *, void *, void *);
128 void uftdi_attach(struct device *, struct device *, void *);
129 int uftdi_detach(struct device *, int);
130 int uftdi_activate(struct device *, enum devact);
131
132 struct cfdriver uftdi_cd = {
133 NULL, "uftdi", DV_DULL
134 };
135
136 const struct cfattach uftdi_ca = {
137 sizeof(struct uftdi_softc),
138 uftdi_match,
139 uftdi_attach,
140 uftdi_detach,
141 uftdi_activate,
142 };
143
144 int
145 uftdi_match(struct device *parent, void *match, void *aux)
146 {
147 struct usb_attach_arg *uaa = aux;
148
149 if (uaa->iface != NULL) {
150 if (uaa->vendor == USB_VENDOR_FTDI &&
151 (uaa->product == USB_PRODUCT_FTDI_SERIAL_2232C))
152 return (UMATCH_VENDOR_IFACESUBCLASS);
153 return (UMATCH_NONE);
154 }
155
156 DPRINTFN(20,("uftdi: vendor=0x%x, product=0x%x\n",
157 uaa->vendor, uaa->product));
158
159 if (uaa->vendor == USB_VENDOR_FTDI &&
160 (uaa->product == USB_PRODUCT_FTDI_SERIAL_8U100AX ||
161 uaa->product == USB_PRODUCT_FTDI_SERIAL_8U232AM ||
162 uaa->product == USB_PRODUCT_FTDI_SERIAL_232BM ||
163 uaa->product == USB_PRODUCT_FTDI_SEMC_DSS20 ||
164 uaa->product == USB_PRODUCT_FTDI_MHAM_KW ||
165 uaa->product == USB_PRODUCT_FTDI_MHAM_YS ||
166 uaa->product == USB_PRODUCT_FTDI_MHAM_Y6 ||
167 uaa->product == USB_PRODUCT_FTDI_MHAM_Y8 ||
168 uaa->product == USB_PRODUCT_FTDI_MHAM_IC ||
169 uaa->product == USB_PRODUCT_FTDI_MHAM_DB9 ||
170 uaa->product == USB_PRODUCT_FTDI_MHAM_RS232 ||
171 uaa->product == USB_PRODUCT_FTDI_MHAM_Y9 ||
172 uaa->product == USB_PRODUCT_FTDI_COASTAL_TNCX ||
173 uaa->product == USB_PRODUCT_FTDI_LCD_LK202_24 ||
174 uaa->product == USB_PRODUCT_FTDI_LCD_LK204_24 ||
175 uaa->product == USB_PRODUCT_FTDI_LCD_MX200 ||
176 uaa->product == USB_PRODUCT_FTDI_LCD_CFA_631 ||
177 uaa->product == USB_PRODUCT_FTDI_LCD_CFA_632 ||
178 uaa->product == USB_PRODUCT_FTDI_LCD_CFA_633 ||
179 uaa->product == USB_PRODUCT_FTDI_LCD_CFA_634 ||
180 uaa->product == USB_PRODUCT_FTDI_MJS_SIRIUS_PC))
181 return (UMATCH_VENDOR_PRODUCT);
182 if (uaa->vendor == USB_VENDOR_SIIG2 &&
183 (uaa->product == USB_PRODUCT_SIIG2_US2308))
184 return (UMATCH_VENDOR_PRODUCT);
185 if (uaa->vendor == USB_VENDOR_INTREPIDCS &&
186 (uaa->product == USB_PRODUCT_INTREPIDCS_VALUECAN ||
187 uaa->product == USB_PRODUCT_INTREPIDCS_NEOVI))
188 return (UMATCH_VENDOR_PRODUCT);
189 if (uaa->vendor == USB_VENDOR_BBELECTRONICS &&
190 (uaa->product == USB_PRODUCT_BBELECTRONICS_USOTL4))
191 return (UMATCH_VENDOR_PRODUCT);
192 if (uaa->vendor == USB_VENDOR_FALCOM &&
193 (uaa->product == USB_PRODUCT_FALCOM_TWIST ||
194 uaa->product == USB_PRODUCT_FALCOM_SAMBA))
195 return (UMATCH_VENDOR_PRODUCT);
196 if (uaa->vendor == USB_VENDOR_SEALEVEL &&
197 uaa->product == USB_PRODUCT_SEALEVEL_USBSERIAL)
198 return (UMATCH_VENDOR_PRODUCT);
199
200 return (UMATCH_NONE);
201 }
202
203 void
204 uftdi_attach(struct device *parent, struct device *self, void *aux)
205 {
206 struct uftdi_softc *sc = (struct uftdi_softc *)self;
207 struct usb_attach_arg *uaa = aux;
208 usbd_device_handle dev = uaa->device;
209 usbd_interface_handle iface;
210 usb_interface_descriptor_t *id;
211 usb_endpoint_descriptor_t *ed;
212 char *devinfop;
213 char *devname = sc->sc_dev.dv_xname;
214 int i;
215 usbd_status err;
216 struct ucom_attach_args uca;
217
218 DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc));
219
220 if (uaa->iface == NULL) {
221
222 err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1);
223 if (err) {
224 printf("\n%s: failed to set configuration, err=%s\n",
225 devname, usbd_errstr(err));
226 goto bad;
227 }
228
229 err = usbd_device2interface_handle(dev, UFTDI_IFACE_INDEX, &iface);
230 if (err) {
231 printf("\n%s: failed to get interface, err=%s\n",
232 devname, usbd_errstr(err));
233 goto bad;
234 }
235 } else
236 iface = uaa->iface;
237
238 devinfop = usbd_devinfo_alloc(dev, 0);
239 printf("\n%s: %s\n", devname, devinfop);
240 usbd_devinfo_free(devinfop);
241
242 id = usbd_get_interface_descriptor(iface);
243
244 sc->sc_udev = dev;
245 sc->sc_iface = iface;
246
247 switch (uaa->vendor) {
248 case USB_VENDOR_FTDI:
249 switch (uaa->product) {
250 case USB_PRODUCT_FTDI_SERIAL_8U100AX:
251 sc->sc_type = UFTDI_TYPE_SIO;
252 sc->sc_hdrlen = 1;
253 break;
254
255 case USB_PRODUCT_FTDI_SEMC_DSS20:
256 case USB_PRODUCT_FTDI_SERIAL_8U232AM:
257 case USB_PRODUCT_FTDI_SERIAL_2232C:
258 case USB_PRODUCT_FTDI_SERIAL_232BM:
259 case USB_PRODUCT_FTDI_COASTAL_TNCX:
260 case USB_PRODUCT_FTDI_LCD_LK202_24:
261 case USB_PRODUCT_FTDI_LCD_LK204_24:
262 case USB_PRODUCT_FTDI_LCD_MX200:
263 case USB_PRODUCT_FTDI_LCD_CFA_631:
264 case USB_PRODUCT_FTDI_LCD_CFA_632:
265 case USB_PRODUCT_FTDI_LCD_CFA_633:
266 case USB_PRODUCT_FTDI_LCD_CFA_634:
267 case USB_PRODUCT_FTDI_MHAM_KW:
268 case USB_PRODUCT_FTDI_MHAM_YS:
269 case USB_PRODUCT_FTDI_MHAM_Y6:
270 case USB_PRODUCT_FTDI_MHAM_Y8:
271 case USB_PRODUCT_FTDI_MHAM_IC:
272 case USB_PRODUCT_FTDI_MHAM_DB9:
273 case USB_PRODUCT_FTDI_MHAM_RS232:
274 case USB_PRODUCT_FTDI_MHAM_Y9:
275 case USB_PRODUCT_SEALEVEL_USBSERIAL:
276 case USB_PRODUCT_FTDI_MJS_SIRIUS_PC:
277 sc->sc_type = UFTDI_TYPE_8U232AM;
278 sc->sc_hdrlen = 0;
279 break;
280
281 default:
282 goto bad;
283 }
284 break;
285
286 case USB_VENDOR_INTREPIDCS:
287 switch (uaa->product) {
288 case USB_PRODUCT_INTREPIDCS_VALUECAN:
289 case USB_PRODUCT_INTREPIDCS_NEOVI:
290 sc->sc_type = UFTDI_TYPE_8U232AM;
291 sc->sc_hdrlen = 0;
292 break;
293
294 default:
295 goto bad;
296 }
297 break;
298
299 case USB_VENDOR_SIIG2:
300 switch (uaa->product) {
301 case USB_PRODUCT_SIIG2_US2308:
302 sc->sc_type = UFTDI_TYPE_8U232AM;
303 sc->sc_hdrlen = 0;
304 break;
305
306 default:
307 goto bad;
308 }
309 break;
310
311 case USB_VENDOR_BBELECTRONICS:
312 switch( uaa->product ){
313 case USB_PRODUCT_BBELECTRONICS_USOTL4:
314 sc->sc_type = UFTDI_TYPE_8U232AM;
315 sc->sc_hdrlen = 0;
316 break;
317 default:
318 goto bad;
319 }
320 break;
321
322 case USB_VENDOR_FALCOM:
323 switch( uaa->product ){
324 case USB_PRODUCT_FALCOM_TWIST:
325 case USB_PRODUCT_FALCOM_SAMBA:
326 sc->sc_type = UFTDI_TYPE_8U232AM;
327 sc->sc_hdrlen = 0;
328 break;
329 default:
330 goto bad;
331 }
332 break;
333 }
334
335
336 uca.bulkin = uca.bulkout = -1;
337 for (i = 0; i < id->bNumEndpoints; i++) {
338 int addr, dir, attr;
339 ed = usbd_interface2endpoint_descriptor(iface, i);
340 if (ed == NULL) {
341 printf("%s: could not read endpoint descriptor\n",
342 devname);
343 goto bad;
344 }
345
346 addr = ed->bEndpointAddress;
347 dir = UE_GET_DIR(ed->bEndpointAddress);
348 attr = ed->bmAttributes & UE_XFERTYPE;
349 if (dir == UE_DIR_IN && attr == UE_BULK)
350 uca.bulkin = addr;
351 else if (dir == UE_DIR_OUT && attr == UE_BULK)
352 uca.bulkout = addr;
353 else {
354 printf("%s: unexpected endpoint\n", devname);
355 goto bad;
356 }
357 }
358 if (uca.bulkin == -1) {
359 printf("%s: Could not find data bulk in\n",
360 sc->sc_dev.dv_xname);
361 goto bad;
362 }
363 if (uca.bulkout == -1) {
364 printf("%s: Could not find data bulk out\n",
365 sc->sc_dev.dv_xname);
366 goto bad;
367 }
368
369 if (uaa->iface == NULL)
370 uca.portno = FTDI_PIT_SIOA;
371 else
372 uca.portno = FTDI_PIT_SIOA + id->bInterfaceNumber;
373
374 uca.ibufsize = UFTDIIBUFSIZE;
375 uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen;
376 uca.ibufsizepad = UFTDIIBUFSIZE;
377 uca.opkthdrlen = sc->sc_hdrlen;
378 uca.device = dev;
379 uca.iface = iface;
380 uca.methods = &uftdi_methods;
381 uca.arg = sc;
382 uca.info = NULL;
383
384 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
385 &sc->sc_dev);
386
387 DPRINTF(("uftdi: in=0x%x out=0x%x\n", uca.bulkin, uca.bulkout));
388 sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
389
390 return;
391
392 bad:
393 DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
394 sc->sc_dying = 1;
395 }
396
397 int
398 uftdi_activate(struct device *self, enum devact act)
399 {
400 struct uftdi_softc *sc = (struct uftdi_softc *)self;
401 int rv = 0;
402
403 switch (act) {
404 case DVACT_ACTIVATE:
405 break;
406
407 case DVACT_DEACTIVATE:
408 if (sc->sc_subdev != NULL)
409 rv = config_deactivate(sc->sc_subdev);
410 sc->sc_dying = 1;
411 break;
412 }
413 return (rv);
414 }
415
416 int
417 uftdi_detach(struct device *self, int flags)
418 {
419 struct uftdi_softc *sc = (struct uftdi_softc *)self;
420
421 DPRINTF(("uftdi_detach: sc=%p flags=%d\n", sc, flags));
422 sc->sc_dying = 1;
423 if (sc->sc_subdev != NULL) {
424 config_detach(sc->sc_subdev, flags);
425 sc->sc_subdev = NULL;
426 }
427
428 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
429 &sc->sc_dev);
430
431 return (0);
432 }
433
434 int
435 uftdi_open(void *vsc, int portno)
436 {
437 struct uftdi_softc *sc = vsc;
438 usb_device_request_t req;
439 usbd_status err;
440 struct termios t;
441
442 DPRINTF(("uftdi_open: sc=%p\n", sc));
443
444 if (sc->sc_dying)
445 return (EIO);
446
447
448 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
449 req.bRequest = FTDI_SIO_RESET;
450 USETW(req.wValue, FTDI_SIO_RESET_SIO);
451 USETW(req.wIndex, portno);
452 USETW(req.wLength, 0);
453 err = usbd_do_request(sc->sc_udev, &req, NULL);
454 if (err)
455 return (EIO);
456
457
458 t.c_ospeed = 9600;
459 t.c_cflag = CSTOPB | CS8;
460 (void)uftdi_param(sc, portno, &t);
461
462
463 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
464 req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
465 USETW(req.wValue, 0);
466 USETW2(req.wIndex, FTDI_SIO_RTS_CTS_HS, portno);
467 USETW(req.wLength, 0);
468 err = usbd_do_request(sc->sc_udev, &req, NULL);
469 if (err)
470 return (EIO);
471
472 return (0);
473 }
474
475 void
476 uftdi_read(void *vsc, int portno, u_char **ptr, u_int32_t *count)
477 {
478 struct uftdi_softc *sc = vsc;
479 u_char msr, lsr;
480
481 DPRINTFN(15,("uftdi_read: sc=%p, port=%d count=%d\n", sc, portno,
482 *count));
483
484 msr = FTDI_GET_MSR(*ptr);
485 lsr = FTDI_GET_LSR(*ptr);
486
487 #ifdef UFTDI_DEBUG
488 if (*count != 2)
489 DPRINTFN(10,("uftdi_read: sc=%p, port=%d count=%d data[0]="
490 "0x%02x\n", sc, portno, *count, (*ptr)[2]));
491 #endif
492
493 if (sc->sc_msr != msr ||
494 (sc->sc_lsr & FTDI_LSR_MASK) != (lsr & FTDI_LSR_MASK)) {
495 DPRINTF(("uftdi_read: status change msr=0x%02x(0x%02x) "
496 "lsr=0x%02x(0x%02x)\n", msr, sc->sc_msr,
497 lsr, sc->sc_lsr));
498 sc->sc_msr = msr;
499 sc->sc_lsr = lsr;
500 ucom_status_change((struct ucom_softc *)sc->sc_subdev);
501 }
502
503
504 *ptr += 2;
505 *count -= 2;
506 }
507
508 void
509 uftdi_write(void *vsc, int portno, u_char *to, u_char *from, u_int32_t *count)
510 {
511 struct uftdi_softc *sc = vsc;
512
513 DPRINTFN(10,("uftdi_write: sc=%p, port=%d count=%u data[0]=0x%02x\n",
514 vsc, portno, *count, from[0]));
515
516
517 if (sc->sc_hdrlen > 0)
518 *to = FTDI_OUT_TAG(*count, portno);
519
520 memcpy(to + sc->sc_hdrlen, from, *count);
521 *count += sc->sc_hdrlen;
522 }
523
524 void
525 uftdi_set(void *vsc, int portno, int reg, int onoff)
526 {
527 struct uftdi_softc *sc = vsc;
528 usb_device_request_t req;
529 int ctl;
530
531 DPRINTF(("uftdi_set: sc=%p, port=%d reg=%d onoff=%d\n", vsc, portno,
532 reg, onoff));
533
534 switch (reg) {
535 case UCOM_SET_DTR:
536 ctl = onoff ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW;
537 break;
538 case UCOM_SET_RTS:
539 ctl = onoff ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW;
540 break;
541 case UCOM_SET_BREAK:
542 uftdi_break(sc, portno, onoff);
543 return;
544 default:
545 return;
546 }
547 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
548 req.bRequest = FTDI_SIO_MODEM_CTRL;
549 USETW(req.wValue, ctl);
550 USETW(req.wIndex, portno);
551 USETW(req.wLength, 0);
552 DPRINTFN(2,("uftdi_set: reqtype=0x%02x req=0x%02x value=0x%04x "
553 "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
554 UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
555 (void)usbd_do_request(sc->sc_udev, &req, NULL);
556 }
557
558 int
559 uftdi_param(void *vsc, int portno, struct termios *t)
560 {
561 struct uftdi_softc *sc = vsc;
562 usb_device_request_t req;
563 usbd_status err;
564 int rate, data, flow;
565
566 DPRINTF(("uftdi_param: sc=%p\n", sc));
567
568 if (sc->sc_dying)
569 return (EIO);
570
571 switch (sc->sc_type) {
572 case UFTDI_TYPE_SIO:
573 switch (t->c_ospeed) {
574 case 300: rate = ftdi_sio_b300; break;
575 case 600: rate = ftdi_sio_b600; break;
576 case 1200: rate = ftdi_sio_b1200; break;
577 case 2400: rate = ftdi_sio_b2400; break;
578 case 4800: rate = ftdi_sio_b4800; break;
579 case 9600: rate = ftdi_sio_b9600; break;
580 case 19200: rate = ftdi_sio_b19200; break;
581 case 38400: rate = ftdi_sio_b38400; break;
582 case 57600: rate = ftdi_sio_b57600; break;
583 case 115200: rate = ftdi_sio_b115200; break;
584 default:
585 return (EINVAL);
586 }
587 break;
588
589 case UFTDI_TYPE_8U232AM:
590 if (uftdi_8u232am_getrate(t->c_ospeed, &rate) == -1)
591 return (EINVAL);
592 break;
593 }
594 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
595 req.bRequest = FTDI_SIO_SET_BAUD_RATE;
596 USETW(req.wValue, rate);
597 USETW(req.wIndex, portno);
598 USETW(req.wLength, 0);
599 DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
600 "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
601 UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
602 err = usbd_do_request(sc->sc_udev, &req, NULL);
603 if (err)
604 return (EIO);
605
606 if (ISSET(t->c_cflag, CSTOPB))
607 data = FTDI_SIO_SET_DATA_STOP_BITS_2;
608 else
609 data = FTDI_SIO_SET_DATA_STOP_BITS_1;
610 if (ISSET(t->c_cflag, PARENB)) {
611 if (ISSET(t->c_cflag, PARODD))
612 data |= FTDI_SIO_SET_DATA_PARITY_ODD;
613 else
614 data |= FTDI_SIO_SET_DATA_PARITY_EVEN;
615 } else
616 data |= FTDI_SIO_SET_DATA_PARITY_NONE;
617 switch (ISSET(t->c_cflag, CSIZE)) {
618 case CS5:
619 data |= FTDI_SIO_SET_DATA_BITS(5);
620 break;
621 case CS6:
622 data |= FTDI_SIO_SET_DATA_BITS(6);
623 break;
624 case CS7:
625 data |= FTDI_SIO_SET_DATA_BITS(7);
626 break;
627 case CS8:
628 data |= FTDI_SIO_SET_DATA_BITS(8);
629 break;
630 }
631 sc->last_lcr = data;
632
633 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
634 req.bRequest = FTDI_SIO_SET_DATA;
635 USETW(req.wValue, data);
636 USETW(req.wIndex, portno);
637 USETW(req.wLength, 0);
638 DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
639 "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
640 UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
641 err = usbd_do_request(sc->sc_udev, &req, NULL);
642 if (err)
643 return (EIO);
644
645 if (ISSET(t->c_cflag, CRTSCTS)) {
646 flow = FTDI_SIO_RTS_CTS_HS;
647 USETW(req.wValue, 0);
648 } else if (ISSET(t->c_iflag, IXON|IXOFF)) {
649 flow = FTDI_SIO_XON_XOFF_HS;
650 USETW2(req.wValue, t->c_cc[VSTOP], t->c_cc[VSTART]);
651 } else {
652 flow = FTDI_SIO_DISABLE_FLOW_CTRL;
653 USETW(req.wValue, 0);
654 }
655 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
656 req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
657 USETW2(req.wIndex, flow, portno);
658 USETW(req.wLength, 0);
659 err = usbd_do_request(sc->sc_udev, &req, NULL);
660 if (err)
661 return (EIO);
662
663 return (0);
664 }
665
666 void
667 uftdi_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
668 {
669 struct uftdi_softc *sc = vsc;
670
671 DPRINTF(("uftdi_status: msr=0x%02x lsr=0x%02x\n",
672 sc->sc_msr, sc->sc_lsr));
673
674 if (msr != NULL)
675 *msr = sc->sc_msr;
676 if (lsr != NULL)
677 *lsr = sc->sc_lsr;
678 }
679
680 void
681 uftdi_break(void *vsc, int portno, int onoff)
682 {
683 struct uftdi_softc *sc = vsc;
684 usb_device_request_t req;
685 int data;
686
687 DPRINTF(("uftdi_break: sc=%p, port=%d onoff=%d\n", vsc, portno,
688 onoff));
689
690 if (onoff) {
691 data = sc->last_lcr | FTDI_SIO_SET_BREAK;
692 } else {
693 data = sc->last_lcr;
694 }
695
696 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
697 req.bRequest = FTDI_SIO_SET_DATA;
698 USETW(req.wValue, data);
699 USETW(req.wIndex, portno);
700 USETW(req.wLength, 0);
701 (void)usbd_do_request(sc->sc_udev, &req, NULL);
702 }
703
704 int
705 uftdi_8u232am_getrate(speed_t speed, int *rate)
706 {
707
708 static const unsigned char roundoff[16] = {
709 0, 2, 2, 4, 4, 4, 8, 8,
710 8, 8, 8, 8, 16, 16, 16, 16,
711 };
712
713 unsigned int d, freq;
714 int result;
715
716 if (speed <= 0)
717 return (-1);
718
719
720 if (speed >= 3000000 * 100 / 103 &&
721 speed <= 3000000 * 100 / 97) {
722 result = 0;
723 goto done;
724 }
725 if (speed >= 2000000 * 100 / 103 &&
726 speed <= 2000000 * 100 / 97) {
727 result = 1;
728 goto done;
729 }
730
731 d = (FTDI_8U232AM_FREQ << 4) / speed;
732 d = (d & ~15) + roundoff[d & 15];
733
734 if (d < FTDI_8U232AM_MIN_DIV)
735 d = FTDI_8U232AM_MIN_DIV;
736 else if (d > FTDI_8U232AM_MAX_DIV)
737 d = FTDI_8U232AM_MAX_DIV;
738
739
740
741
742
743
744 freq = speed * d;
745 if (freq < (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 103 ||
746 freq > (quad_t)(FTDI_8U232AM_FREQ << 4) * 100 / 97)
747 return (-1);
748
749
750
751
752
753
754
755 result = d >> 4;
756 if (d & 8)
757 result |= 0x4000;
758 else if (d & 4)
759 result |= 0x8000;
760 else if (d & 2)
761 result |= 0xc000;
762
763 done:
764 *rate = result;
765 return (0);
766 }