Home | History | Annotate | Line # | Download | only in usb
uark.c revision 1.6.14.2
      1  1.6.14.2     skrll /*	$NetBSD: uark.c,v 1.6.14.2 2015/03/19 17:26:43 skrll Exp $	*/
      2       1.1    martin /*	$OpenBSD: uark.c,v 1.13 2009/10/13 19:33:17 pirofti Exp $	*/
      3       1.1    martin 
      4       1.1    martin /*
      5       1.1    martin  * Copyright (c) 2006 Jonathan Gray <jsg (at) openbsd.org>
      6       1.1    martin  *
      7       1.1    martin  * Permission to use, copy, modify, and distribute this software for any
      8       1.1    martin  * purpose with or without fee is hereby granted, provided that the above
      9       1.1    martin  * copyright notice and this permission notice appear in all copies.
     10       1.1    martin  *
     11       1.1    martin  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12       1.1    martin  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13       1.1    martin  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14       1.1    martin  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15       1.1    martin  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16       1.1    martin  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17       1.1    martin  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18       1.1    martin  */
     19       1.1    martin 
     20       1.1    martin #include <sys/param.h>
     21       1.1    martin #include <sys/systm.h>
     22       1.1    martin #include <sys/kernel.h>
     23       1.1    martin #include <sys/conf.h>
     24       1.1    martin #include <sys/tty.h>
     25       1.1    martin #include <sys/device.h>
     26       1.1    martin 
     27       1.1    martin #include <dev/usb/usb.h>
     28       1.1    martin #include <dev/usb/usbdi.h>
     29       1.1    martin #include <dev/usb/usbdi_util.h>
     30       1.1    martin #include <dev/usb/usbdevs.h>
     31       1.1    martin 
     32       1.1    martin #include <dev/usb/ucomvar.h>
     33       1.1    martin 
     34       1.1    martin #ifdef UARK_DEBUG
     35       1.1    martin #define DPRINTFN(n, x)  do { if (uarkdebug > (n)) printf x; } while (0)
     36       1.1    martin int	uarkebug = 0;
     37       1.1    martin #else
     38       1.1    martin #define DPRINTFN(n, x)
     39       1.1    martin #endif
     40       1.1    martin #define DPRINTF(x) DPRINTFN(0, x)
     41       1.1    martin 
     42       1.1    martin #define UARKBUFSZ		256
     43       1.1    martin #define UARK_CONFIG_NO	0
     44       1.1    martin #define UARK_IFACE_NO		0
     45       1.1    martin 
     46       1.1    martin #define UARK_SET_DATA_BITS(x)	(x - 5)
     47       1.1    martin 
     48       1.1    martin #define UARK_PARITY_NONE	0x00
     49       1.1    martin #define UARK_PARITY_ODD		0x08
     50       1.1    martin #define UARK_PARITY_EVEN	0x18
     51       1.1    martin 
     52       1.1    martin #define UARK_STOP_BITS_1	0x00
     53       1.1    martin #define UARK_STOP_BITS_2	0x04
     54       1.1    martin 
     55       1.1    martin #define UARK_BAUD_REF		3000000
     56       1.1    martin 
     57       1.1    martin #define UARK_WRITE		0x40
     58       1.1    martin #define UARK_READ		0xc0
     59       1.1    martin 
     60       1.1    martin #define UARK_REQUEST		0xfe
     61       1.1    martin 
     62       1.1    martin struct uark_softc {
     63       1.6       chs 	device_t		sc_dev;
     64  1.6.14.2     skrll 	struct usbd_device *	sc_udev;
     65  1.6.14.2     skrll 	struct usbd_interface *	sc_iface;
     66       1.6       chs 	device_t		sc_subdev;
     67       1.1    martin 
     68       1.6       chs 	u_char			sc_msr;
     69       1.6       chs 	u_char			sc_lsr;
     70       1.1    martin 
     71       1.6       chs 	u_char			sc_dying;
     72       1.1    martin };
     73       1.1    martin 
     74       1.1    martin void	uark_get_status(void *, int portno, u_char *lsr, u_char *msr);
     75       1.1    martin void	uark_set(void *, int, int, int);
     76       1.1    martin int	uark_param(void *, int, struct termios *);
     77       1.1    martin void	uark_break(void *, int, int);
     78       1.1    martin int	uark_cmd(struct uark_softc *, uint16_t, uint16_t);
     79       1.1    martin 
     80       1.1    martin struct ucom_methods uark_methods = {
     81  1.6.14.1     skrll 	.ucom_get_status = uark_get_status,
     82  1.6.14.1     skrll 	.ucom_set = uark_set,
     83  1.6.14.1     skrll 	.ucom_param = uark_param,
     84  1.6.14.1     skrll 	.ucom_ioctl = NULL,
     85  1.6.14.1     skrll 	.ucom_open = NULL,
     86  1.6.14.1     skrll 	.ucom_close = NULL,
     87  1.6.14.1     skrll 	.ucom_read = NULL,
     88  1.6.14.1     skrll 	.ucom_write = NULL,
     89       1.1    martin };
     90       1.1    martin 
     91       1.1    martin static const struct usb_devno uark_devs[] = {
     92       1.1    martin 	{ USB_VENDOR_ARKMICROCHIPS, USB_PRODUCT_ARKMICROCHIPS_USBSERIAL },
     93       1.1    martin };
     94       1.1    martin 
     95       1.2    dyoung int             uark_match(device_t, cfdata_t, void *);
     96       1.2    dyoung void            uark_attach(device_t, device_t, void *);
     97       1.2    dyoung int             uark_detach(device_t, int);
     98       1.2    dyoung int             uark_activate(device_t, enum devact);
     99       1.2    dyoung extern struct cfdriver uark_cd;
    100       1.2    dyoung CFATTACH_DECL_NEW(uark, sizeof(struct uark_softc), uark_match, uark_attach, uark_detach, uark_activate);
    101       1.1    martin 
    102       1.5  jakllsch int
    103       1.2    dyoung uark_match(device_t parent, cfdata_t match, void *aux)
    104       1.1    martin {
    105       1.2    dyoung 	struct usb_attach_arg *uaa = aux;
    106       1.1    martin 
    107       1.1    martin 	return (usb_lookup(uark_devs, uaa->vendor, uaa->product) != NULL) ?
    108       1.1    martin 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
    109       1.1    martin }
    110       1.1    martin 
    111       1.5  jakllsch void
    112       1.2    dyoung uark_attach(device_t parent, device_t self, void *aux)
    113       1.1    martin {
    114       1.2    dyoung 	struct uark_softc *sc = device_private(self);
    115       1.2    dyoung 	struct usb_attach_arg *uaa = aux;
    116  1.6.14.2     skrll 	struct usbd_device * dev = uaa->device;
    117       1.1    martin 	char *devinfop;
    118       1.1    martin 	struct ucom_attach_args uca;
    119       1.1    martin 	usb_interface_descriptor_t *id;
    120       1.1    martin 	usb_endpoint_descriptor_t *ed;
    121       1.1    martin 	usbd_status error;
    122       1.1    martin 	int i;
    123       1.1    martin 
    124       1.1    martin 	memset(&uca, 0, sizeof(uca));
    125       1.1    martin 	sc->sc_dev = self;
    126       1.1    martin 
    127       1.1    martin 	devinfop = usbd_devinfo_alloc(dev, 0);
    128       1.2    dyoung 	aprint_naive("\n");
    129       1.2    dyoung 	aprint_normal("\n");
    130       1.1    martin 	aprint_normal_dev(self, "%s\n", devinfop);
    131       1.1    martin 	usbd_devinfo_free(devinfop);
    132       1.1    martin 
    133       1.1    martin 	sc->sc_udev = dev;
    134       1.1    martin 
    135       1.1    martin 	if (usbd_set_config_index(sc->sc_udev, UARK_CONFIG_NO, 1) != 0) {
    136       1.1    martin 		aprint_error_dev(self, "could not set configuration no\n");
    137       1.1    martin 		sc->sc_dying = 1;
    138       1.1    martin 		return;
    139       1.1    martin 	}
    140       1.1    martin 
    141       1.1    martin 	/* get the first interface handle */
    142       1.1    martin 	error = usbd_device2interface_handle(sc->sc_udev, UARK_IFACE_NO,
    143       1.1    martin 	    &sc->sc_iface);
    144       1.1    martin 	if (error != 0) {
    145       1.1    martin 		aprint_error_dev(self, "could not get interface handle\n");
    146       1.1    martin 		sc->sc_dying = 1;
    147       1.1    martin 		return;
    148       1.1    martin 	}
    149       1.1    martin 
    150       1.1    martin 	id = usbd_get_interface_descriptor(sc->sc_iface);
    151       1.1    martin 
    152       1.1    martin 	uca.bulkin = uca.bulkout = -1;
    153       1.1    martin 	for (i = 0; i < id->bNumEndpoints; i++) {
    154       1.1    martin 		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
    155       1.1    martin 		if (ed == NULL) {
    156       1.1    martin 			aprint_error_dev(self, "no endpoint descriptor found for %d\n",
    157       1.1    martin 			    i);
    158       1.1    martin 			sc->sc_dying = 1;
    159       1.1    martin 			return;
    160       1.1    martin 		}
    161       1.1    martin 
    162       1.1    martin 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    163       1.1    martin 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    164       1.1    martin 			uca.bulkin = ed->bEndpointAddress;
    165       1.1    martin 		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    166       1.1    martin 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
    167       1.1    martin 			uca.bulkout = ed->bEndpointAddress;
    168       1.1    martin 	}
    169       1.1    martin 
    170       1.1    martin 	if (uca.bulkin == -1 || uca.bulkout == -1) {
    171       1.1    martin 		aprint_error_dev(self, "missing endpoint\n");
    172       1.1    martin 		sc->sc_dying = 1;
    173       1.1    martin 		return;
    174       1.1    martin 	}
    175       1.1    martin 
    176       1.1    martin 	uca.ibufsize = UARKBUFSZ;
    177       1.1    martin 	uca.obufsize = UARKBUFSZ;
    178       1.1    martin 	uca.ibufsizepad = UARKBUFSZ;
    179       1.1    martin 	uca.opkthdrlen = 0;
    180       1.1    martin 	uca.device = sc->sc_udev;
    181       1.1    martin 	uca.iface = sc->sc_iface;
    182       1.1    martin 	uca.methods = &uark_methods;
    183       1.1    martin 	uca.arg = sc;
    184       1.1    martin 	uca.info = NULL;
    185       1.1    martin 
    186       1.1    martin 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
    187       1.1    martin 	    sc->sc_dev);
    188       1.5  jakllsch 
    189       1.1    martin 	sc->sc_subdev = config_found_sm_loc(self, "ucombus", NULL, &uca,
    190       1.1    martin 					    ucomprint, ucomsubmatch);
    191       1.1    martin 
    192       1.2    dyoung 	return;
    193       1.1    martin }
    194       1.1    martin 
    195       1.1    martin int
    196       1.6       chs uark_detach(device_t self, int flags)
    197       1.1    martin {
    198       1.1    martin 	struct uark_softc *sc = device_private(self);
    199       1.1    martin 	int rv = 0;
    200       1.1    martin 
    201       1.1    martin 	sc->sc_dying = 1;
    202       1.1    martin 	if (sc->sc_subdev != NULL) {
    203       1.1    martin 		rv = config_detach(sc->sc_subdev, flags);
    204       1.1    martin 		sc->sc_subdev = NULL;
    205       1.1    martin 	}
    206       1.1    martin 
    207       1.1    martin 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
    208       1.1    martin 			   sc->sc_dev);
    209       1.1    martin 
    210       1.1    martin 	return rv;
    211       1.1    martin }
    212       1.1    martin 
    213       1.1    martin int
    214       1.6       chs uark_activate(device_t self, enum devact act)
    215       1.1    martin {
    216       1.1    martin 	struct uark_softc *sc = device_private(self);
    217       1.1    martin 	int rv = 0;
    218       1.1    martin 
    219       1.1    martin 	switch (act) {
    220       1.1    martin 	case DVACT_DEACTIVATE:
    221       1.1    martin 		if (sc->sc_subdev != NULL)
    222       1.1    martin 			rv = config_deactivate(sc->sc_subdev);
    223       1.1    martin 		sc->sc_dying = 1;
    224       1.1    martin 		break;
    225       1.1    martin 	}
    226       1.1    martin 	return (rv);
    227       1.1    martin }
    228       1.1    martin 
    229       1.1    martin void
    230       1.1    martin uark_set(void *vsc, int portno, int reg, int onoff)
    231       1.1    martin {
    232       1.1    martin 	struct uark_softc *sc = vsc;
    233       1.1    martin 
    234       1.1    martin 	switch (reg) {
    235       1.1    martin 	case UCOM_SET_BREAK:
    236       1.1    martin 		uark_break(sc, portno, onoff);
    237       1.1    martin 		return;
    238       1.1    martin 	case UCOM_SET_DTR:
    239       1.1    martin 	case UCOM_SET_RTS:
    240       1.1    martin 	default:
    241       1.1    martin 		return;
    242       1.1    martin 	}
    243       1.1    martin }
    244       1.1    martin 
    245       1.1    martin int
    246       1.1    martin uark_param(void *vsc, int portno, struct termios *t)
    247       1.1    martin {
    248       1.1    martin 	struct uark_softc *sc = (struct uark_softc *)vsc;
    249       1.1    martin 	int data;
    250       1.1    martin 
    251       1.1    martin 	switch (t->c_ospeed) {
    252       1.1    martin 	case 300:
    253       1.1    martin 	case 600:
    254       1.1    martin 	case 1200:
    255       1.1    martin 	case 1800:
    256       1.1    martin 	case 2400:
    257       1.1    martin 	case 4800:
    258       1.1    martin 	case 9600:
    259       1.1    martin 	case 19200:
    260       1.1    martin 	case 38400:
    261       1.1    martin 	case 57600:
    262       1.1    martin 	case 115200:
    263       1.1    martin 		uark_cmd(sc, 3, 0x83);
    264       1.1    martin 		uark_cmd(sc, 0, (UARK_BAUD_REF / t->c_ospeed) & 0xFF);
    265       1.1    martin 		uark_cmd(sc, 1, (UARK_BAUD_REF / t->c_ospeed) >> 8);
    266       1.1    martin 		uark_cmd(sc, 3, 0x03);
    267       1.1    martin 		break;
    268       1.1    martin 	default:
    269       1.1    martin 		return (EINVAL);
    270       1.1    martin 	}
    271       1.1    martin 
    272       1.1    martin 	if (ISSET(t->c_cflag, CSTOPB))
    273       1.1    martin 		data = UARK_STOP_BITS_2;
    274       1.1    martin 	else
    275       1.1    martin 		data = UARK_STOP_BITS_1;
    276       1.1    martin 
    277       1.1    martin 	if (ISSET(t->c_cflag, PARENB)) {
    278       1.1    martin 		if (ISSET(t->c_cflag, PARODD))
    279       1.1    martin 			data |= UARK_PARITY_ODD;
    280       1.1    martin 		else
    281       1.1    martin 			data |= UARK_PARITY_EVEN;
    282       1.1    martin 	} else
    283       1.1    martin 		data |= UARK_PARITY_NONE;
    284       1.1    martin 
    285       1.1    martin 	switch (ISSET(t->c_cflag, CSIZE)) {
    286       1.1    martin 	case CS5:
    287       1.1    martin 		data |= UARK_SET_DATA_BITS(5);
    288       1.1    martin 		break;
    289       1.1    martin 	case CS6:
    290       1.1    martin 		data |= UARK_SET_DATA_BITS(6);
    291       1.1    martin 		break;
    292       1.1    martin 	case CS7:
    293       1.1    martin 		data |= UARK_SET_DATA_BITS(7);
    294       1.1    martin 		break;
    295       1.1    martin 	case CS8:
    296       1.1    martin 		data |= UARK_SET_DATA_BITS(8);
    297       1.1    martin 		break;
    298       1.1    martin 	}
    299       1.1    martin 
    300       1.1    martin 	uark_cmd(sc, 3, 0x00);
    301       1.1    martin 	uark_cmd(sc, 3, data);
    302       1.1    martin 
    303       1.1    martin #if 0
    304       1.1    martin 	/* XXX flow control */
    305       1.1    martin 	if (ISSET(t->c_cflag, CRTSCTS))
    306       1.1    martin 		/*  rts/cts flow ctl */
    307       1.1    martin 	} else if (ISSET(t->c_iflag, IXON|IXOFF)) {
    308       1.1    martin 		/*  xon/xoff flow ctl */
    309       1.1    martin 	} else {
    310       1.1    martin 		/* disable flow ctl */
    311       1.1    martin 	}
    312       1.1    martin #endif
    313       1.1    martin 
    314       1.1    martin 	return (0);
    315       1.1    martin }
    316       1.1    martin 
    317       1.1    martin void
    318       1.1    martin uark_get_status(void *vsc, int portno, u_char *lsr, u_char *msr)
    319       1.1    martin {
    320       1.1    martin 	struct uark_softc *sc = vsc;
    321       1.5  jakllsch 
    322       1.1    martin 	if (msr != NULL)
    323       1.1    martin 		*msr = sc->sc_msr;
    324       1.1    martin 	if (lsr != NULL)
    325       1.1    martin 		*lsr = sc->sc_lsr;
    326       1.1    martin }
    327       1.1    martin 
    328       1.1    martin void
    329       1.1    martin uark_break(void *vsc, int portno, int onoff)
    330       1.1    martin {
    331       1.1    martin #if 0
    332       1.1    martin 	struct uark_softc *sc = vsc;
    333       1.1    martin 
    334       1.1    martin #ifdef UARK_DEBUG
    335       1.1    martin 	aprint_normal_dev(sc->sc_dev, "break %s!\n", onoff ? "on" : "off");
    336       1.1    martin #endif
    337       1.1    martin 
    338       1.1    martin 	if (onoff)
    339       1.1    martin 		/* break on */
    340       1.1    martin 		uark_cmd(sc, 4, 0x01);
    341       1.1    martin 	else
    342       1.1    martin 		uark_cmd(sc, 4, 0x00);
    343       1.1    martin #endif
    344       1.1    martin }
    345       1.1    martin 
    346       1.1    martin int
    347       1.1    martin uark_cmd(struct uark_softc *sc, uint16_t index, uint16_t value)
    348       1.1    martin {
    349       1.1    martin 	usb_device_request_t req;
    350       1.1    martin 	usbd_status err;
    351       1.1    martin 
    352       1.1    martin 	req.bmRequestType = UARK_WRITE;
    353       1.1    martin 	req.bRequest = UARK_REQUEST;
    354       1.1    martin 	USETW(req.wValue, value);
    355       1.1    martin 	USETW(req.wIndex, index);
    356       1.1    martin 	USETW(req.wLength, 0);
    357       1.1    martin 	err = usbd_do_request(sc->sc_udev, &req, NULL);
    358       1.1    martin 
    359       1.1    martin 	if (err)
    360       1.1    martin 		return (EIO);
    361       1.1    martin 
    362       1.1    martin 	return (0);
    363       1.1    martin }
    364