Deleted Added
full compact
1/* $OpenBSD: uslcom.c,v 1.17 2007/11/24 10:52:12 jsg Exp $ */
2
3#include <sys/cdefs.h>
4__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 239180 2012-08-10 15:29:41Z hselasky $");
4__FBSDID("$FreeBSD: head/sys/dev/usb/serial/uslcom.c 239260 2012-08-14 22:21:46Z gavin $");
5
6/*
7 * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * Driver for Silicon Laboratories CP2101/CP2102/CP2103/CP2104/CP2105
24 * USB-Serial adapters. Based on datasheet AN571, publicly available from
25 * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN571.pdf
26 */
27
28#include <sys/stdint.h>
29#include <sys/stddef.h>
30#include <sys/param.h>
31#include <sys/queue.h>
32#include <sys/types.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/bus.h>

--- 26 unchanged lines hidden (view full) ---

62static SYSCTL_NODE(_hw_usb, OID_AUTO, uslcom, CTLFLAG_RW, 0, "USB uslcom");
63SYSCTL_INT(_hw_usb_uslcom, OID_AUTO, debug, CTLFLAG_RW,
64 &uslcom_debug, 0, "Debug level");
65#endif
66
67#define USLCOM_BULK_BUF_SIZE 1024
68#define USLCOM_CONFIG_INDEX 0
69
64#define USLCOM_SET_DATA_BITS(x) ((x) << 8)
65
70/* Request types */
71#define USLCOM_WRITE 0x41
72#define USLCOM_READ 0xc1
73
74/* Request codes */
71#define USLCOM_UART 0x00
72#define USLCOM_SET_BAUD_DIV 0x01
73#define USLCOM_DATA 0x03
74#define USLCOM_BREAK 0x05
75#define USLCOM_CTRL 0x07
76#define USLCOM_RCTRL 0x08
77#define USLCOM_SET_FLOWCTRL 0x13
78#define USLCOM_SET_BAUD_RATE 0x1e
75#define USLCOM_IFC_ENABLE 0x00
76#define USLCOM_SET_BAUDDIV 0x01
77#define USLCOM_SET_LINE_CTL 0x03
78#define USLCOM_SET_BREAK 0x05
79#define USLCOM_SET_MHS 0x07
80#define USLCOM_GET_MDMSTS 0x08
81#define USLCOM_SET_FLOW 0x13
82#define USLCOM_SET_BAUDRATE 0x1e
83#define USLCOM_VENDOR_SPECIFIC 0xff
84
81/* USLCOM_UART values */
82#define USLCOM_UART_DISABLE 0x00
83#define USLCOM_UART_ENABLE 0x01
85/* USLCOM_IFC_ENABLE values */
86#define USLCOM_IFC_ENABLE_DIS 0x00
87#define USLCOM_IFC_ENABLE_EN 0x01
88
85/* USLCOM_CTRL/USLCOM_RCTRL values */
86#define USLCOM_CTRL_DTR_ON 0x0001
87#define USLCOM_CTRL_DTR_SET 0x0100
88#define USLCOM_CTRL_RTS_ON 0x0002
89#define USLCOM_CTRL_RTS_SET 0x0200
90#define USLCOM_CTRL_CTS 0x0010
91#define USLCOM_CTRL_DSR 0x0020
92#define USLCOM_CTRL_RI 0x0040
93#define USLCOM_CTRL_DCD 0x0080
89/* USLCOM_SET_MHS/USLCOM_GET_MDMSTS values */
90#define USLCOM_MHS_DTR_ON 0x0001
91#define USLCOM_MHS_DTR_SET 0x0100
92#define USLCOM_MHS_RTS_ON 0x0002
93#define USLCOM_MHS_RTS_SET 0x0200
94#define USLCOM_MHS_CTS 0x0010
95#define USLCOM_MHS_DSR 0x0020
96#define USLCOM_MHS_RI 0x0040
97#define USLCOM_MHS_DCD 0x0080
98
95/* USLCOM_SET_BAUD_DIV values */
96#define USLCOM_BAUD_REF 3686400 /* 3.6864 MHz */
99/* USLCOM_SET_BAUDDIV values */
100#define USLCOM_BAUDDIV_REF 3686400 /* 3.6864 MHz */
101
98/* USLCOM_DATA values */
102/* USLCOM_SET_LINE_CTL values */
103#define USLCOM_STOP_BITS_1 0x00
104#define USLCOM_STOP_BITS_2 0x02
105#define USLCOM_PARITY_NONE 0x00
106#define USLCOM_PARITY_ODD 0x10
107#define USLCOM_PARITY_EVEN 0x20
108#define USLCOM_SET_DATA_BITS(x) ((x) << 8)
109
105/* USLCOM_BREAK values */
106#define USLCOM_BREAK_OFF 0x00
107#define USLCOM_BREAK_ON 0x01
110/* USLCOM_SET_BREAK values */
111#define USLCOM_SET_BREAK_OFF 0x00
112#define USLCOM_SET_BREAK_ON 0x01
113
109/* USLCOM_SET_FLOWCTRL values - 1st word */
114/* USLCOM_SET_FLOW values - 1st word */
115#define USLCOM_FLOW_DTR_ON 0x00000001 /* DTR static active */
116#define USLCOM_FLOW_CTS_HS 0x00000008 /* CTS handshake */
112/* USLCOM_SET_FLOWCTRL values - 2nd word */
117/* USLCOM_SET_FLOW values - 2nd word */
118#define USLCOM_FLOW_RTS_ON 0x00000040 /* RTS static active */
119#define USLCOM_FLOW_RTS_HS 0x00000080 /* RTS handshake */
120
121/* USLCOM_VENDOR_SPECIFIC values */
122#define USLCOM_WRITE_LATCH 0x37E1
123#define USLCOM_READ_LATCH 0x00C2
124
125enum {

--- 334 unchanged lines hidden (view full) ---

460
461static void
462uslcom_open(struct ucom_softc *ucom)
463{
464 struct uslcom_softc *sc = ucom->sc_parent;
465 struct usb_device_request req;
466
467 req.bmRequestType = USLCOM_WRITE;
463 req.bRequest = USLCOM_UART;
464 USETW(req.wValue, USLCOM_UART_ENABLE);
468 req.bRequest = USLCOM_IFC_ENABLE;
469 USETW(req.wValue, USLCOM_IFC_ENABLE_EN);
470 USETW(req.wIndex, sc->sc_iface_no);
471 USETW(req.wLength, 0);
472
473 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
474 &req, NULL, 0, 1000)) {
475 DPRINTF("UART enable failed (ignored)\n");
476 }
477

--- 6 unchanged lines hidden (view full) ---

484{
485 struct uslcom_softc *sc = ucom->sc_parent;
486 struct usb_device_request req;
487
488 /* stop polling status */
489 usb_callout_stop(&sc->sc_watchdog);
490
491 req.bmRequestType = USLCOM_WRITE;
487 req.bRequest = USLCOM_UART;
488 USETW(req.wValue, USLCOM_UART_DISABLE);
492 req.bRequest = USLCOM_IFC_ENABLE;
493 USETW(req.wValue, USLCOM_IFC_ENABLE_DIS);
494 USETW(req.wIndex, sc->sc_iface_no);
495 USETW(req.wLength, 0);
496
497 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
498 &req, NULL, 0, 1000)) {
499 DPRINTF("UART disable failed (ignored)\n");
500 }
501}
502
503static void
504uslcom_set_dtr(struct ucom_softc *ucom, uint8_t onoff)
505{
506 struct uslcom_softc *sc = ucom->sc_parent;
507 struct usb_device_request req;
508 uint16_t ctl;
509
510 DPRINTF("onoff = %d\n", onoff);
511
507 ctl = onoff ? USLCOM_CTRL_DTR_ON : 0;
508 ctl |= USLCOM_CTRL_DTR_SET;
512 ctl = onoff ? USLCOM_MHS_DTR_ON : 0;
513 ctl |= USLCOM_MHS_DTR_SET;
514
515 req.bmRequestType = USLCOM_WRITE;
511 req.bRequest = USLCOM_CTRL;
516 req.bRequest = USLCOM_SET_MHS;
517 USETW(req.wValue, ctl);
518 USETW(req.wIndex, sc->sc_iface_no);
519 USETW(req.wLength, 0);
520
521 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
522 &req, NULL, 0, 1000)) {
523 DPRINTF("Setting DTR failed (ignored)\n");
524 }
525}
526
527static void
528uslcom_set_rts(struct ucom_softc *ucom, uint8_t onoff)
529{
530 struct uslcom_softc *sc = ucom->sc_parent;
531 struct usb_device_request req;
532 uint16_t ctl;
533
534 DPRINTF("onoff = %d\n", onoff);
535
531 ctl = onoff ? USLCOM_CTRL_RTS_ON : 0;
532 ctl |= USLCOM_CTRL_RTS_SET;
536 ctl = onoff ? USLCOM_MHS_RTS_ON : 0;
537 ctl |= USLCOM_MHS_RTS_SET;
538
539 req.bmRequestType = USLCOM_WRITE;
535 req.bRequest = USLCOM_CTRL;
540 req.bRequest = USLCOM_SET_MHS;
541 USETW(req.wValue, ctl);
542 USETW(req.wIndex, sc->sc_iface_no);
543 USETW(req.wLength, 0);
544
545 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
546 &req, NULL, 0, 1000)) {
547 DPRINTF("Setting DTR failed (ignored)\n");
548 }

--- 14 unchanged lines hidden (view full) ---

563 struct usb_device_request req;
564 uint32_t baudrate, flowctrl[4];
565 uint16_t data;
566
567 DPRINTF("\n");
568
569 baudrate = t->c_ospeed;
570 req.bmRequestType = USLCOM_WRITE;
566 req.bRequest = USLCOM_SET_BAUD_RATE;
571 req.bRequest = USLCOM_SET_BAUDRATE;
572 USETW(req.wValue, 0);
573 USETW(req.wIndex, sc->sc_iface_no);
574 USETW(req.wLength, sizeof(baudrate));
575
576 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
577 &req, &baudrate, 0, 1000)) {
578 DPRINTF("Set baudrate failed (ignored)\n");
579 }

--- 20 unchanged lines hidden (view full) ---

600 data |= USLCOM_SET_DATA_BITS(7);
601 break;
602 case CS8:
603 data |= USLCOM_SET_DATA_BITS(8);
604 break;
605 }
606
607 req.bmRequestType = USLCOM_WRITE;
603 req.bRequest = USLCOM_DATA;
608 req.bRequest = USLCOM_SET_LINE_CTL;
609 USETW(req.wValue, data);
610 USETW(req.wIndex, sc->sc_iface_no);
611 USETW(req.wLength, 0);
612
613 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
614 &req, NULL, 0, 1000)) {
615 DPRINTF("Set format failed (ignored)\n");
616 }
617
618 if (t->c_cflag & CRTSCTS) {
619 flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON | USLCOM_FLOW_CTS_HS);
620 flowctrl[1] = htole32(USLCOM_FLOW_RTS_HS);
616 flowctrl[2] = 0;
617 flowctrl[3] = 0;
621 } else {
622 flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON);
623 flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON);
621 flowctrl[2] = 0;
622 flowctrl[3] = 0;
624 }
625 flowctrl[2] = 0;
626 flowctrl[3] = 0;
627 req.bmRequestType = USLCOM_WRITE;
625 req.bRequest = USLCOM_SET_FLOWCTRL;
628 req.bRequest = USLCOM_SET_FLOW;
629 USETW(req.wValue, 0);
630 USETW(req.wIndex, sc->sc_iface_no);
631 USETW(req.wLength, sizeof(flowctrl));
632
633 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
634 &req, flowctrl, 0, 1000)) {
635 DPRINTF("Set flowcontrol failed (ignored)\n");
636 }

--- 10 unchanged lines hidden (view full) ---

647 *msr = sc->sc_msr;
648}
649
650static void
651uslcom_set_break(struct ucom_softc *ucom, uint8_t onoff)
652{
653 struct uslcom_softc *sc = ucom->sc_parent;
654 struct usb_device_request req;
652 uint16_t brk = onoff ? USLCOM_BREAK_ON : USLCOM_BREAK_OFF;
655 uint16_t brk = onoff ? USLCOM_SET_BREAK_ON : USLCOM_SET_BREAK_OFF;
656
657 req.bmRequestType = USLCOM_WRITE;
655 req.bRequest = USLCOM_BREAK;
658 req.bRequest = USLCOM_SET_BREAK;
659 USETW(req.wValue, brk);
660 USETW(req.wIndex, sc->sc_iface_no);
661 USETW(req.wLength, 0);
662
663 if (ucom_cfg_do_request(sc->sc_udev, &sc->sc_ucom,
664 &req, NULL, 0, 1000)) {
665 DPRINTF("Set BREAK failed (ignored)\n");
666 }

--- 118 unchanged lines hidden (view full) ---

785 struct usb_device_request req;
786 uint8_t msr = 0;
787 uint8_t buf;
788
789 switch (USB_GET_STATE(xfer)) {
790 case USB_ST_TRANSFERRED:
791 pc = usbd_xfer_get_frame(xfer, 1);
792 usbd_copy_out(pc, 0, &buf, sizeof(buf));
790 if (buf & USLCOM_CTRL_CTS)
793 if (buf & USLCOM_MHS_CTS)
794 msr |= SER_CTS;
792 if (buf & USLCOM_CTRL_DSR)
795 if (buf & USLCOM_MHS_DSR)
796 msr |= SER_DSR;
794 if (buf & USLCOM_CTRL_RI)
797 if (buf & USLCOM_MHS_RI)
798 msr |= SER_RI;
796 if (buf & USLCOM_CTRL_DCD)
799 if (buf & USLCOM_MHS_DCD)
800 msr |= SER_DCD;
801
802 if (msr != sc->sc_msr) {
803 DPRINTF("status change msr=0x%02x "
804 "(was 0x%02x)\n", msr, sc->sc_msr);
805 sc->sc_msr = msr;
806 ucom_status_change(&sc->sc_ucom);
807 }
808 break;
809
810 case USB_ST_SETUP:
811 req.bmRequestType = USLCOM_READ;
809 req.bRequest = USLCOM_RCTRL;
812 req.bRequest = USLCOM_GET_MDMSTS;
813 USETW(req.wValue, 0);
814 USETW(req.wIndex, sc->sc_iface_no);
815 USETW(req.wLength, sizeof(buf));
816
817 usbd_xfer_set_frames(xfer, 2);
818 usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
819 usbd_xfer_set_frame_len(xfer, 1, sizeof(buf));
820

--- 52 unchanged lines hidden ---