1 /* $NetBSD: ubsa_common.c,v 1.9 2012/12/11 09:17:31 msaitoh 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@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.9 2012/12/11 09:17:31 msaitoh Exp $"); 58 59 #include <sys/param.h> 60 #include <sys/systm.h> 61 #include <sys/kernel.h> 62 #include <sys/malloc.h> 63 #include <sys/ioccom.h> 64 #include <sys/fcntl.h> 65 #include <sys/conf.h> 66 #include <sys/tty.h> 67 #include <sys/file.h> 68 #include <sys/select.h> 69 #include <sys/proc.h> 70 #include <sys/device.h> 71 #include <sys/poll.h> 72 #include <sys/sysctl.h> 73 #include <sys/bus.h> 74 75 #include <dev/usb/usb.h> 76 #include <dev/usb/usbdi.h> 77 #include <dev/usb/usbdi_util.h> 78 #include <dev/usb/usbdivar.h> 79 80 #include <dev/usb/usbcdc.h> 81 #include <dev/usb/usbdevs.h> 82 #include <dev/usb/usb_quirks.h> 83 #include <dev/usb/ucomvar.h> 84 #include <dev/usb/ubsavar.h> 85 86 #ifdef UBSA_DEBUG 87 extern int ubsadebug; 88 #define DPRINTFN(n, x) do { \ 89 if (ubsadebug > (n)) \ 90 printf x; \ 91 } while (0) 92 #else 93 #define DPRINTFN(n, x) 94 #endif 95 #define DPRINTF(x) DPRINTFN(0, x) 96 97 int 98 ubsa_request(struct ubsa_softc *sc, int portno, u_int8_t request, u_int16_t value) 99 { 100 usb_device_request_t req; 101 usbd_status err; 102 103 if (sc->sc_quadumts) 104 req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 105 else 106 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 107 108 if (portno >= UBSA_MAXCONN) { 109 printf("%s: ubsa_request: invalid port(%d)#\n", 110 device_xname(sc->sc_dev), portno); 111 return USBD_INVAL; 112 } 113 114 req.bRequest = request; 115 USETW(req.wValue, value); 116 USETW(req.wIndex, sc->sc_iface_number[portno]); 117 USETW(req.wLength, 0); 118 119 err = usbd_do_request(sc->sc_udev, &req, 0); 120 if (err) 121 printf("%s: ubsa_request: %s\n", 122 device_xname(sc->sc_dev), usbd_errstr(err)); 123 return (err); 124 } 125 126 void 127 ubsa_dtr(struct ubsa_softc *sc, int portno, int onoff) 128 { 129 130 DPRINTF(("ubsa_dtr: onoff = %d\n", onoff)); 131 132 if (sc->sc_dtr == onoff) 133 return; 134 sc->sc_dtr = onoff; 135 136 ubsa_request(sc, portno, UBSA_SET_DTR, onoff ? 1 : 0); 137 } 138 139 void 140 ubsa_rts(struct ubsa_softc *sc, int portno, int onoff) 141 { 142 143 DPRINTF(("ubsa_rts: onoff = %d\n", onoff)); 144 145 if (sc->sc_rts == onoff) 146 return; 147 sc->sc_rts = onoff; 148 149 ubsa_request(sc, portno, UBSA_SET_RTS, onoff ? 1 : 0); 150 } 151 152 void 153 ubsa_quadumts_dtr(struct ubsa_softc *sc, int portno, int onoff) 154 { 155 156 DPRINTF(("ubsa_dtr: onoff = %d\n", onoff)); 157 158 if (sc->sc_dtr == onoff) 159 return; 160 sc->sc_dtr = onoff; 161 162 ubsa_request(sc, portno, UBSA_QUADUMTS_SET_PIN, 163 (sc->sc_rts ? 2 : 0)+(sc->sc_dtr ? 1 : 0)); 164 } 165 166 void 167 ubsa_quadumts_rts(struct ubsa_softc *sc, int portno, int onoff) 168 { 169 170 DPRINTF(("ubsa_rts: onoff = %d\n", onoff)); 171 172 if (sc->sc_rts == onoff) 173 return; 174 sc->sc_rts = onoff; 175 176 ubsa_request(sc, portno, UBSA_QUADUMTS_SET_PIN, 177 (sc->sc_rts ? 2 : 0)+(sc->sc_dtr ? 1 : 0)); 178 } 179 180 void 181 ubsa_break(struct ubsa_softc *sc, int portno, int onoff) 182 { 183 DPRINTF(("ubsa_rts: onoff = %d\n", onoff)); 184 185 ubsa_request(sc, portno, UBSA_SET_BREAK, onoff ? 1 : 0); 186 } 187 188 void 189 ubsa_set(void *addr, int portno, int reg, int onoff) 190 { 191 struct ubsa_softc *sc; 192 193 sc = addr; 194 switch (reg) { 195 case UCOM_SET_DTR: 196 if (sc->sc_quadumts) 197 ubsa_quadumts_dtr(sc, portno, onoff); 198 else 199 ubsa_dtr(sc, portno, onoff); 200 break; 201 case UCOM_SET_RTS: 202 if (sc->sc_quadumts) 203 ubsa_quadumts_rts(sc, portno, onoff); 204 else 205 ubsa_rts(sc, portno, onoff); 206 break; 207 case UCOM_SET_BREAK: 208 if (!sc->sc_quadumts) 209 ubsa_break(sc, portno, onoff); 210 break; 211 default: 212 break; 213 } 214 } 215 216 void 217 ubsa_baudrate(struct ubsa_softc *sc, int portno, speed_t speed) 218 { 219 u_int16_t value = 0; 220 221 DPRINTF(("ubsa_baudrate: speed = %d\n", speed)); 222 223 switch(speed) { 224 case B0: 225 break; 226 case B300: 227 case B600: 228 case B1200: 229 case B2400: 230 case B4800: 231 case B9600: 232 case B19200: 233 case B38400: 234 case B57600: 235 case B115200: 236 case B230400: 237 value = B230400 / speed; 238 break; 239 default: 240 printf("%s: ubsa_param: unsupported baudrate, " 241 "forcing default of 9600\n", 242 device_xname(sc->sc_dev)); 243 value = B230400 / B9600; 244 break; 245 }; 246 247 if (speed == B0) { 248 ubsa_flow(sc, portno, 0, 0); 249 ubsa_dtr(sc, portno, 0); 250 ubsa_rts(sc, portno, 0); 251 } else 252 ubsa_request(sc, portno, UBSA_SET_BAUDRATE, value); 253 } 254 255 void 256 ubsa_parity(struct ubsa_softc *sc, int portno, tcflag_t cflag) 257 { 258 int value; 259 260 DPRINTF(("ubsa_parity: cflag = 0x%x\n", cflag)); 261 262 if (cflag & PARENB) 263 value = (cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN; 264 else 265 value = UBSA_PARITY_NONE; 266 267 ubsa_request(sc, portno, UBSA_SET_PARITY, value); 268 } 269 270 void 271 ubsa_databits(struct ubsa_softc *sc, int portno, tcflag_t cflag) 272 { 273 int value; 274 275 DPRINTF(("ubsa_databits: cflag = 0x%x\n", cflag)); 276 277 switch (cflag & CSIZE) { 278 case CS5: value = 0; break; 279 case CS6: value = 1; break; 280 case CS7: value = 2; break; 281 case CS8: value = 3; break; 282 default: 283 printf("%s: ubsa_param: unsupported databits requested, " 284 "forcing default of 8\n", 285 device_xname(sc->sc_dev)); 286 value = 3; 287 } 288 289 ubsa_request(sc, portno, UBSA_SET_DATA_BITS, value); 290 } 291 292 void 293 ubsa_stopbits(struct ubsa_softc *sc, int portno, tcflag_t cflag) 294 { 295 int value; 296 297 DPRINTF(("ubsa_stopbits: cflag = 0x%x\n", cflag)); 298 299 value = (cflag & CSTOPB) ? 1 : 0; 300 301 ubsa_request(sc, portno, UBSA_SET_STOP_BITS, value); 302 } 303 304 void 305 ubsa_flow(struct ubsa_softc *sc, int portno, tcflag_t cflag, tcflag_t iflag) 306 { 307 int value; 308 309 DPRINTF(("ubsa_flow: cflag = 0x%x, iflag = 0x%x\n", cflag, iflag)); 310 311 value = 0; 312 if (cflag & CRTSCTS) 313 value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS; 314 if (iflag & (IXON|IXOFF)) 315 value |= UBSA_FLOW_OXON | UBSA_FLOW_IXON; 316 317 ubsa_request(sc, portno, UBSA_SET_FLOW_CTRL, value); 318 } 319 320 int 321 ubsa_param(void *addr, int portno, struct termios *ti) 322 { 323 struct ubsa_softc *sc = addr; 324 325 DPRINTF(("ubsa_param: sc = %p\n", sc)); 326 327 if (!sc->sc_quadumts) { 328 ubsa_baudrate(sc, portno, ti->c_ospeed); 329 ubsa_parity(sc, portno, ti->c_cflag); 330 ubsa_databits(sc, portno, ti->c_cflag); 331 ubsa_stopbits(sc, portno, ti->c_cflag); 332 ubsa_flow(sc, portno, ti->c_cflag, ti->c_iflag); 333 } 334 335 return (0); 336 } 337 338 int 339 ubsa_open(void *addr, int portno) 340 { 341 struct ubsa_softc *sc = addr; 342 int err; 343 344 if (sc->sc_dying) 345 return (ENXIO); 346 347 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 348 sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); 349 /* XXX only iface# = 0 has intr line */ 350 /* XXX E220 specific? need to check */ 351 err = usbd_open_pipe_intr(sc->sc_iface[0], 352 sc->sc_intr_number, 353 USBD_SHORT_XFER_OK, 354 &sc->sc_intr_pipe, 355 sc, 356 sc->sc_intr_buf, 357 sc->sc_isize, 358 ubsa_intr, 359 UBSA_INTR_INTERVAL); 360 if (err) { 361 printf("%s: cannot open interrupt pipe (addr %d)\n", 362 device_xname(sc->sc_dev), 363 sc->sc_intr_number); 364 return (EIO); 365 } 366 } 367 368 return (0); 369 } 370 371 void 372 ubsa_close(void *addr, int portno) 373 { 374 struct ubsa_softc *sc = addr; 375 int err; 376 377 if (sc->sc_dying) 378 return; 379 380 DPRINTF(("ubsa_close: close\n")); 381 382 if (sc->sc_intr_pipe != NULL) { 383 err = usbd_abort_pipe(sc->sc_intr_pipe); 384 if (err) 385 printf("%s: abort interrupt pipe failed: %s\n", 386 device_xname(sc->sc_dev), 387 usbd_errstr(err)); 388 err = usbd_close_pipe(sc->sc_intr_pipe); 389 if (err) 390 printf("%s: close interrupt pipe failed: %s\n", 391 device_xname(sc->sc_dev), 392 usbd_errstr(err)); 393 free(sc->sc_intr_buf, M_USBDEV); 394 sc->sc_intr_pipe = NULL; 395 } 396 } 397 398 void 399 ubsa_intr(usbd_xfer_handle xfer, usbd_private_handle priv, 400 usbd_status status) 401 { 402 struct ubsa_softc *sc = priv; 403 u_char *buf; 404 int i; 405 406 buf = sc->sc_intr_buf; 407 if (sc->sc_dying) 408 return; 409 410 if (status != USBD_NORMAL_COMPLETION) { 411 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 412 return; 413 414 DPRINTF(("%s: ubsa_intr: abnormal status: %s\n", 415 device_xname(sc->sc_dev), usbd_errstr(status))); 416 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 417 return; 418 } 419 420 /* incidentally, Belkin adapter status bits match UART 16550 bits */ 421 sc->sc_lsr = buf[2]; 422 sc->sc_msr = buf[3]; 423 424 DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n", 425 device_xname(sc->sc_dev), sc->sc_lsr, sc->sc_msr)); 426 427 for (i = 0; i < sc->sc_numif; i++) { 428 ucom_status_change(device_private(sc->sc_subdevs[i])); 429 } 430 } 431 432 void 433 ubsa_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 434 { 435 struct ubsa_softc *sc = addr; 436 437 DPRINTF(("ubsa_get_status\n")); 438 439 if (lsr != NULL) 440 *lsr = sc->sc_lsr; 441 if (msr != NULL) 442 *msr = sc->sc_msr; 443 } 444 445