1/* $NetBSD: ubsa_common.c,v 1.15 2021/06/13 09:29:38 mlelstv 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.15 2021/06/13 09:29:38 mlelstv Exp $"); 58 59#include <sys/param.h> 60#include <sys/systm.h> 61#include <sys/kernel.h> 62#include <sys/kmem.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 87extern 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 97int 98ubsa_request(struct ubsa_softc *sc, int portno, uint8_t request, uint16_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 126void 127ubsa_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 139void 140ubsa_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 152void 153ubsa_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 166void 167ubsa_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 180void 181ubsa_break(struct ubsa_softc *sc, int portno, int onoff) 182{ 183 DPRINTF(("ubsa_rts: onoff = %d\n", onoff)); 184 185 if (sc->sc_dying) 186 return; 187 188 ubsa_request(sc, portno, UBSA_SET_BREAK, onoff ? 1 : 0); 189} 190 191void 192ubsa_set(void *addr, int portno, int reg, int onoff) 193{ 194 struct ubsa_softc *sc = addr; 195 196 if (sc->sc_dying) 197 return; 198 199 switch (reg) { 200 case UCOM_SET_DTR: 201 if (sc->sc_quadumts) 202 ubsa_quadumts_dtr(sc, portno, onoff); 203 else 204 ubsa_dtr(sc, portno, onoff); 205 break; 206 case UCOM_SET_RTS: 207 if (sc->sc_quadumts) 208 ubsa_quadumts_rts(sc, portno, onoff); 209 else 210 ubsa_rts(sc, portno, onoff); 211 break; 212 case UCOM_SET_BREAK: 213 if (!sc->sc_quadumts) 214 ubsa_break(sc, portno, onoff); 215 break; 216 default: 217 break; 218 } 219} 220 221void 222ubsa_baudrate(struct ubsa_softc *sc, int portno, speed_t speed) 223{ 224 uint16_t value = 0; 225 226 DPRINTF(("ubsa_baudrate: speed = %d\n", speed)); 227 228 switch(speed) { 229 case B0: 230 break; 231 case B300: 232 case B600: 233 case B1200: 234 case B2400: 235 case B4800: 236 case B9600: 237 case B19200: 238 case B38400: 239 case B57600: 240 case B115200: 241 case B230400: 242 value = B230400 / speed; 243 break; 244 default: 245 printf("%s: ubsa_param: unsupported baudrate, " 246 "forcing default of 9600\n", 247 device_xname(sc->sc_dev)); 248 value = B230400 / B9600; 249 break; 250 }; 251 252 if (speed == B0) { 253 ubsa_flow(sc, portno, 0, 0); 254 ubsa_dtr(sc, portno, 0); 255 ubsa_rts(sc, portno, 0); 256 } else 257 ubsa_request(sc, portno, UBSA_SET_BAUDRATE, value); 258} 259 260void 261ubsa_parity(struct ubsa_softc *sc, int portno, tcflag_t cflag) 262{ 263 int value; 264 265 DPRINTF(("ubsa_parity: cflag = %#x\n", cflag)); 266 267 if (cflag & PARENB) 268 value = (cflag & PARODD) ? UBSA_PARITY_ODD : UBSA_PARITY_EVEN; 269 else 270 value = UBSA_PARITY_NONE; 271 272 ubsa_request(sc, portno, UBSA_SET_PARITY, value); 273} 274 275void 276ubsa_databits(struct ubsa_softc *sc, int portno, tcflag_t cflag) 277{ 278 int value; 279 280 DPRINTF(("ubsa_databits: cflag = %#x\n", cflag)); 281 282 switch (cflag & CSIZE) { 283 case CS5: value = 0; break; 284 case CS6: value = 1; break; 285 case CS7: value = 2; break; 286 case CS8: value = 3; break; 287 default: 288 printf("%s: ubsa_param: unsupported databits requested, " 289 "forcing default of 8\n", 290 device_xname(sc->sc_dev)); 291 value = 3; 292 } 293 294 ubsa_request(sc, portno, UBSA_SET_DATA_BITS, value); 295} 296 297void 298ubsa_stopbits(struct ubsa_softc *sc, int portno, tcflag_t cflag) 299{ 300 int value; 301 302 DPRINTF(("ubsa_stopbits: cflag = %#x\n", cflag)); 303 304 value = (cflag & CSTOPB) ? 1 : 0; 305 306 ubsa_request(sc, portno, UBSA_SET_STOP_BITS, value); 307} 308 309void 310ubsa_flow(struct ubsa_softc *sc, int portno, tcflag_t cflag, tcflag_t iflag) 311{ 312 int value; 313 314 DPRINTF(("ubsa_flow: cflag = %#x, iflag = %#x\n", cflag, iflag)); 315 316 value = 0; 317 if (cflag & CRTSCTS) 318 value |= UBSA_FLOW_OCTS | UBSA_FLOW_IRTS; 319 if (iflag & IXOFF) 320 value |= UBSA_FLOW_OXON; 321 if (iflag & IXON) 322 value |= UBSA_FLOW_IXON; 323 324 ubsa_request(sc, portno, UBSA_SET_FLOW_CTRL, value); 325} 326 327int 328ubsa_param(void *addr, int portno, struct termios *ti) 329{ 330 struct ubsa_softc *sc = addr; 331 332 if (sc->sc_dying) 333 return EIO; 334 335 DPRINTF(("ubsa_param: sc = %p\n", sc)); 336 337 if (!sc->sc_quadumts) { 338 ubsa_baudrate(sc, portno, ti->c_ospeed); 339 ubsa_parity(sc, portno, ti->c_cflag); 340 ubsa_databits(sc, portno, ti->c_cflag); 341 ubsa_stopbits(sc, portno, ti->c_cflag); 342 ubsa_flow(sc, portno, ti->c_cflag, ti->c_iflag); 343 } 344 345 return 0; 346} 347 348int 349ubsa_open(void *addr, int portno) 350{ 351 struct ubsa_softc *sc = addr; 352 int err; 353 354 if (sc->sc_dying) 355 return EIO; 356 357 if (sc->sc_intr_number != -1 && sc->sc_intr_pipe == NULL) { 358 sc->sc_intr_buf = kmem_alloc(sc->sc_isize, KM_SLEEP); 359 /* XXX only iface# = 0 has intr line */ 360 /* XXX E220 specific? need to check */ 361 err = usbd_open_pipe_intr(sc->sc_iface[0], 362 sc->sc_intr_number, 363 USBD_SHORT_XFER_OK, 364 &sc->sc_intr_pipe, 365 sc, 366 sc->sc_intr_buf, 367 sc->sc_isize, 368 ubsa_intr, 369 UBSA_INTR_INTERVAL); 370 if (err) { 371 printf("%s: cannot open interrupt pipe (addr %d)\n", 372 device_xname(sc->sc_dev), 373 sc->sc_intr_number); 374 return EIO; 375 } 376 } 377 378 return 0; 379} 380 381void 382ubsa_close_pipe(struct ubsa_softc *sc) 383{ 384 385 if (sc->sc_intr_pipe != NULL) { 386 usbd_abort_pipe(sc->sc_intr_pipe); 387 usbd_close_pipe(sc->sc_intr_pipe); 388 sc->sc_intr_pipe = NULL; 389 } 390 if (sc->sc_intr_buf) { 391 kmem_free(sc->sc_intr_buf, sc->sc_isize); 392 sc->sc_intr_buf = NULL; 393 } 394} 395 396void 397ubsa_close(void *addr, int portno) 398{ 399 struct ubsa_softc *sc = addr; 400 401 DPRINTF(("ubsa_close: close\n")); 402 403 if (sc->sc_dying) 404 return; 405 406 ubsa_close_pipe(sc); 407} 408 409void 410ubsa_intr(struct usbd_xfer *xfer, void *priv, 411 usbd_status status) 412{ 413 struct ubsa_softc *sc = priv; 414 u_char *buf; 415 int i; 416 417 buf = sc->sc_intr_buf; 418 if (sc->sc_dying) 419 return; 420 421 if (status != USBD_NORMAL_COMPLETION) { 422 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 423 return; 424 425 DPRINTF(("%s: ubsa_intr: abnormal status: %s\n", 426 device_xname(sc->sc_dev), usbd_errstr(status))); 427 usbd_clear_endpoint_stall_async(sc->sc_intr_pipe); 428 return; 429 } 430 431 /* incidentally, Belkin adapter status bits match UART 16550 bits */ 432 sc->sc_lsr = buf[2]; 433 sc->sc_msr = buf[3]; 434 435 DPRINTF(("%s: ubsa lsr = 0x%02x, msr = 0x%02x\n", 436 device_xname(sc->sc_dev), sc->sc_lsr, sc->sc_msr)); 437 438 for (i = 0; i < sc->sc_numif; i++) { 439 ucom_status_change(device_private(sc->sc_subdevs[i])); 440 } 441} 442 443void 444ubsa_get_status(void *addr, int portno, u_char *lsr, u_char *msr) 445{ 446 struct ubsa_softc *sc = addr; 447 448 DPRINTF(("ubsa_get_status\n")); 449 450 *lsr = sc->sc_lsr; 451 *msr = sc->sc_msr; 452} 453 454