Home | History | Annotate | Line # | Download | only in usb
ubsa_common.c revision 1.4
      1 /*	$NetBSD: ubsa_common.c,v 1.4 2008/05/24 16:40:58 cube Exp $	*/
      2 /*-
      3  * Copyright (c) 2002, Alexander Kabaev <kan.FreeBSD.org>.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 /*
     28  * Copyright (c) 2001 The NetBSD Foundation, Inc.
     29  * All rights reserved.
     30  *
     31  * This code is derived from software contributed to The NetBSD Foundation
     32  * by Ichiro FUKUHARA (ichiro (at) ichiro.org).
     33  *
     34  * Redistribution and use in source and binary forms, with or without
     35  * modification, are permitted provided that the following conditions
     36  * are met:
     37  * 1. Redistributions of source code must retain the above copyright
     38  *    notice, this list of conditions and the following disclaimer.
     39  * 2. Redistributions in binary form must reproduce the above copyright
     40  *    notice, this list of conditions and the following disclaimer in the
     41  *    documentation and/or other materials provided with the distribution.
     42  *
     43  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     44  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     45  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     46  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     47  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     48  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     49  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     50  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     51  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     52  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     53  * POSSIBILITY OF SUCH DAMAGE.
     54  */
     55 
     56 #include <sys/cdefs.h>
     57 __KERNEL_RCSID(0, "$NetBSD: ubsa_common.c,v 1.4 2008/05/24 16:40:58 cube Exp $");
     58 
     59 #include <sys/param.h>
     60 #include <sys/systm.h>
     61 #include <sys/kernel.h>
     62 #include <sys/malloc.h>
     63 #ifdef __FreeBSD__
     64 #include <sys/bus.h>
     65 #endif
     66 #include <sys/ioccom.h>
     67 #include <sys/fcntl.h>
     68 #include <sys/conf.h>
     69 #include <sys/tty.h>
     70 #include <sys/file.h>
     71 #if __FreeBSD_version >= 500014
     72 #include <sys/selinfo.h>
     73 #else
     74 #include <sys/select.h>
     75 #endif
     76 #include <sys/proc.h>
     77 #include <sys/device.h>
     78 #include <sys/poll.h>
     79 #include <sys/sysctl.h>
     80 #include <sys/bus.h>
     81 
     82 #include <dev/usb/usb.h>
     83 #include <dev/usb/usbdi.h>
     84 #include <dev/usb/usbdi_util.h>
     85 #include <dev/usb/usbdivar.h>
     86 
     87 #include <dev/usb/usbcdc.h>
     88 #include <dev/usb/usbdevs.h>
     89 #include <dev/usb/usb_quirks.h>
     90 #include <dev/usb/ucomvar.h>
     91 #include <dev/usb/ubsavar.h>
     92 
     93 #ifdef UBSA_DEBUG
     94 extern	int	ubsadebug;
     95 #define	DPRINTFN(n, x)	do { \
     96 				if (ubsadebug > (n)) \
     97 					logprintf x; \
     98 			} while (0)
     99 #else
    100 #define	DPRINTFN(n, x)
    101 #endif
    102 #define	DPRINTF(x) DPRINTFN(0, x)
    103 
    104 int
    105 ubsa_request(struct ubsa_softc *sc, int portno, u_int8_t request, u_int16_t value)
    106 {
    107 	usb_device_request_t req;
    108 	usbd_status err;
    109 
    110 	if (sc->sc_quadumts)
    111 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
    112 	else
    113 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
    114 
    115 	if (portno > UBSA_MAXCONN) {
    116 		printf("%s: ubsa_request: invalid port(%d)#\n",
    117 			USBDEVNAME(sc->sc_dev), portno);
    118 		return USBD_INVAL;
    119 	}
    120 
    121 	req.bRequest = request;
    122 	USETW(req.wValue, value);
    123 	USETW(req.wIndex, sc->sc_iface_number[portno]);
    124 	USETW(req.wLength, 0);
    125 
    126 	err = usbd_do_request(sc->sc_udev, &req, 0);
    127 	if (err)
    128 		printf("%s: ubsa_request: %s\n",
    129 		    USBDEVNAME(sc->sc_dev), usbd_errstr(err));
    130 	return (err);
    131 }
    132 
    133 void
    134 ubsa_dtr(struct ubsa_softc *sc, int portno, int onoff)
    135 {
    136 
    137 	DPRINTF(("ubsa_dtr: onoff = %d\n", onoff));
    138 
    139 	if (sc->sc_dtr == onoff)
    140 		return;
    141 	sc->sc_dtr = onoff;
    142 
    143 	ubsa_request(sc, portno, UBSA_SET_DTR, onoff ? 1 : 0);
    144 }
    145 
    146 void
    147 ubsa_rts(struct ubsa_softc *sc, int portno, int onoff)
    148 {
    149 
    150 	DPRINTF(("ubsa_rts: onoff = %d\n", onoff));
    151 
    152 	if (sc->sc_rts == onoff)
    153 		return;
    154 	sc->sc_rts = onoff;
    155 
    156 	ubsa_request(sc, portno, UBSA_SET_RTS, onoff ? 1 : 0);
    157 }
    158 
    159 void
    160 ubsa_quadumts_dtr(struct ubsa_softc *sc, int portno, int onoff)
    161 {
    162 
    163 	DPRINTF(("ubsa_dtr: onoff = %d\n", onoff));
    164 
    165 	if (sc->sc_dtr == onoff)
    166 		return;
    167 	sc->sc_dtr = onoff;
    168 
    169 	ubsa_request(sc, portno, UBSA_QUADUMTS_SET_PIN,
    170 		 (sc->sc_rts ? 2 : 0)+(sc->sc_dtr ? 1 : 0));
    171 }
    172 
    173 void
    174 ubsa_quadumts_rts(struct ubsa_softc *sc, int portno, int onoff)
    175 {
    176 
    177 	DPRINTF(("ubsa_rts: onoff = %d\n", onoff));
    178 
    179 	if (sc->sc_rts == onoff)
    180 		return;
    181 	sc->sc_rts = onoff;
    182 
    183 	ubsa_request(sc, portno, UBSA_QUADUMTS_SET_PIN,
    184 		 (sc->sc_rts ? 2 : 0)+(sc->sc_dtr ? 1 : 0));
    185 }
    186 
    187 void
    188 ubsa_break(struct ubsa_softc *sc, int portno, int onoff)
    189 {
    190 	DPRINTF(("ubsa_rts: onoff = %d\n", onoff));
    191 
    192 	ubsa_request(sc, portno, UBSA_SET_BREAK, onoff ? 1 : 0);
    193 }
    194 
    195 void
    196 ubsa_set(void *addr, int portno, int reg, int onoff)
    197 {
    198 	struct ubsa_softc *sc;
    199 
    200 	sc = addr;
    201 	switch (reg) {
    202 	case UCOM_SET_DTR:
    203 		if (sc->sc_quadumts)
    204 			ubsa_quadumts_dtr(sc, portno, onoff);
    205 		else
    206 			ubsa_dtr(sc, portno, onoff);
    207 		break;
    208 	case UCOM_SET_RTS:
    209 		if (sc->sc_quadumts)
    210 			ubsa_quadumts_rts(sc, portno, onoff);
    211 		else
    212 			ubsa_rts(sc, portno, onoff);
    213 		break;
    214 	case UCOM_SET_BREAK:
    215 		if (!sc->sc_quadumts)
    216 			ubsa_break(sc, portno, onoff);
    217 		break;
    218 	default:
    219 		break;
    220 	}
    221 }
    222 
    223 void
    224 ubsa_baudrate(struct ubsa_softc *sc, int portno, speed_t speed)
    225 {
    226 	u_int16_t value = 0;
    227 
    228 	DPRINTF(("ubsa_baudrate: speed = %d\n", speed));
    229 
    230 	switch(speed) {
    231 	case B0:
    232 		break;
    233 	case B300:
    234 	case B600:
    235 	case B1200:
    236 	case B2400:
    237 	case B4800:
    238 	case B9600:
    239 	case B19200:
    240 	case B38400:
    241 	case B57600:
    242 	case B115200:
    243 	case B230400:
    244 		value = B230400 / speed;
    245 		break;
    246 	default:
    247 		printf("%s: ubsa_param: unsupported baudrate, "
    248 		    "forcing default of 9600\n",
    249 		    USBDEVNAME(sc->sc_dev));
    250 		value = B230400 / B9600;
    251 		break;
    252 	};
    253 
    254 	if (speed == B0) {
    255 		ubsa_flow(sc, portno, 0, 0);
    256 		ubsa_dtr(sc, portno, 0);
    257 		ubsa_rts(sc, portno, 0);
    258 	} else
    259 		ubsa_request(sc, portno, UBSA_SET_BAUDRATE, value);
    260 }
    261 
    262 void
    263 ubsa_parity(struct ubsa_softc *sc, int portno, tcflag_t cflag)
    264 {
    265 	int value;
    266 
    267 	DPRINTF(("ubsa_parity: cflag = 0x%x\n", cflag));
    268 
    269 	if (cflag & PARENB)
    270 		value = (cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN;
    271 	else
    272 		value = UBSA_PARITY_NONE;
    273 
    274 	ubsa_request(sc, portno, UBSA_SET_PARITY, value);
    275 }
    276 
    277 void
    278 ubsa_databits(struct ubsa_softc *sc, int portno, tcflag_t cflag)
    279 {
    280 	int value;
    281 
    282 	DPRINTF(("ubsa_databits: cflag = 0x%x\n", cflag));
    283 
    284 	switch (cflag & CSIZE) {
    285 	case CS5: value = 0; break;
    286 	case CS6: value = 1; break;
    287 	case CS7: value = 2; break;
    288 	case CS8: value = 3; break;
    289 	default:
    290 		printf("%s: ubsa_param: unsupported databits requested, "
    291 		    "forcing default of 8\n",
    292 		    USBDEVNAME(sc->sc_dev));
    293 		value = 3;
    294 	}
    295 
    296 	ubsa_request(sc, portno, UBSA_SET_DATA_BITS, value);
    297 }
    298 
    299 void
    300 ubsa_stopbits(struct ubsa_softc *sc, int portno, tcflag_t cflag)
    301 {
    302 	int value;
    303 
    304 	DPRINTF(("ubsa_stopbits: cflag = 0x%x\n", cflag));
    305 
    306 	value = (cflag & CSTOPB) ? 1 : 0;
    307 
    308 	ubsa_request(sc, portno, UBSA_SET_STOP_BITS, value);
    309 }
    310 
    311 void
    312 ubsa_flow(struct ubsa_softc *sc, int portno, tcflag_t cflag, tcflag_t iflag)
    313 {
    314 	int value;
    315 
    316 	DPRINTF(("ubsa_flow: cflag = 0x%x, iflag = 0x%x\n", cflag, iflag));
    317 
    318 	value = 0;
    319 	if (cflag & CRTSCTS)
    320 		value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS;
    321 	if (iflag & (IXON|IXOFF))
    322 		value |= UBSA_FLOW_OXON | UBSA_FLOW_IXON;
    323 
    324 	ubsa_request(sc, portno, UBSA_SET_FLOW_CTRL, value);
    325 }
    326 
    327 int
    328 ubsa_param(void *addr, int portno, struct termios *ti)
    329 {
    330 	struct ubsa_softc *sc = addr;
    331 
    332 	DPRINTF(("ubsa_param: sc = %p\n", sc));
    333 
    334 	if (!sc->sc_quadumts) {
    335 		ubsa_baudrate(sc, portno, ti->c_ospeed);
    336 		ubsa_parity(sc, portno, ti->c_cflag);
    337 		ubsa_databits(sc, portno, ti->c_cflag);
    338 		ubsa_stopbits(sc, portno, ti->c_cflag);
    339 		ubsa_flow(sc, portno, ti->c_cflag, ti->c_iflag);
    340 	}
    341 
    342 	return (0);
    343 }
    344 
    345 int
    346 ubsa_open(void *addr, int portno)
    347 {
    348 	struct ubsa_softc *sc = addr;
    349 	int err;
    350 
    351 	if (sc->sc_dying)
    352 		return (ENXIO);
    353 
    354 	if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) {
    355 		sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK);
    356 		/* XXX only iface# = 0 has intr line */
    357 		/* XXX E220 specific? need to check */
    358 		err = usbd_open_pipe_intr(sc->sc_iface[0],
    359 		    sc->sc_intr_number,
    360 		    USBD_SHORT_XFER_OK,
    361 		    &sc->sc_intr_pipe,
    362 		    sc,
    363 		    sc->sc_intr_buf,
    364 		    sc->sc_isize,
    365 		    ubsa_intr,
    366 		    UBSA_INTR_INTERVAL);
    367 		if (err) {
    368 			printf("%s: cannot open interrupt pipe (addr %d)\n",
    369 			    USBDEVNAME(sc->sc_dev),
    370 			    sc->sc_intr_number);
    371 			return (EIO);
    372 		}
    373 	}
    374 
    375 	return (0);
    376 }
    377 
    378 void
    379 ubsa_close(void *addr, int portno)
    380 {
    381 	struct ubsa_softc *sc = addr;
    382 	int err;
    383 
    384 	if (sc->sc_dying)
    385 		return;
    386 
    387 	DPRINTF(("ubsa_close: close\n"));
    388 
    389 	if (sc->sc_intr_pipe != NULL) {
    390 		err = usbd_abort_pipe(sc->sc_intr_pipe);
    391 		if (err)
    392 			printf("%s: abort interrupt pipe failed: %s\n",
    393 			    USBDEVNAME(sc->sc_dev),
    394 			    usbd_errstr(err));
    395 		err = usbd_close_pipe(sc->sc_intr_pipe);
    396 		if (err)
    397 			printf("%s: close interrupt pipe failed: %s\n",
    398 			    USBDEVNAME(sc->sc_dev),
    399 			    usbd_errstr(err));
    400 		free(sc->sc_intr_buf, M_USBDEV);
    401 		sc->sc_intr_pipe = NULL;
    402 	}
    403 }
    404 
    405 void
    406 ubsa_intr(usbd_xfer_handle xfer, usbd_private_handle priv,
    407     usbd_status status)
    408 {
    409 	struct ubsa_softc *sc = priv;
    410 	u_char *buf;
    411 	int i;
    412 
    413 	buf = sc->sc_intr_buf;
    414 	if (sc->sc_dying)
    415 		return;
    416 
    417 	if (status != USBD_NORMAL_COMPLETION) {
    418 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
    419 			return;
    420 
    421 		DPRINTF(("%s: ubsa_intr: abnormal status: %s\n",
    422 		    USBDEVNAME(sc->sc_dev), usbd_errstr(status)));
    423 		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
    424 		return;
    425 	}
    426 
    427 	/* incidentally, Belkin adapter status bits match UART 16550 bits */
    428 	sc->sc_lsr = buf[2];
    429 	sc->sc_msr = buf[3];
    430 
    431 	DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n",
    432 	    USBDEVNAME(sc->sc_dev), sc->sc_lsr, sc->sc_msr));
    433 
    434 	for (i = 0; i < sc->sc_numif; i++) {
    435 		ucom_status_change(device_private(sc->sc_subdevs[i]));
    436 	}
    437 }
    438 
    439 void
    440 ubsa_get_status(void *addr, int portno, u_char *lsr, u_char *msr)
    441 {
    442 	struct ubsa_softc *sc = addr;
    443 
    444 	DPRINTF(("ubsa_get_status\n"));
    445 
    446 	if (lsr != NULL)
    447 		*lsr = sc->sc_lsr;
    448 	if (msr != NULL)
    449 		*msr = sc->sc_msr;
    450 }
    451 
    452