Home | History | Annotate | Line # | Download | only in usb
umcs.c revision 1.1
      1 /* $NetBSD: umcs.c,v 1.1 2014/03/16 09:34:45 martin Exp $ */
      2 /* $FreeBSD: head/sys/dev/usb/serial/umcs.c 260559 2014-01-12 11:44:28Z hselasky $ */
      3 
      4 /*-
      5  * Copyright (c) 2010 Lev Serebryakov <lev (at) FreeBSD.org>.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 /*
     31  * This driver supports several multiport USB-to-RS232 serial adapters driven
     32  * by MosChip mos7820 and mos7840, bridge chips.
     33  * The adapters are sold under many different brand names.
     34  *
     35  * Datasheets are available at MosChip www site at
     36  * http://www.moschip.com.  The datasheets don't contain full
     37  * programming information for the chip.
     38  *
     39  * It is nornal to have only two enabled ports in devices, based on
     40  * quad-port mos7840.
     41  *
     42  */
     43 #include <sys/cdefs.h>
     44 __KERNEL_RCSID(0, "$NetBSD: umcs.c,v 1.1 2014/03/16 09:34:45 martin Exp $");
     45 
     46 #include <sys/param.h>
     47 #include <sys/systm.h>
     48 #include <sys/atomic.h>
     49 #include <sys/kernel.h>
     50 #include <sys/conf.h>
     51 #include <sys/tty.h>
     52 #include <sys/device.h>
     53 #include <sys/malloc.h>
     54 #include <sys/workqueue.h>
     55 
     56 #include <dev/usb/usb.h>
     57 #include <dev/usb/usbdi.h>
     58 #include <dev/usb/usbdi_util.h>
     59 #include <dev/usb/usbdevs.h>
     60 
     61 #include <dev/usb/usbdevs.h>
     62 #include <dev/usb/ucomvar.h>
     63 
     64 #include "umcs.h"
     65 
     66 #if 0
     67 #define	DPRINTF(ARG)	printf ARG
     68 #else
     69 #define	DPRINTF(ARG)
     70 #endif
     71 
     72 /*
     73  * Two-port devices (both with 7820 chip and 7840 chip configured as two-port)
     74  * have ports 0 and 2, with ports 1 and 3 omitted.
     75  * So, PHYSICAL port numbers on two-port device will be 0 and 2.
     76  *
     77  * We use an array of the following struct, indexed by ucom port index,
     78  * and include the physical port number in it.
     79  */
     80 struct umcs7840_softc_oneport {
     81 	device_t sc_port_ucom;		/* ucom subdevice */
     82 	uint32_t sc_port_changed;	/* call ucom_status_change() */
     83 	unsigned int sc_port_phys;	/* physical port number */
     84 	uint8_t	sc_port_lcr;		/* local line control register */
     85 	uint8_t	sc_port_mcr;		/* local modem control register */
     86 };
     87 
     88 struct umcs7840_softc {
     89 	device_t sc_dev;		/* ourself */
     90 	usbd_interface_handle sc_iface; /* the usb interface */
     91 	usbd_device_handle sc_udev;	/* the usb device */
     92 	usbd_pipe_handle sc_intr_pipe;	/* interrupt pipe */
     93 	usbd_xfer_handle sc_intr_xfer;	/* and preallocated xfer */
     94 	uint8_t *sc_intr_buf;		/* buffer for interrupt xfer */
     95 	struct workqueue *sc_change_wq;	/* workqueue for status changes */
     96 	struct work sc_work;		/* work for said workqueue.  */
     97 	struct umcs7840_softc_oneport sc_ports[UMCS7840_MAX_PORTS];
     98 					/* data for each port */
     99 	uint8_t	sc_numports;		/* number of ports (subunits) */
    100 	bool sc_init_done;		/* special one time init in open */
    101 	bool sc_dying;			/* we have been deactivated */
    102 };
    103 
    104 static int umcs7840_get_reg(struct umcs7840_softc *sc, uint8_t reg, uint8_t *data);
    105 static int umcs7840_set_reg(struct umcs7840_softc *sc, uint8_t reg, uint8_t data);
    106 static int umcs7840_get_UART_reg(struct umcs7840_softc *sc, uint8_t portno, uint8_t reg, uint8_t *data);
    107 static int umcs7840_set_UART_reg(struct umcs7840_softc *sc, uint8_t portno, uint8_t reg, uint8_t data);
    108 static int umcs7840_calc_baudrate(uint32_t rate, uint16_t *divisor, uint8_t *clk);
    109 static void umcs7840_dtr(struct umcs7840_softc *sc, int portno, bool onoff);
    110 static void umcs7840_rts(struct umcs7840_softc *sc, int portno, bool onoff);
    111 static void umcs7840_break(struct umcs7840_softc *sc, int portno, bool onoff);
    112 
    113 static int umcs7840_match(device_t, cfdata_t, void *);
    114 static void umcs7840_attach(device_t, device_t, void *);
    115 static int umcs7840_detach(device_t, int);
    116 static void umcs7840_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status);
    117 static void umcs7840_change_worker(struct work *w, void *arg);
    118 static int umcs7840_activate(device_t, enum devact);
    119 static void umcs7840_childdet(device_t, device_t);
    120 
    121 static void umcs7840_get_status(void *, int, u_char *, u_char *);
    122 static void umcs7840_set(void *, int, int, int);
    123 static int umcs7840_param(void *, int, struct termios *);
    124 static int umcs7840_port_open(void *sc, int portno);
    125 static void umcs7840_port_close(void *sc, int portno);
    126 
    127 struct ucom_methods umcs7840_methods = {
    128 	umcs7840_get_status,
    129 	umcs7840_set,
    130 	umcs7840_param,
    131 	NULL,
    132 	umcs7840_port_open,
    133 	umcs7840_port_close,
    134 };
    135 
    136 static const struct usb_devno umcs7840_devs[] = {
    137 	{ USB_VENDOR_MOSCHIP,		USB_PRODUCT_MOSCHIP_MCS7703 },
    138 	{ USB_VENDOR_MOSCHIP,		USB_PRODUCT_MOSCHIP_MCS7810 },
    139 	{ USB_VENDOR_MOSCHIP,		USB_PRODUCT_MOSCHIP_MCS7820 },
    140 	{ USB_VENDOR_MOSCHIP,		USB_PRODUCT_MOSCHIP_MCS7840 },
    141 	{ USB_VENDOR_ATEN,		USB_PRODUCT_ATEN_UC2324 }
    142 };
    143 #define umcs7840_lookup(v, p) usb_lookup(umcs7840_devs, v, p)
    144 
    145 CFATTACH_DECL2_NEW(umcs, sizeof(struct umcs7840_softc), umcs7840_match,
    146     umcs7840_attach, umcs7840_detach, umcs7840_activate, NULL,
    147     umcs7840_childdet);
    148 
    149 static inline int
    150 umcs7840_reg_sp(int phyport)
    151 {
    152 	KASSERT(phyport >= 0 && phyport < 4);
    153 	switch (phyport) {
    154 	default:
    155 	case 0:	return MCS7840_DEV_REG_SP1;
    156 	case 1:	return MCS7840_DEV_REG_SP2;
    157 	case 2:	return MCS7840_DEV_REG_SP3;
    158 	case 3:	return MCS7840_DEV_REG_SP4;
    159 	}
    160 }
    161 
    162 static inline int
    163 umcs7840_reg_ctrl(int phyport)
    164 {
    165 	KASSERT(phyport >= 0 && phyport < 4);
    166 	switch (phyport) {
    167 	default:
    168 	case 0:	return MCS7840_DEV_REG_CONTROL1;
    169 	case 1:	return MCS7840_DEV_REG_CONTROL2;
    170 	case 2:	return MCS7840_DEV_REG_CONTROL3;
    171 	case 3:	return MCS7840_DEV_REG_CONTROL4;
    172 	}
    173 }
    174 
    175 static inline int
    176 umcs7840_reg_dcr0(int phyport)
    177 {
    178 	KASSERT(phyport >= 0 && phyport < 4);
    179 	switch (phyport) {
    180 	default:
    181 	case 0:	return MCS7840_DEV_REG_DCR0_1;
    182 	case 1:	return MCS7840_DEV_REG_DCR0_2;
    183 	case 2:	return MCS7840_DEV_REG_DCR0_3;
    184 	case 3:	return MCS7840_DEV_REG_DCR0_4;
    185 	}
    186 }
    187 
    188 static int
    189 umcs7840_match(device_t dev, cfdata_t match, void *aux)
    190 {
    191 	struct usb_attach_arg *uaa = aux;
    192 
    193 	return (umcs7840_lookup(uaa->vendor, uaa->product) != NULL ?
    194 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
    195 }
    196 
    197 static void
    198 umcs7840_attach(device_t parent, device_t self, void * aux)
    199 {
    200 	struct umcs7840_softc *sc = device_private(self);
    201 	struct usb_attach_arg *uaa = aux;
    202 	usbd_device_handle dev = uaa->device;
    203 	usb_interface_descriptor_t *id;
    204 	usb_endpoint_descriptor_t *ed;
    205 	char *devinfop;
    206 	struct ucom_attach_args uca;
    207 	int error, i, intr_addr;
    208 	uint8_t data;
    209 	uint16_t isize;
    210 
    211 	sc->sc_dev = self;
    212 	sc->sc_udev = uaa->device;
    213 
    214 	if (usbd_set_config_index(sc->sc_udev, MCS7840_CONFIG_INDEX, 1) != 0) {
    215 		aprint_error(": could not set configuration no\n");
    216 		return;
    217 	}
    218 
    219 	/* get the first interface handle */
    220 	error = usbd_device2interface_handle(sc->sc_udev, MCS7840_IFACE_INDEX,
    221 	    &sc->sc_iface);
    222 	if (error != 0) {
    223 		aprint_error(": could not get interface handle\n");
    224 		return;
    225 	}
    226 
    227 	/*
    228 	 * Get number of ports
    229 	 * Documentation (full datasheet) says, that number of ports is
    230 	 * set as MCS7840_DEV_MODE_SELECT24S bit in MODE R/Only
    231 	 * register. But vendor driver uses these undocumented
    232 	 * register & bit.
    233 	 *
    234 	 * Experiments show, that MODE register can have `0'
    235 	 * (4 ports) bit on 2-port device, so use vendor driver's way.
    236 	 *
    237 	 * Also, see notes in header file for these constants.
    238 	 */
    239 	umcs7840_get_reg(sc, MCS7840_DEV_REG_GPIO, &data);
    240 	if (data & MCS7840_DEV_GPIO_4PORTS) {
    241 		sc->sc_numports = 4;
    242 		/* physical port no are : 0, 1, 2, 3 */
    243 	} else {
    244 		if (uaa->product == USB_PRODUCT_MOSCHIP_MCS7810)
    245 			sc->sc_numports = 1;
    246 		else {
    247 			sc->sc_numports = 2;
    248 			/* physical port no are : 0 and 2 */
    249 		}
    250 	}
    251 	devinfop = usbd_devinfo_alloc(dev, 0);
    252 	aprint_normal(": %s\n", devinfop);
    253 	usbd_devinfo_free(devinfop);
    254 	aprint_verbose_dev(self, "found %d active ports\n", sc->sc_numports);
    255 
    256 	if (!umcs7840_get_reg(sc, MCS7840_DEV_REG_MODE, &data)) {
    257 		aprint_verbose_dev(self, "On-die confguration: RST: active %s, "
    258 		    "HRD: %s, PLL: %s, POR: %s, Ports: %s, EEPROM write %s, "
    259 		    "IrDA is %savailable\n",
    260 		    (data & MCS7840_DEV_MODE_RESET) ? "low" : "high",
    261 		    (data & MCS7840_DEV_MODE_SER_PRSNT) ? "yes" : "no",
    262 		    (data & MCS7840_DEV_MODE_PLLBYPASS) ? "bypassed" : "avail",
    263 		    (data & MCS7840_DEV_MODE_PORBYPASS) ? "bypassed" : "avail",
    264 		    (data & MCS7840_DEV_MODE_SELECT24S) ? "2" : "4",
    265 		    (data & MCS7840_DEV_MODE_EEPROMWR) ? "enabled" : "disabled",
    266 		    (data & MCS7840_DEV_MODE_IRDA) ? "" : "not ");
    267 	}
    268 
    269 	/*
    270 	 * Set up the interrupt pipe
    271 	 */
    272 	id = usbd_get_interface_descriptor(sc->sc_iface);
    273 	isize = 0;
    274 	intr_addr = -1;
    275 	for (i = 0 ; i < id->bNumEndpoints ; i++) {
    276 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
    277 		if (ed == NULL) continue;
    278 		if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN
    279 		    || UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT)
    280 			continue;
    281 		isize = UGETW(ed->wMaxPacketSize);
    282 		intr_addr = ed->bEndpointAddress;
    283 		break;
    284 	}
    285 	if (intr_addr < 0) {
    286 		aprint_error_dev(self, "interrupt pipe not found\n");
    287 		return;
    288 	}
    289 	sc->sc_intr_buf = malloc(isize, M_USBDEV, M_WAITOK);
    290 
    291 	error = usbd_open_pipe_intr(sc->sc_iface, intr_addr,
    292 		    USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, sc->sc_intr_buf,
    293 		    isize, umcs7840_intr, 100);
    294 	if (error) {
    295 		aprint_error_dev(self, "cannot open interrupt pipe "
    296 		    "(addr %d)\n", intr_addr);
    297 		return;
    298 	}
    299 
    300 	sc->sc_intr_xfer = usbd_alloc_xfer(uaa->device);
    301 	if (sc->sc_intr_xfer == NULL) {
    302 		aprint_error_dev(self, "alloc intr xfer failed\n");
    303 		return;
    304         }
    305 	if (workqueue_create(&sc->sc_change_wq, "umcsq",
    306 		umcs7840_change_worker, sc, PRI_NONE, IPL_USB, WQ_MPSAFE)) {
    307 		aprint_error_dev(self, "workqueue creation failed\n");
    308 		return;
    309         }
    310 
    311 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
    312 	    sc->sc_dev);
    313 
    314 	memset(&uca, 0, sizeof uca);
    315 	uca.ibufsize = 256;
    316 	uca.obufsize = 256;
    317 	uca.ibufsizepad = 256;
    318 	uca.opkthdrlen = 0;
    319 	uca.device = sc->sc_udev;
    320 	uca.iface = sc->sc_iface;
    321 	uca.methods = &umcs7840_methods;
    322 	uca.arg = sc;
    323 
    324 	for (i = 0; i < sc->sc_numports; i++) {
    325 		uca.bulkin = uca.bulkout = -1;
    326 
    327 		/*
    328 		 * On four port cards, endpoints are 0/1 for first,
    329 		 * 2/3 for second, ...
    330 		 * On two port cards, they are 0/1 for first, 4/5 for second.
    331 		 * On single port, just 0/1 will be used.
    332 		 */
    333 		int phyport = i * (sc->sc_numports == 2 ? 2 : 1);
    334 
    335 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface,
    336 			phyport*2);
    337 		if (ed == NULL) {
    338 			aprint_error_dev(self,
    339 			    "no bulk in endpoint found for %d\n", i);
    340 			return;
    341 		}
    342 		uca.bulkin = ed->bEndpointAddress;
    343 
    344 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface,
    345 			phyport*2 + 1);
    346 		if (ed == NULL) {
    347 			aprint_error_dev(self,
    348 			    "no bulk out endpoint found for %d\n", i);
    349 			return;
    350 		}
    351 		uca.bulkout = ed->bEndpointAddress;
    352 		uca.portno = i;
    353 		DPRINTF(("port %d physical port %d bulk-in %d bulk-out %d\n",
    354 		    i, phyport, uca.bulkin, uca.bulkout));
    355 
    356 		sc->sc_ports[i].sc_port_phys = phyport;
    357 		sc->sc_ports[i].sc_port_ucom =
    358 		    config_found_sm_loc(self, "ucombus", NULL, &uca,
    359 					    ucomprint, ucomsubmatch);
    360 	}
    361 }
    362 
    363 static int
    364 umcs7840_get_reg(struct umcs7840_softc *sc, uint8_t reg, uint8_t *data)
    365 {
    366 	usb_device_request_t req;
    367 	int err;
    368 
    369 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
    370 	req.bRequest = MCS7840_RDREQ;
    371 	USETW(req.wValue, 0);
    372 	USETW(req.wIndex, reg);
    373 	USETW(req.wLength, UMCS7840_READ_LENGTH);
    374 
    375 	err = usbd_do_request(sc->sc_udev, &req, data);
    376 	if (err)
    377 		aprint_normal_dev(sc->sc_dev,
    378 		    "Reading register %d failed: %s\n", reg, usbd_errstr(err));
    379 	return err;
    380 }
    381 
    382 static int
    383 umcs7840_set_reg(struct umcs7840_softc *sc, uint8_t reg, uint8_t data)
    384 {
    385 	usb_device_request_t req;
    386 	int err;
    387 
    388 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    389 	req.bRequest = MCS7840_WRREQ;
    390 	USETW(req.wValue, data);
    391 	USETW(req.wIndex, reg);
    392 	USETW(req.wLength, 0);
    393 
    394 	err = usbd_do_request(sc->sc_udev, &req, 0);
    395 	if (err)
    396 		aprint_normal_dev(sc->sc_dev, "Writing register %d failed: %s\n", reg, usbd_errstr(err));
    397 
    398 	return err;
    399 }
    400 
    401 static int
    402 umcs7840_get_UART_reg(struct umcs7840_softc *sc, uint8_t portno,
    403 	uint8_t reg, uint8_t *data)
    404 {
    405 	usb_device_request_t req;
    406 	uint16_t wVal;
    407 	int err;
    408 
    409 	/* portno is port number */
    410 	wVal = ((uint16_t)(portno + 1)) << 8;
    411 
    412 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
    413 	req.bRequest = MCS7840_RDREQ;
    414 	USETW(req.wValue, wVal);
    415 	USETW(req.wIndex, reg);
    416 	USETW(req.wLength, UMCS7840_READ_LENGTH);
    417 
    418 	err = usbd_do_request(sc->sc_udev, &req, data);
    419 	if (err)
    420 		aprint_normal_dev(sc->sc_dev, "Reading UART %d register %d failed: %s\n", portno, reg, usbd_errstr(err));
    421 	return err;
    422 }
    423 
    424 static int
    425 umcs7840_set_UART_reg(struct umcs7840_softc *sc, uint8_t portno, uint8_t reg, uint8_t data)
    426 {
    427 	usb_device_request_t req;
    428 	int err;
    429 	uint16_t wVal;
    430 
    431 	/* portno is the physical port number */
    432 	wVal = ((uint16_t)(portno + 1)) << 8 | data;
    433 
    434 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    435 	req.bRequest = MCS7840_WRREQ;
    436 	USETW(req.wValue, wVal);
    437 	USETW(req.wIndex, reg);
    438 	USETW(req.wLength, 0);
    439 
    440 	err = usbd_do_request(sc->sc_udev, &req, NULL);
    441 	if (err)
    442 		device_printf(sc->sc_dev, "Writing UART%d register %d failed: %s\n", portno, reg, usbd_errstr(err));
    443 	return err;
    444 }
    445 
    446 static int
    447 umcs7840_set_baudrate(struct umcs7840_softc *sc, uint8_t portno, uint32_t rate)
    448 {
    449 	int err;
    450 	uint16_t divisor;
    451 	uint8_t clk;
    452 	uint8_t data;
    453 	uint8_t physport = sc->sc_ports[portno].sc_port_phys;
    454 	int spreg = umcs7840_reg_sp(physport);
    455 
    456 	if (umcs7840_calc_baudrate(rate, &divisor, &clk)) {
    457 		DPRINTF(("Port %d bad speed: %d\n", portno, rate));
    458 		return (-1);
    459 	}
    460 	if (divisor == 0 || (clk & MCS7840_DEV_SPx_CLOCK_MASK) != clk) {
    461 		DPRINTF(("Port %d bad speed calculation: %d\n", portno, rate));
    462 		return (-1);
    463 	}
    464 	DPRINTF(("Port %d set speed: %d (%02x / %d)\n", portno, rate, clk, divisor));
    465 
    466 	/* Set clock source for standard BAUD frequences */
    467 	err = umcs7840_get_reg(sc, spreg, &data);
    468 	if (err)
    469 		return err;
    470 	data &= MCS7840_DEV_SPx_CLOCK_MASK;
    471 	data |= clk;
    472 	err = umcs7840_set_reg(sc, spreg, data);
    473 	if (err)
    474 		return err;
    475 
    476 	/* Set divider */
    477 	sc->sc_ports[portno].sc_port_lcr |= MCS7840_UART_LCR_DIVISORS;
    478 	err = umcs7840_set_UART_reg(sc, physport, MCS7840_UART_REG_LCR, sc->sc_ports[portno].sc_port_lcr);
    479 	if (err)
    480 		return err;
    481 
    482 	err = umcs7840_set_UART_reg(sc, physport, MCS7840_UART_REG_DLL, (uint8_t)(divisor & 0xff));
    483 	if (err)
    484 		return err;
    485 	err = umcs7840_set_UART_reg(sc, physport, MCS7840_UART_REG_DLM, (uint8_t)((divisor >> 8) & 0xff));
    486 	if (err)
    487 		return err;
    488 
    489 	/* Turn off access to DLL/DLM registers of UART */
    490 	sc->sc_ports[portno].sc_port_lcr &= ~MCS7840_UART_LCR_DIVISORS;
    491 	err = umcs7840_set_UART_reg(sc, physport, MCS7840_UART_REG_LCR, sc->sc_ports[portno].sc_port_lcr);
    492 	if (err)
    493 		return err;
    494 	return (0);
    495 }
    496 
    497 static int
    498 umcs7840_calc_baudrate(uint32_t rate, uint16_t *divisor, uint8_t *clk)
    499 {
    500 	/* Maximum speeds for standard frequences, when PLL is not used */
    501 	static const uint32_t umcs7840_baudrate_divisors[] =
    502 	    {0, 115200, 230400, 403200, 460800, 806400, 921600,
    503 	     1572864, 3145728,};
    504 	static const uint8_t umcs7840_baudrate_divisors_len =
    505 	     __arraycount(umcs7840_baudrate_divisors);
    506 	uint8_t i = 0;
    507 
    508 	if (rate > umcs7840_baudrate_divisors[umcs7840_baudrate_divisors_len - 1])
    509 		return (-1);
    510 
    511 	for (i = 0; i < umcs7840_baudrate_divisors_len - 1
    512 	     && !(rate > umcs7840_baudrate_divisors[i]
    513 	     && rate <= umcs7840_baudrate_divisors[i + 1]); ++i);
    514 	*divisor = umcs7840_baudrate_divisors[i + 1] / rate;
    515 	/* 0x00 .. 0x70 */
    516 	*clk = i << MCS7840_DEV_SPx_CLOCK_SHIFT;
    517 	return (0);
    518 }
    519 
    520 static int
    521 umcs7840_detach(device_t self, int flags)
    522 {
    523 	struct umcs7840_softc *sc = device_private(self);
    524 	int rv = 0, i;
    525 
    526 	/* close interrupt pipe */
    527 	if (sc->sc_intr_pipe != NULL) {
    528 		rv = usbd_abort_pipe(sc->sc_intr_pipe);
    529 		if (rv)
    530 			aprint_error_dev(sc->sc_dev,
    531 			    "abort interrupt pipe failed: %s\n",
    532 			    usbd_errstr(rv));
    533 		rv = usbd_close_pipe(sc->sc_intr_pipe);
    534 		if (rv)
    535 			aprint_error_dev(sc->sc_dev,
    536 			    "close interrupt pipe failed: %s\n",
    537 			    usbd_errstr(rv));
    538 		free(sc->sc_intr_buf, M_USBDEV);
    539 		sc->sc_intr_pipe = NULL;
    540 	}
    541 	if (sc->sc_change_wq != NULL)
    542 		workqueue_destroy(sc->sc_change_wq);
    543 
    544 	for (i = 0; i < sc->sc_numports; i++) {
    545 		if (sc->sc_ports[i].sc_port_ucom) {
    546 			rv = config_detach(sc->sc_ports[i].sc_port_ucom,
    547 			    flags);
    548 			if (rv)
    549 				break;
    550 		}
    551 	}
    552 
    553 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
    554 			   sc->sc_dev);
    555 
    556 	return rv;
    557 }
    558 
    559 int
    560 umcs7840_activate(device_t self, enum devact act)
    561 {
    562 	struct umcs7840_softc *sc = device_private(self);
    563 
    564 	switch (act) {
    565 	case DVACT_DEACTIVATE:
    566 		sc->sc_dying = true;
    567 		return 0;
    568 	default:
    569 		return EOPNOTSUPP;
    570 	}
    571 }
    572 
    573 static void
    574 umcs7840_childdet(device_t self, device_t child)
    575 {
    576 	struct umcs7840_softc *sc = device_private(self);
    577 	int i;
    578 
    579 	for (i = 0; i < sc->sc_numports; i++) {
    580 		if (child == sc->sc_ports[i].sc_port_ucom) {
    581 			sc->sc_ports[i].sc_port_ucom = NULL;
    582 			return;
    583 		}
    584 	}
    585 }
    586 
    587 static void
    588 umcs7840_get_status(void *self, int portno, u_char *lsr, u_char *msr)
    589 {
    590 	struct umcs7840_softc *sc = self;
    591 	uint8_t pn = sc->sc_ports[portno].sc_port_phys;
    592 	uint8_t	hw_lsr = 0;	/* local line status register */
    593 	uint8_t	hw_msr = 0;	/* local modem status register */
    594 
    595 	/* Read LSR & MSR */
    596 	umcs7840_get_UART_reg(sc, pn, MCS7840_UART_REG_LSR, &hw_lsr);
    597 	umcs7840_get_UART_reg(sc, pn, MCS7840_UART_REG_MSR, &hw_msr);
    598 
    599 	*lsr = hw_lsr;
    600 	*msr = hw_msr;
    601 }
    602 
    603 static void
    604 umcs7840_set(void *self, int portno, int reg, int onoff)
    605 {
    606 	struct umcs7840_softc *sc = self;
    607 	int pn = sc->sc_ports[portno].sc_port_phys;
    608 
    609 	if (sc->sc_dying)
    610 		return;
    611 
    612 	switch (reg) {
    613 	case UCOM_SET_DTR:
    614 		umcs7840_dtr(sc, pn, onoff);
    615 		break;
    616 	case UCOM_SET_RTS:
    617 		umcs7840_rts(sc, pn, onoff);
    618 		break;
    619 	case UCOM_SET_BREAK:
    620 		umcs7840_break(sc, pn, onoff);
    621 		break;
    622 	default:
    623 		break;
    624 	}
    625 }
    626 
    627 static int
    628 umcs7840_param(void *self, int portno, struct termios *t)
    629 {
    630 	struct umcs7840_softc *sc = self;
    631 	int pn = sc->sc_ports[portno].sc_port_phys;
    632 	uint8_t lcr = sc->sc_ports[portno].sc_port_lcr;
    633 	uint8_t mcr = sc->sc_ports[portno].sc_port_mcr;
    634 
    635 	if (t->c_cflag & CSTOPB) {
    636 		lcr |= MCS7840_UART_LCR_STOPB2;
    637 	} else {
    638 		lcr |= MCS7840_UART_LCR_STOPB1;
    639 	}
    640 
    641 	lcr &= ~MCS7840_UART_LCR_PARITYMASK;
    642 	if (t->c_cflag & PARENB) {
    643 		lcr |= MCS7840_UART_LCR_PARITYON;
    644 		if (t->c_cflag & PARODD) {
    645 			lcr = MCS7840_UART_LCR_PARITYODD;
    646 		} else {
    647 			lcr = MCS7840_UART_LCR_PARITYEVEN;
    648 		}
    649 	} else {
    650 		lcr &= ~MCS7840_UART_LCR_PARITYON;
    651 	}
    652 
    653 	lcr &= ~MCS7840_UART_LCR_DATALENMASK;
    654 	switch (t->c_cflag & CSIZE) {
    655 	case CS5:
    656 		lcr |= MCS7840_UART_LCR_DATALEN5;
    657 		break;
    658 	case CS6:
    659 		lcr |= MCS7840_UART_LCR_DATALEN6;
    660 		break;
    661 	case CS7:
    662 		lcr |= MCS7840_UART_LCR_DATALEN7;
    663 		break;
    664 	case CS8:
    665 		lcr |= MCS7840_UART_LCR_DATALEN8;
    666 		break;
    667 	}
    668 
    669 	if (t->c_cflag & CRTSCTS)
    670 		mcr |= MCS7840_UART_MCR_CTSRTS;
    671 	else
    672 		mcr &= ~MCS7840_UART_MCR_CTSRTS;
    673 
    674 	if (t->c_cflag & CLOCAL)
    675 		mcr &= ~MCS7840_UART_MCR_DTRDSR;
    676 	else
    677 		mcr |= MCS7840_UART_MCR_DTRDSR;
    678 
    679 	sc->sc_ports[portno].sc_port_lcr = lcr;
    680 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_LCR,
    681 	    sc->sc_ports[pn].sc_port_lcr);
    682 
    683 	sc->sc_ports[portno].sc_port_mcr = mcr;
    684 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_MCR,
    685 	    sc->sc_ports[pn].sc_port_mcr);
    686 
    687 	if (umcs7840_set_baudrate(sc, pn, t->c_ospeed))
    688 		return EIO;
    689 
    690 	return 0;
    691 }
    692 
    693 static void
    694 umcs7840_dtr(struct umcs7840_softc *sc, int portno, bool onoff)
    695 {
    696 	int pn = sc->sc_ports[portno].sc_port_phys;
    697 	uint8_t mcr = sc->sc_ports[portno].sc_port_mcr;
    698 
    699 	if (onoff)
    700 		mcr |= MCS7840_UART_MCR_DTR;
    701 	else
    702 		mcr &= ~MCS7840_UART_MCR_DTR;
    703 
    704 	sc->sc_ports[portno].sc_port_mcr = mcr;
    705 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_MCR,
    706 	    sc->sc_ports[pn].sc_port_mcr);
    707 }
    708 
    709 static void
    710 umcs7840_rts(struct umcs7840_softc *sc, int portno, bool onoff)
    711 {
    712 	int pn = sc->sc_ports[portno].sc_port_phys;
    713 	uint8_t mcr = sc->sc_ports[portno].sc_port_mcr;
    714 
    715 	if (onoff)
    716 		mcr |= MCS7840_UART_MCR_RTS;
    717 	else
    718 		mcr &= ~MCS7840_UART_MCR_RTS;
    719 
    720 	sc->sc_ports[portno].sc_port_mcr = mcr;
    721 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_MCR,
    722 	    sc->sc_ports[pn].sc_port_mcr);
    723 }
    724 
    725 static void
    726 umcs7840_break(struct umcs7840_softc *sc, int portno, bool onoff)
    727 {
    728 	int pn = sc->sc_ports[portno].sc_port_phys;
    729 	uint8_t lcr = sc->sc_ports[portno].sc_port_lcr;
    730 
    731 	if (onoff)
    732 		lcr |= MCS7840_UART_LCR_BREAK;
    733 	else
    734 		lcr &= ~MCS7840_UART_LCR_BREAK;
    735 
    736 	sc->sc_ports[portno].sc_port_lcr = lcr;
    737 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_LCR,
    738 	    sc->sc_ports[pn].sc_port_lcr);
    739 }
    740 
    741 static int
    742 umcs7840_port_open(void *self, int portno)
    743 {
    744 	struct umcs7840_softc *sc = self;
    745 	int pn = sc->sc_ports[portno].sc_port_phys;
    746 	int spreg = umcs7840_reg_sp(pn);
    747 	int ctrlreg = umcs7840_reg_ctrl(pn);
    748 	uint8_t data;
    749 
    750 	if (sc->sc_dying)
    751 		return EIO;
    752 
    753 	/* If it very first open, finish global configuration */
    754 	if (!sc->sc_init_done) {
    755 		if (umcs7840_get_reg(sc, MCS7840_DEV_REG_CONTROL1, &data))
    756 			return EIO;
    757 		data |= MCS7840_DEV_CONTROL1_DRIVER_DONE;
    758 		if (umcs7840_set_reg(sc, MCS7840_DEV_REG_CONTROL1, data))
    759 			return EIO;
    760 		sc->sc_init_done = 1;
    761 	}
    762 
    763 	/* Toggle reset bit on-off */
    764 	if (umcs7840_get_reg(sc, spreg, &data))
    765 		return EIO;
    766 	data |= MCS7840_DEV_SPx_UART_RESET;
    767 	if (umcs7840_set_reg(sc, spreg, data))
    768 		return EIO;
    769 	data &= ~MCS7840_DEV_SPx_UART_RESET;
    770 	if (umcs7840_set_reg(sc, spreg, data))
    771 		return EIO;
    772 
    773 	/* Set RS-232 mode */
    774 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_SCRATCHPAD,
    775 	    MCS7840_UART_SCRATCHPAD_RS232))
    776 		return EIO;
    777 
    778 	/* Disable RX on time of initialization */
    779 	if (umcs7840_get_reg(sc, ctrlreg, &data))
    780 		return EIO;
    781 	data |= MCS7840_DEV_CONTROLx_RX_DISABLE;
    782 	if (umcs7840_set_reg(sc, ctrlreg, data))
    783 		return EIO;
    784 
    785 	/* Disable all interrupts */
    786 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_IER, 0))
    787 		return EIO;
    788 
    789 	/* Reset FIFO -- documented */
    790 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_FCR, 0))
    791 		return EIO;
    792 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_FCR,
    793 	    MCS7840_UART_FCR_ENABLE | MCS7840_UART_FCR_FLUSHRHR |
    794 	    MCS7840_UART_FCR_FLUSHTHR | MCS7840_UART_FCR_RTL_1_14))
    795 		return EIO;
    796 
    797 	/* Set 8 bit, no parity, 1 stop bit -- documented */
    798 	sc->sc_ports[pn].sc_port_lcr =
    799 	    MCS7840_UART_LCR_DATALEN8 | MCS7840_UART_LCR_STOPB1;
    800 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_LCR,
    801 	    sc->sc_ports[pn].sc_port_lcr))
    802 		return EIO;
    803 
    804 	/*
    805 	 * Enable DTR/RTS on modem control, enable modem interrupts --
    806 	 * documented
    807 	 */
    808 	sc->sc_ports[pn].sc_port_mcr = MCS7840_UART_MCR_DTR
    809 	    | MCS7840_UART_MCR_RTS | MCS7840_UART_MCR_IE;
    810 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_MCR,
    811 	    sc->sc_ports[pn].sc_port_mcr))
    812 		return EIO;
    813 
    814 	/* Clearing Bulkin and Bulkout FIFO */
    815 	if (umcs7840_get_reg(sc, spreg, &data))
    816 		return EIO;
    817 	data |= MCS7840_DEV_SPx_RESET_OUT_FIFO | MCS7840_DEV_SPx_RESET_IN_FIFO;
    818 	if (umcs7840_set_reg(sc, spreg, data))
    819 		return EIO;
    820 	data &= ~(MCS7840_DEV_SPx_RESET_OUT_FIFO
    821 	    | MCS7840_DEV_SPx_RESET_IN_FIFO);
    822 	if (umcs7840_set_reg(sc, spreg, data))
    823 		return EIO;
    824 
    825 	/* Set speed 9600 */
    826 	if (umcs7840_set_baudrate(sc, pn, 9600))
    827 		return EIO;
    828 
    829 
    830 	/* Finally enable all interrupts -- documented */
    831 	/*
    832 	 * Copied from vendor driver, I don't know why we should read LCR
    833 	 * here
    834 	 */
    835 	if (umcs7840_get_UART_reg(sc, pn, MCS7840_UART_REG_LCR,
    836 	    &sc->sc_ports[pn].sc_port_lcr))
    837 		return EIO;
    838 	if (umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_IER,
    839 	    MCS7840_UART_IER_RXSTAT | MCS7840_UART_IER_MODEM))
    840 		return EIO;
    841 
    842 	/* Enable RX */
    843 	if (umcs7840_get_reg(sc, ctrlreg, &data))
    844 		return EIO;
    845 	data &= ~MCS7840_DEV_CONTROLx_RX_DISABLE;
    846 	if (umcs7840_set_reg(sc, ctrlreg, data))
    847 		return EIO;
    848 	return 0;
    849 }
    850 
    851 static void
    852 umcs7840_port_close(void *self, int portno)
    853 {
    854 	struct umcs7840_softc *sc = self;
    855 	int pn = sc->sc_ports[portno].sc_port_phys;
    856 	int ctrlreg = umcs7840_reg_ctrl(pn);
    857 	uint8_t data;
    858 
    859 	atomic_swap_32(&sc->sc_ports[portno].sc_port_changed, 0);
    860 
    861 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_MCR, 0);
    862 	umcs7840_set_UART_reg(sc, pn, MCS7840_UART_REG_IER, 0);
    863 
    864 	/* Disable RX */
    865 	if (umcs7840_get_reg(sc, ctrlreg, &data))
    866 		return;
    867 	data |= MCS7840_DEV_CONTROLx_RX_DISABLE;
    868 	if (umcs7840_set_reg(sc, ctrlreg, data))
    869 		return;
    870 }
    871 
    872 static void
    873 umcs7840_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
    874     usbd_status status)
    875 {
    876 	struct umcs7840_softc *sc = priv;
    877 	u_char *buf = sc->sc_intr_buf;
    878 	int actlen;
    879 	int subunit, found;
    880 
    881 	if (sc->sc_dying)
    882 		return;
    883 
    884 	found = 0;
    885 	if (status != USBD_NORMAL_COMPLETION) {
    886 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    887 			return;
    888 
    889 		aprint_error_dev(sc->sc_dev,
    890 		    "umcs7840_intr: abnormal status: %s\n",
    891 		    usbd_errstr(status));
    892 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
    893 		return;
    894 	}
    895 
    896 	usbd_get_xfer_status(xfer, NULL, NULL, &actlen, NULL);
    897 	if (actlen == 5 || actlen == 13) {
    898 		/* Check status of all ports */
    899 		for (subunit = 0; subunit < sc->sc_numports; subunit++) {
    900 			uint8_t pn = sc->sc_ports[subunit].sc_port_phys;
    901 			if (buf[pn] & MCS7840_UART_ISR_NOPENDING)
    902 				continue;
    903 			DPRINTF(("Port %d has pending interrupt: %02x "
    904 			    "(FIFO: %02x)\n", pn,
    905 			    buf[pn] & MCS7840_UART_ISR_INTMASK,
    906 			    buf[pn] & (~MCS7840_UART_ISR_INTMASK)));
    907 			switch (buf[pn] & MCS7840_UART_ISR_INTMASK) {
    908 			case MCS7840_UART_ISR_RXERR:
    909 			case MCS7840_UART_ISR_RXHASDATA:
    910 			case MCS7840_UART_ISR_RXTIMEOUT:
    911 			case MCS7840_UART_ISR_MSCHANGE:
    912 				atomic_swap_32(
    913 				    &sc->sc_ports[subunit].sc_port_changed,
    914 				    1);
    915 				found++;
    916 				break;
    917 			default:
    918 				/* Do nothing */
    919 				break;
    920 			}
    921 		}
    922 		if (found)
    923 			workqueue_enqueue(sc->sc_change_wq, &sc->sc_work,
    924 			    NULL);
    925 	} else {
    926 		device_printf(sc->sc_dev, "Invalid interrupt data length %d",
    927 		   actlen);
    928 	}
    929 }
    930 
    931 static void
    932 umcs7840_change_worker(struct work *w, void *arg)
    933 {
    934 	struct umcs7840_softc *sc = arg;
    935 	int i;
    936 
    937 	for (i = 0; i < sc->sc_numports; i++) {
    938 		if (sc->sc_ports[i].sc_port_changed) {
    939 			ucom_status_change(device_private(
    940 			    sc->sc_ports[i].sc_port_ucom));
    941 			atomic_swap_32(&sc->sc_ports[i].sc_port_changed, 0);
    942 		}
    943 	}
    944 }
    945