68#include <sys/stdint.h>
69#include <sys/stddef.h>
74#include <sys/kernel.h>
76#include <sys/module.h>
79#include <sys/condvar.h>
80#include <sys/sysctl.h>
82#include <sys/unistd.h>
83#include <sys/callout.h>
84#include <sys/malloc.h>
92#define USB_DEBUG_VAR uchcom_debug
99static int uchcom_debug = 0;
101static SYSCTL_NODE(_hw_usb, OID_AUTO, uchcom, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
104 &uchcom_debug, 0,
"uchcom debug level");
107#define UCHCOM_IFACE_INDEX 0
108#define UCHCOM_CONFIG_INDEX 0
110#define UCHCOM_REV_CH340 0x0250
111#define UCHCOM_INPUT_BUF_SIZE 8
113#define UCHCOM_REQ_GET_VERSION 0x5F
114#define UCHCOM_REQ_READ_REG 0x95
115#define UCHCOM_REQ_WRITE_REG 0x9A
116#define UCHCOM_REQ_RESET 0xA1
117#define UCHCOM_REQ_SET_DTRRTS 0xA4
119#define UCHCOM_REG_STAT1 0x06
120#define UCHCOM_REG_STAT2 0x07
121#define UCHCOM_REG_BPS_PRE 0x12
122#define UCHCOM_REG_BPS_DIV 0x13
123#define UCHCOM_REG_BPS_MOD 0x14
124#define UCHCOM_REG_BPS_PAD 0x0F
125#define UCHCOM_REG_BREAK1 0x05
126#define UCHCOM_REG_LCR1 0x18
127#define UCHCOM_REG_LCR2 0x25
129#define UCHCOM_VER_20 0x20
130#define UCHCOM_VER_30 0x30
132#define UCHCOM_BASE_UNKNOWN 0
133#define UCHCOM_BPS_MOD_BASE 20000000
134#define UCHCOM_BPS_MOD_BASE_OFS 1100
136#define UCHCOM_DTR_MASK 0x20
137#define UCHCOM_RTS_MASK 0x40
139#define UCHCOM_BRK_MASK 0x01
141#define UCHCOM_LCR1_MASK 0xAF
142#define UCHCOM_LCR2_MASK 0x07
143#define UCHCOM_LCR1_RX 0x80
144#define UCHCOM_LCR1_TX 0x40
145#define UCHCOM_LCR1_PARENB 0x08
146#define UCHCOM_LCR1_CS8 0x03
147#define UCHCOM_LCR2_PAREVEN 0x07
148#define UCHCOM_LCR2_PARODD 0x06
149#define UCHCOM_LCR2_PARMARK 0x05
150#define UCHCOM_LCR2_PARSPACE 0x04
152#define UCHCOM_INTR_STAT1 0x02
153#define UCHCOM_INTR_STAT2 0x03
154#define UCHCOM_INTR_LEAST 4
156#define UCHCOM_BULK_BUF_SIZE 1024
197 {2999999, 23530, 6000000, {3, 0, 0}},
198 {23529, 2942, 750000, {2, 0, 0}},
199 {2941, 368, 93750, {1, 0, 0}},
200 {367, 1, 11719, {0, 0, 0}},
203#define NUM_DIVIDERS nitems(dividers)
206 {
USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)},
207 {
USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)},
208 {
USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER_2, 0)},
249 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
258 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
266 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
322 mtx_init(&sc->
sc_mtx,
"uchcom", NULL, MTX_DEF);
328 case USB_PRODUCT_WCH2_CH341SER:
329 device_printf(
dev,
"CH340 detected\n");
331 case USB_PRODUCT_WCH2_CH341SER_2:
332 case USB_PRODUCT_WCH2_CH341SER_3:
333 device_printf(
dev,
"CH341 detected\n");
336 device_printf(
dev,
"New CH340/CH341 product 0x%04x detected\n",
347 DPRINTF(
"one or more missing USB endpoints, "
382 device_claim_softc(
dev);
396 device_free_softc(sc);
412 uint16_t value, uint16_t index)
417 req.bRequest = reqno;
422 DPRINTF(
"WR REQ 0x%02X VAL 0x%04X IDX 0x%04X\n",
430 uint16_t value, uint16_t index,
void *buf, uint16_t buflen)
435 req.bRequest = reqno;
440 DPRINTF(
"RD REQ 0x%02X VAL 0x%04X IDX 0x%04X LEN %d\n",
448 uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2)
450 DPRINTF(
"0x%02X<-0x%02X, 0x%02X<-0x%02X\n",
451 (
unsigned)reg1, (
unsigned)val1,
452 (
unsigned)reg2, (
unsigned)val2);
455 reg1 | ((uint16_t)reg2 << 8), val1 | ((uint16_t)val2 << 8));
460 uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2)
466 reg1 | ((uint16_t)reg2 << 8), 0, buf,
sizeof(buf));
468 DPRINTF(
"0x%02X->0x%02X, 0x%02X->0x%02X\n",
469 (
unsigned)reg1, (
unsigned)buf[0],
470 (
unsigned)reg2, (
unsigned)buf[1]);
563 brk1 &= ~UCHCOM_BRK_MASK;
564 brk2 &= ~UCHCOM_LCR1_TX;
599 if (div == 0 || div >= 0xFF)
601 if ((rem << 1) >= rate)
603 dp->
dv_div = (uint8_t)-div;
607 mod = mod + (mod / 2);
609 dp->
dv_mod = (mod + 0xFF) / 0x100;
654 DPRINTF(
"onoff = %d\n", onoff);
665 DPRINTF(
"onoff = %d\n", onoff);
687 switch (t->c_cflag & CSIZE) {
693 if ((t->c_cflag & CSTOPB) != 0)
695 if ((t->c_cflag & PARENB) != 0)
792 DPRINTF(
"actlen = %u\n", actlen);
798 DPRINTF(
"data = 0x%02X 0x%02X 0x%02X 0x%02X\n",
799 (
unsigned)buf[0], (
unsigned)buf[1],
800 (
unsigned)buf[2], (
unsigned)buf[3]);
835 DPRINTF(
"actlen = %d\n", actlen);
static SYSCTL_NODE(_hw_usb, OID_AUTO, dwc_otg, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "USB DWC OTG")
SYSCTL_INT(_hw_usb_dwc_otg, OID_AUTO, phy_type, CTLFLAG_RDTUN, &dwc_otg_phy_type, 0, "DWC OTG PHY TYPE - 0/1/2/3 - ULPI/HSIC/INTERNAL/UTMI+")
struct uchcom_divider dvr_divider
struct ucom_softc sc_ucom
struct ucom_super_softc sc_super_ucom
struct usb_device * sc_udev
struct usb_xfer * sc_xfer[UCHCOM_N_TRANSFER]
void(* ucom_cfg_get_status)(struct ucom_softc *, uint8_t *plsr, uint8_t *pmsr)
enum usb_hc_mode usb_mode
struct usbd_lookup_info info
struct usb_device * device
static void uchcom_update_version(struct uchcom_softc *)
static device_method_t uchcom_methods[]
static int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t)
#define UCHCOM_REG_BPS_DIV
#define UCHCOM_BPS_MOD_BASE
static const struct usb_config uchcom_config_data[UCHCOM_N_TRANSFER]
#define UCHCOM_REG_BPS_PRE
static driver_t uchcom_driver
static void uchcom_ctrl_write(struct uchcom_softc *sc, uint8_t reqno, uint16_t value, uint16_t index)
#define UCHCOM_REG_BREAK1
static void uchcom_cfg_open(struct ucom_softc *ucom)
static void uchcom_stop_read(struct ucom_softc *)
UCOM_UNLOAD_DRAIN(uchcom)
static void uchcom_free(struct ucom_softc *)
static void uchcom_update_status(struct uchcom_softc *)
static usb_callback_t uchcom_intr_callback
static int uchcom_pre_param(struct ucom_softc *, struct termios *)
static void uchcom_cfg_param(struct ucom_softc *, struct termios *)
static void uchcom_read_reg(struct uchcom_softc *sc, uint8_t reg1, uint8_t *rval1, uint8_t reg2, uint8_t *rval2)
MODULE_VERSION(uchcom, 1)
#define UCHCOM_REG_BPS_PAD
#define UCHCOM_CONFIG_INDEX
static usb_callback_t uchcom_read_callback
static void uchcom_get_version(struct uchcom_softc *sc, uint8_t *rver)
static void uchcom_cfg_get_status(struct ucom_softc *, uint8_t *, uint8_t *)
static device_detach_t uchcom_detach
#define UCHCOM_REQ_GET_VERSION
static void uchcom_get_status(struct uchcom_softc *sc, uint8_t *rval)
static void uchcom_set_dtr_rts_20(struct uchcom_softc *sc, uint8_t val)
static device_probe_t uchcom_probe
static void uchcom_free_softc(struct uchcom_softc *)
static struct ucom_callback uchcom_callback
static void uchcom_cfg_set_dtr(struct ucom_softc *, uint8_t)
#define UCHCOM_REQ_READ_REG
static void uchcom_ctrl_read(struct uchcom_softc *sc, uint8_t reqno, uint16_t value, uint16_t index, void *buf, uint16_t buflen)
#define UCHCOM_BASE_UNKNOWN
static void uchcom_cfg_set_rts(struct ucom_softc *, uint8_t)
#define UCHCOM_IFACE_INDEX
static void uchcom_set_dtr_rts_10(struct uchcom_softc *sc, uint8_t val)
static const STRUCT_USB_HOST_ID uchcom_devs[]
static void uchcom_set_baudrate(struct uchcom_softc *, uint32_t)
static devclass_t uchcom_devclass
static void uchcom_start_write(struct ucom_softc *)
static device_attach_t uchcom_attach
#define UCHCOM_INTR_LEAST
static void uchcom_cfg_set_break(struct ucom_softc *, uint8_t)
static void uchcom_convert_status(struct uchcom_softc *, uint8_t)
#define UCHCOM_INPUT_BUF_SIZE
static void uchcom_start_read(struct ucom_softc *)
DRIVER_MODULE(uchcom, uhub, uchcom_driver, uchcom_devclass, NULL, 0)
static const struct uchcom_divider_record dividers[]
MODULE_DEPEND(uchcom, ucom, 1, 1, 1)
static void uchcom_stop_write(struct ucom_softc *)
#define UCHCOM_REQ_WRITE_REG
static void uchcom_poll(struct ucom_softc *ucom)
#define UCHCOM_REG_BPS_MOD
#define UCHCOM_REQ_SET_DTRRTS
static usb_callback_t uchcom_write_callback
static void uchcom_write_reg(struct uchcom_softc *sc, uint8_t reg1, uint8_t val1, uint8_t reg2, uint8_t val2)
#define UCHCOM_BPS_MOD_BASE_OFS
#define UCHCOM_INTR_STAT1
static void uchcom_set_dtr_rts(struct uchcom_softc *)
USB_PNP_HOST_INFO(uchcom_devs)
#define UCHCOM_BULK_BUF_SIZE
#define UT_WRITE_VENDOR_DEVICE
#define UT_READ_VENDOR_DEVICE
void usbd_copy_out(struct usb_page_cache *cache, usb_frlength_t offset, void *ptr, usb_frlength_t len)
const char * usbd_errstr(usb_error_t err)
int usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, struct usb_attach_arg *uaa)
uint8_t ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len, uint32_t *actlen)
void ucom_status_change(struct ucom_softc *sc)
int ucom_attach(struct ucom_super_softc *ssc, struct ucom_softc *sc, int subunits, void *parent, const struct ucom_callback *callback, struct mtx *mtx)
int ucom_unref(struct ucom_super_softc *ssc)
void ucom_ref(struct ucom_super_softc *ssc)
void ucom_set_pnpinfo_usb(struct ucom_super_softc *ssc, device_t dev)
void ucom_detach(struct ucom_super_softc *ssc, struct ucom_softc *sc)
void ucom_put_data(struct ucom_softc *sc, struct usb_page_cache *pc, uint32_t offset, uint32_t len)
#define ucom_cfg_do_request(udev, com, req, ptr, flags, timo)
void usbd_transfer_submit(struct usb_xfer *xfer)
void usbd_transfer_unsetup(struct usb_xfer **pxfer, uint16_t n_setup)
void usbd_xfer_set_frame_len(struct usb_xfer *xfer, usb_frcount_t frindex, usb_frlength_t len)
struct usb_page_cache * usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex)
usb_error_t usbd_transfer_setup(struct usb_device *udev, const uint8_t *ifaces, struct usb_xfer **ppxfer, const struct usb_config *setup_start, uint16_t n_setup, void *priv_sc, struct mtx *xfer_mtx)
void usbd_transfer_start(struct usb_xfer *xfer)
void usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max)
void * usbd_xfer_softc(struct usb_xfer *xfer)
void usbd_xfer_set_stall(struct usb_xfer *xfer)
void usbd_transfer_stop(struct usb_xfer *xfer)
void usbd_xfer_status(struct usb_xfer *xfer, int *actlen, int *sumlen, int *aframes, int *nframes)
usb_frlength_t usbd_xfer_max_len(struct usb_xfer *xfer)
void device_set_usb_desc(device_t dev)
#define USB_SHORT_XFER_OK
#define USB_ST_TRANSFERRED
void() usb_callback_t(struct usb_xfer *, usb_error_t)
#define USB_VPI(vend, prod, info)
#define STRUCT_USB_HOST_ID
#define USB_GET_STATE(xfer)