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 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 |
70/* Request types */ 71#define USLCOM_WRITE 0x41 72#define USLCOM_READ 0xc1 73 74/* Request codes */ |
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 |
85/* USLCOM_IFC_ENABLE values */ 86#define USLCOM_IFC_ENABLE_DIS 0x00 87#define USLCOM_IFC_ENABLE_EN 0x01 |
88 |
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 |
99/* USLCOM_SET_BAUDDIV values */ 100#define USLCOM_BAUDDIV_REF 3686400 /* 3.6864 MHz */ |
101 |
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 |
110/* USLCOM_SET_BREAK values */ 111#define USLCOM_SET_BREAK_OFF 0x00 112#define USLCOM_SET_BREAK_ON 0x01 |
113 |
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 */ |
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; |
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; |
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 |
512 ctl = onoff ? USLCOM_MHS_DTR_ON : 0; 513 ctl |= USLCOM_MHS_DTR_SET; |
514 515 req.bmRequestType = USLCOM_WRITE; |
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 |
536 ctl = onoff ? USLCOM_MHS_RTS_ON : 0; 537 ctl |= USLCOM_MHS_RTS_SET; |
538 539 req.bmRequestType = USLCOM_WRITE; |
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; |
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; |
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); |
621 } else { 622 flowctrl[0] = htole32(USLCOM_FLOW_DTR_ON); 623 flowctrl[1] = htole32(USLCOM_FLOW_RTS_ON); |
624 } |
625 flowctrl[2] = 0; 626 flowctrl[3] = 0; |
627 req.bmRequestType = USLCOM_WRITE; |
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; |
655 uint16_t brk = onoff ? USLCOM_SET_BREAK_ON : USLCOM_SET_BREAK_OFF; |
656 657 req.bmRequestType = USLCOM_WRITE; |
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)); |
793 if (buf & USLCOM_MHS_CTS) |
794 msr |= SER_CTS; |
795 if (buf & USLCOM_MHS_DSR) |
796 msr |= SER_DSR; |
797 if (buf & USLCOM_MHS_RI) |
798 msr |= SER_RI; |
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; |
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 --- |