Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Oct 2009 21:52:02 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r198257 - in head/sys/dev/usb: . serial
Message-ID:  <200910192152.n9JLq2Hn016355@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Mon Oct 19 21:52:02 2009
New Revision: 198257
URL: http://svn.freebsd.org/changeset/base/198257

Log:
  Add support for newer WinChipHead CH341 chips, previously in the uch341 driver.
  
  Submitted by:	HPS

Modified:
  head/sys/dev/usb/serial/uchcom.c
  head/sys/dev/usb/usbdevs

Modified: head/sys/dev/usb/serial/uchcom.c
==============================================================================
--- head/sys/dev/usb/serial/uchcom.c	Mon Oct 19 21:43:59 2009	(r198256)
+++ head/sys/dev/usb/serial/uchcom.c	Mon Oct 19 21:52:02 2009	(r198257)
@@ -66,7 +66,8 @@
 __FBSDID("$FreeBSD$");
 
 /*
- * driver for WinChipHead CH341/340, the worst USB-serial chip in the world.
+ * Driver for WinChipHead CH341/340, the worst USB-serial chip in the
+ * world.
  */
 
 #include <sys/stdint.h>
@@ -206,6 +207,7 @@ static const struct uchcom_divider_recor
 
 static const struct usb_device_id uchcom_devs[] = {
 	{USB_VPI(USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341SER, 0)},
+	{USB_VPI(USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341SER, 0)},
 };
 
 /* protypes */
@@ -213,6 +215,7 @@ static const struct usb_device_id uchcom
 static int	uchcom_pre_param(struct ucom_softc *, struct termios *);
 static void	uchcom_cfg_get_status(struct ucom_softc *, uint8_t *,
 		    uint8_t *);
+static void	uchcom_cfg_open(struct ucom_softc *ucom);
 static void	uchcom_cfg_param(struct ucom_softc *, struct termios *);
 static void	uchcom_cfg_set_break(struct ucom_softc *, uint8_t);
 static void	uchcom_cfg_set_dtr(struct ucom_softc *, uint8_t);
@@ -224,12 +227,9 @@ static void	uchcom_stop_write(struct uco
 static void	uchcom_update_version(struct uchcom_softc *);
 static void	uchcom_convert_status(struct uchcom_softc *, uint8_t);
 static void	uchcom_update_status(struct uchcom_softc *);
-static void	uchcom_set_dtrrts(struct uchcom_softc *);
+static void	uchcom_set_dtr_rts(struct uchcom_softc *);
 static int	uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t);
-static void	uchcom_set_dte_rate(struct uchcom_softc *, uint32_t);
-static void	uchcom_set_line_control(struct uchcom_softc *, tcflag_t);
-static void	uchcom_clear_chip(struct uchcom_softc *);
-static void	uchcom_reset_chip(struct uchcom_softc *);
+static void	uchcom_set_baudrate(struct uchcom_softc *, uint32_t);
 static void	uchcom_poll(struct ucom_softc *ucom);
 
 static device_probe_t uchcom_probe;
@@ -275,6 +275,7 @@ static struct ucom_callback uchcom_callb
 	.ucom_cfg_set_dtr = &uchcom_cfg_set_dtr,
 	.ucom_cfg_set_rts = &uchcom_cfg_set_rts,
 	.ucom_cfg_set_break = &uchcom_cfg_set_break,
+	.ucom_cfg_open = &uchcom_cfg_open,
 	.ucom_cfg_param = &uchcom_cfg_param,
 	.ucom_pre_param = &uchcom_pre_param,
 	.ucom_start_read = &uchcom_start_read,
@@ -341,17 +342,6 @@ uchcom_attach(device_t dev)
 		    "error=%s\n", usbd_errstr(error));
 		goto detach;
 	}
-	/*
-	 * Do the initialization during attach so that the system does not
-	 * sleep during open:
-	 */
-	uchcom_update_version(sc);
-	uchcom_clear_chip(sc);
-	uchcom_reset_chip(sc);
-	uchcom_update_status(sc);
-
-	sc->sc_dtr = 1;
-	sc->sc_rts = 1;
 
 	/* clear stall at first run */
 	mtx_lock(&sc->sc_mtx);
@@ -458,8 +448,7 @@ uchcom_get_version(struct uchcom_softc *
 {
 	uint8_t buf[UCHCOM_INPUT_BUF_SIZE];
 
-	uchcom_ctrl_read(
-	    sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof(buf));
+	uchcom_ctrl_read(sc, UCHCOM_REQ_GET_VERSION, 0, 0, buf, sizeof(buf));
 
 	if (rver)
 		*rver = buf[0];
@@ -472,13 +461,13 @@ uchcom_get_status(struct uchcom_softc *s
 }
 
 static void
-uchcom_set_dtrrts_10(struct uchcom_softc *sc, uint8_t val)
+uchcom_set_dtr_rts_10(struct uchcom_softc *sc, uint8_t val)
 {
 	uchcom_write_reg(sc, UCHCOM_REG_STAT1, val, UCHCOM_REG_STAT1, val);
 }
 
 static void
-uchcom_set_dtrrts_20(struct uchcom_softc *sc, uint8_t val)
+uchcom_set_dtr_rts_20(struct uchcom_softc *sc, uint8_t val)
 {
 	uchcom_ctrl_write(sc, UCHCOM_REQ_SET_DTRRTS, val, 0);
 }
@@ -515,7 +504,7 @@ uchcom_update_status(struct uchcom_softc
 
 
 static void
-uchcom_set_dtrrts(struct uchcom_softc *sc)
+uchcom_set_dtr_rts(struct uchcom_softc *sc)
 {
 	uint8_t val = 0;
 
@@ -525,9 +514,9 @@ uchcom_set_dtrrts(struct uchcom_softc *s
 		val |= UCHCOM_RTS_MASK;
 
 	if (sc->sc_version < UCHCOM_VER_20)
-		uchcom_set_dtrrts_10(sc, ~val);
+		uchcom_set_dtr_rts_10(sc, ~val);
 	else
-		uchcom_set_dtrrts_20(sc, ~val);
+		uchcom_set_dtr_rts_20(sc, ~val);
 }
 
 static void
@@ -583,16 +572,16 @@ found:
 		dp->dv_div = (uint8_t)-div;
 	}
 
-	mod = UCHCOM_BPS_MOD_BASE / rate + UCHCOM_BPS_MOD_BASE_OFS;
-	mod = mod + mod / 2;
+	mod = (UCHCOM_BPS_MOD_BASE / rate) + UCHCOM_BPS_MOD_BASE_OFS;
+	mod = mod + (mod / 2);
 
-	dp->dv_mod = mod / 0x100;
+	dp->dv_mod = (mod + 0xFF) / 0x100;
 
 	return (0);
 }
 
 static void
-uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate)
+uchcom_set_baudrate(struct uchcom_softc *sc, uint32_t rate)
 {
 	struct uchcom_divider dv;
 
@@ -607,76 +596,6 @@ uchcom_set_dte_rate(struct uchcom_softc 
 	    UCHCOM_REG_BPS_PAD, 0);
 }
 
-static void
-uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag)
-{
-	uint8_t lcr1 = 0;
-	uint8_t lcr2 = 0;
-
-	uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2);
-
-	lcr1 &= ~UCHCOM_LCR1_MASK;
-	lcr2 &= ~UCHCOM_LCR2_MASK;
-
-	/*
-	 * XXX: it is difficult to handle the line control appropriately:
-	 *   - CS8, !CSTOPB and any parity mode seems ok, but
-	 *   - the chip doesn't have the function to calculate parity
-	 *     in !CS8 mode.
-	 *   - it is unclear that the chip supports CS5,6 mode.
-	 *   - it is unclear how to handle stop bits.
-	 */
-
-	if (cflag & PARENB) {
-		lcr1 |= UCHCOM_LCR1_PARENB;
-		if (cflag & PARODD)
-			lcr2 |= UCHCOM_LCR2_PARODD;
-		else
-			lcr2 |= UCHCOM_LCR2_PAREVEN;
-	}
-	uchcom_write_reg(sc, UCHCOM_REG_LCR1, lcr1, UCHCOM_REG_LCR2, lcr2);
-}
-
-static void
-uchcom_clear_chip(struct uchcom_softc *sc)
-{
-	DPRINTF("\n");
-	uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);
-}
-
-static void
-uchcom_reset_chip(struct uchcom_softc *sc)
-{
-	uint16_t val;
-	uint16_t idx;
-	uint8_t lcr1;
-	uint8_t lcr2;
-	uint8_t pre;
-	uint8_t div;
-	uint8_t mod;
-
-	uchcom_read_reg(sc, UCHCOM_REG_LCR1, &lcr1, UCHCOM_REG_LCR2, &lcr2);
-	uchcom_read_reg(sc, UCHCOM_REG_BPS_PRE, &pre, UCHCOM_REG_BPS_DIV, &div);
-	uchcom_read_reg(sc, UCHCOM_REG_BPS_MOD, &mod, UCHCOM_REG_BPS_PAD, NULL);
-
-	val = 0;
-	idx = 0;
-	val |= (uint16_t)(lcr1 & 0xF0) << 8;
-	val |= 0x01;
-	val |= (uint16_t)(lcr2 & 0x0F) << 8;
-	val |= 0x02;
-	idx |= pre & 0x07;
-	val |= 0x04;
-	idx |= (uint16_t)div << 8;
-	val |= 0x08;
-	idx |= mod & 0xF8;
-	val |= 0x10;
-
-	DPRINTF("reset v=0x%04X, i=0x%04X\n", val, idx);
-
-	uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, val, idx);
-}
-
 /* ----------------------------------------------------------------------
  * methods for ucom
  */
@@ -699,7 +618,7 @@ uchcom_cfg_set_dtr(struct ucom_softc *uc
 	DPRINTF("onoff = %d\n", onoff);
 
 	sc->sc_dtr = onoff;
-	uchcom_set_dtrrts(sc);
+	uchcom_set_dtr_rts(sc);
 }
 
 static void
@@ -710,7 +629,18 @@ uchcom_cfg_set_rts(struct ucom_softc *uc
 	DPRINTF("onoff = %d\n", onoff);
 
 	sc->sc_rts = onoff;
-	uchcom_set_dtrrts(sc);
+	uchcom_set_dtr_rts(sc);
+}
+
+static void
+uchcom_cfg_open(struct ucom_softc *ucom)
+{
+	struct uchcom_softc *sc = ucom->sc_parent;
+
+	DPRINTF("\n");
+
+	uchcom_update_version(sc);
+	uchcom_update_status(sc);
 }
 
 static int
@@ -719,12 +649,10 @@ uchcom_pre_param(struct ucom_softc *ucom
 	struct uchcom_divider dv;
 
 	switch (t->c_cflag & CSIZE) {
-	case CS5:
-	case CS6:
-	case CS7:
-		return (EIO);
-	default:
+	case CS8:
 		break;
+	default:
+		return (EIO);
 	}
 
 	if (uchcom_calc_divider_settings(&dv, t->c_ospeed)) {
@@ -738,8 +666,16 @@ uchcom_cfg_param(struct ucom_softc *ucom
 {
 	struct uchcom_softc *sc = ucom->sc_parent;
 
-	uchcom_set_line_control(sc, t->c_cflag);
-	uchcom_set_dte_rate(sc, t->c_ospeed);
+	uchcom_get_version(sc, 0);
+	uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0, 0);
+	uchcom_set_baudrate(sc, t->c_ospeed);
+	uchcom_read_reg(sc, 0x18, 0, 0x25, 0);
+	uchcom_write_reg(sc, 0x18, 0x50, 0x25, 0x00);
+	uchcom_update_status(sc);
+	uchcom_ctrl_write(sc, UCHCOM_REQ_RESET, 0x501f, 0xd90a);
+	uchcom_set_baudrate(sc, t->c_ospeed);
+	uchcom_set_dtr_rts(sc);
+	uchcom_update_status(sc);
 }
 
 static void
@@ -840,14 +776,14 @@ uchcom_write_callback(struct usb_xfer *x
 tr_setup:
 		pc = usbd_xfer_get_frame(xfer, 0);
 		if (ucom_get_data(&sc->sc_ucom, pc, 0,
-		    UCHCOM_BULK_BUF_SIZE, &actlen)) {
+		    usbd_xfer_max_len(xfer), &actlen)) {
 
 			DPRINTF("actlen = %d\n", actlen);
 
 			usbd_xfer_set_frame_len(xfer, 0, actlen);
 			usbd_transfer_submit(xfer);
 		}
-		return;
+		break;
 
 	default:			/* Error */
 		if (error != USB_ERR_CANCELLED) {
@@ -855,8 +791,7 @@ tr_setup:
 			usbd_xfer_set_stall(xfer);
 			goto tr_setup;
 		}
-		return;
-
+		break;
 	}
 }
 
@@ -871,14 +806,17 @@ uchcom_read_callback(struct usb_xfer *xf
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		pc = usbd_xfer_get_frame(xfer, 0);
-		ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
+
+		if (actlen > 0) {
+			pc = usbd_xfer_get_frame(xfer, 0);
+			ucom_put_data(&sc->sc_ucom, pc, 0, actlen);
+		}
 
 	case USB_ST_SETUP:
 tr_setup:
 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
 		usbd_transfer_submit(xfer);
-		return;
+		break;
 
 	default:			/* Error */
 		if (error != USB_ERR_CANCELLED) {
@@ -886,7 +824,7 @@ tr_setup:
 			usbd_xfer_set_stall(xfer);
 			goto tr_setup;
 		}
-		return;
+		break;
 	}
 }
 

Modified: head/sys/dev/usb/usbdevs
==============================================================================
--- head/sys/dev/usb/usbdevs	Mon Oct 19 21:43:59 2009	(r198256)
+++ head/sys/dev/usb/usbdevs	Mon Oct 19 21:52:02 2009	(r198257)
@@ -626,6 +626,7 @@ vendor AMIT		0x18c5	AMIT
 vendor QCOM		0x18e8	Qcom
 vendor LINKSYS3		0x1915	Linksys
 vendor QUALCOMMINC	0x19d2	Qualcomm, Incorporated
+vendor WCH2		0x1a86	QinHeng Electronics
 vendor STELERA		0x1a8d	Stelera Wireless
 vendor MPMAN		0x1cae	MpMan
 vendor DRESDENELEKTRONIK 0x1cf1 dresden elektronik
@@ -2516,8 +2517,11 @@ product WACOM GRAPHIRE		0x0010	Graphire
 product WACOM GRAPHIRE3_4X5	0x0013	Graphire 3 4x5
 product WACOM INTUOSA5		0x0021	Intuos A5
 product WACOM GD0912U		0x0022	Intuos 9x12 Graphics Tablet
-/* WCH products*/
+
+/* WCH products */
 product WCH CH341SER		0x5523	CH341/CH340 USB-Serial Bridge
+product WCH2 CH341SER		0x7523	CH341/CH340 USB-Serial Bridge
+
 /* Western Digital products */
 product WESTERN COMBO		0x0200	Firewire USB Combo
 product WESTERN EXTHDD		0x0400	External HDD



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200910192152.n9JLq2Hn016355>