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