1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 3 * 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * Copyright (c) 2016-2024 Hiroki Sato <hrs@FreeBSD.org> 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (lennart@augustsson.net). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/bus.h> 38 #include <sys/callout.h> 39 #include <sys/condvar.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/module.h> 44 #include <sys/mutex.h> 45 #include <sys/priv.h> 46 #include <sys/queue.h> 47 #include <sys/stddef.h> 48 #include <sys/stdint.h> 49 #include <sys/sx.h> 50 #include <sys/sysctl.h> 51 #include <sys/unistd.h> 52 53 #include <dev/usb/usb.h> 54 #include <dev/usb/usb_ioctl.h> 55 #include <dev/usb/usbdi.h> 56 #include <dev/usb/usbdi_util.h> 57 #include <dev/usb/usb_core.h> 58 59 #include "usbdevs.h" 60 61 #define USB_DEBUG_VAR udbc_debug 62 #include <dev/usb/usb_process.h> 63 #include <dev/usb/serial/usb_serial.h> 64 #include <dev/usb/usb_debug.h> 65 66 static SYSCTL_NODE(_hw_usb, OID_AUTO, udbc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 67 "USB DbC Client"); 68 69 #ifdef USB_DEBUG 70 static int udbc_debug = 0; 71 SYSCTL_INT(_hw_usb_udbc, OID_AUTO, debug, CTLFLAG_RWTUN, &udbc_debug, 0, 72 "Debug level"); 73 #endif 74 75 #define UDBC_CONFIG_INDEX 0 76 77 #define UDBC_IBUFSIZE 1024 78 #define UDBC_OBUFSIZE 1024 79 80 enum { 81 UDBC_BULK_DT_WR, 82 UDBC_BULK_DT_RD, 83 UDBC_N_TRANSFER, /* n of EP */ 84 }; 85 86 struct udbc_softc { 87 struct ucom_super_softc sc_super_ucom; 88 struct ucom_softc sc_ucom; 89 90 struct usb_device *sc_udev; 91 struct usb_xfer *sc_xfer[UDBC_N_TRANSFER]; 92 device_t sc_dev; 93 struct mtx sc_mtx; 94 95 uint32_t sc_unit; 96 }; 97 98 /* prototypes */ 99 100 static device_probe_t udbc_probe; 101 static device_attach_t udbc_attach; 102 static device_detach_t udbc_detach; 103 static void udbc_free_softc(struct udbc_softc *); 104 105 static usb_callback_t udbc_write_callback; 106 static usb_callback_t udbc_read_callback; 107 108 static void udbc_free(struct ucom_softc *); 109 static void udbc_cfg_open(struct ucom_softc *); 110 static void udbc_cfg_close(struct ucom_softc *); 111 static int udbc_pre_param(struct ucom_softc *, struct termios *); 112 static int udbc_ioctl(struct ucom_softc *, uint32_t, caddr_t, int, 113 struct thread *); 114 static void udbc_start_read(struct ucom_softc *); 115 static void udbc_stop_read(struct ucom_softc *); 116 static void udbc_start_write(struct ucom_softc *); 117 static void udbc_stop_write(struct ucom_softc *); 118 static void udbc_poll(struct ucom_softc *ucom); 119 120 static const struct usb_config udbc_config[UDBC_N_TRANSFER] = { 121 [UDBC_BULK_DT_WR] = { 122 .type = UE_BULK, 123 .endpoint = UE_ADDR_ANY, 124 .direction = UE_DIR_OUT, 125 .bufsize = UDBC_OBUFSIZE, 126 .flags = {.pipe_bof = 1,}, 127 .callback = &udbc_write_callback, 128 }, 129 130 [UDBC_BULK_DT_RD] = { 131 .type = UE_BULK, 132 .endpoint = UE_ADDR_ANY, 133 .direction = UE_DIR_IN, 134 .bufsize = UDBC_IBUFSIZE, 135 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 136 .callback = &udbc_read_callback, 137 }, 138 }; 139 140 static const struct ucom_callback udbc_callback = { 141 .ucom_cfg_open = &udbc_cfg_open, 142 .ucom_cfg_close = &udbc_cfg_close, 143 .ucom_pre_param = &udbc_pre_param, 144 .ucom_ioctl = &udbc_ioctl, 145 .ucom_start_read = &udbc_start_read, 146 .ucom_stop_read = &udbc_stop_read, 147 .ucom_start_write = &udbc_start_write, 148 .ucom_stop_write = &udbc_stop_write, 149 .ucom_poll = &udbc_poll, 150 .ucom_free = &udbc_free, 151 }; 152 153 static device_method_t udbc_methods[] = { 154 /* Device interface */ 155 DEVMETHOD(device_probe, udbc_probe), 156 DEVMETHOD(device_attach, udbc_attach), 157 DEVMETHOD(device_detach, udbc_detach), 158 DEVMETHOD_END 159 }; 160 161 static int 162 udbc_probe(device_t dev) 163 { 164 struct usb_attach_arg *uaa = device_get_ivars(dev); 165 166 if (uaa->usb_mode != USB_MODE_HOST) 167 return (ENXIO); 168 if (uaa->info.bConfigIndex != UDBC_CONFIG_INDEX) 169 return (ENXIO); 170 if (uaa->info.bInterfaceClass != UICLASS_DIAGNOSTIC) 171 return (ENXIO); 172 if (uaa->info.bDeviceProtocol != 0x00) /* GNU GDB == 1 */ 173 return (ENXIO); 174 175 return (BUS_PROBE_SPECIFIC); 176 } 177 178 static int 179 udbc_attach(device_t dev) 180 { 181 struct usb_attach_arg *uaa = device_get_ivars(dev); 182 struct udbc_softc *sc = device_get_softc(dev); 183 int error; 184 185 DPRINTF("\n"); 186 187 sc->sc_udev = uaa->device; 188 sc->sc_dev = dev; 189 sc->sc_unit = device_get_unit(dev); 190 191 device_set_usb_desc(dev); 192 mtx_init(&sc->sc_mtx, "udbc", NULL, MTX_DEF); 193 ucom_ref(&sc->sc_super_ucom); 194 195 sc->sc_ucom.sc_portno = 0; 196 197 error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, 198 sc->sc_xfer, udbc_config, UDBC_N_TRANSFER, sc, &sc->sc_mtx); 199 200 if (error) { 201 device_printf(dev, 202 "allocating USB transfers failed\n"); 203 goto detach; 204 } 205 /* clear stall at first run */ 206 mtx_lock(&sc->sc_mtx); 207 usbd_xfer_set_stall(sc->sc_xfer[UDBC_BULK_DT_WR]); 208 usbd_xfer_set_stall(sc->sc_xfer[UDBC_BULK_DT_RD]); 209 mtx_unlock(&sc->sc_mtx); 210 211 error = ucom_attach(&sc->sc_super_ucom, &sc->sc_ucom, 1, sc, 212 &udbc_callback, &sc->sc_mtx); 213 if (error) 214 goto detach; 215 ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev); 216 217 return (0); /* success */ 218 219 detach: 220 udbc_detach(dev); 221 return (ENXIO); 222 } 223 224 static int 225 udbc_detach(device_t dev) 226 { 227 struct udbc_softc *sc = device_get_softc(dev); 228 229 ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); 230 usbd_transfer_unsetup(sc->sc_xfer, UDBC_N_TRANSFER); 231 232 device_claim_softc(dev); 233 234 udbc_free_softc(sc); 235 236 return (0); 237 } 238 239 UCOM_UNLOAD_DRAIN(udbc); 240 241 static void 242 udbc_free_softc(struct udbc_softc *sc) 243 { 244 if (ucom_unref(&sc->sc_super_ucom)) { 245 mtx_destroy(&sc->sc_mtx); 246 device_free_softc(sc); 247 } 248 } 249 250 static void 251 udbc_free(struct ucom_softc *ucom) 252 { 253 udbc_free_softc(ucom->sc_parent); 254 } 255 256 static void 257 udbc_cfg_open(struct ucom_softc *ucom) 258 { 259 /* 260 * This do-nothing open routine exists for the sole purpose of this 261 * DPRINTF() so that you can see the point at which open gets called 262 * when debugging is enabled. 263 */ 264 DPRINTF("\n"); 265 } 266 267 static void 268 udbc_cfg_close(struct ucom_softc *ucom) 269 { 270 /* 271 * This do-nothing close routine exists for the sole purpose of this 272 * DPRINTF() so that you can see the point at which close gets called 273 * when debugging is enabled. 274 */ 275 DPRINTF("\n"); 276 } 277 278 static void 279 udbc_write_callback(struct usb_xfer *xfer, usb_error_t error) 280 { 281 struct udbc_softc *sc = usbd_xfer_softc(xfer); 282 struct usb_page_cache *pc; 283 uint32_t buflen; 284 285 DPRINTFN(3, "\n"); 286 287 switch (USB_GET_STATE(xfer)) { 288 default: /* Error */ 289 if (error != USB_ERR_CANCELLED) { 290 /* try to clear stall first */ 291 usbd_xfer_set_stall(xfer); 292 } 293 /* FALLTHROUGH */ 294 case USB_ST_SETUP: 295 case USB_ST_TRANSFERRED: 296 pc = usbd_xfer_get_frame(xfer, 0); 297 if (ucom_get_data(&sc->sc_ucom, pc, 0, UDBC_OBUFSIZE, 298 &buflen) == 0) 299 break; 300 if (buflen != 0) { 301 usbd_xfer_set_frame_len(xfer, 0, buflen); 302 usbd_transfer_submit(xfer); 303 } 304 break; 305 } 306 } 307 308 static void 309 udbc_read_callback(struct usb_xfer *xfer, usb_error_t error) 310 { 311 struct udbc_softc *sc = usbd_xfer_softc(xfer); 312 struct usb_page_cache *pc; 313 int buflen; 314 315 DPRINTFN(3, "\n"); 316 317 usbd_xfer_status(xfer, &buflen, NULL, NULL, NULL); 318 319 switch (USB_GET_STATE(xfer)) { 320 case USB_ST_TRANSFERRED: 321 pc = usbd_xfer_get_frame(xfer, 0); 322 ucom_put_data(&sc->sc_ucom, pc, 0, buflen); 323 /* FALLTHROUGH */ 324 case USB_ST_SETUP: 325 tr_setup: 326 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 327 usbd_transfer_submit(xfer); 328 return; 329 330 default: /* Error */ 331 if (error != USB_ERR_CANCELLED) { 332 /* try to clear stall first */ 333 usbd_xfer_set_stall(xfer); 334 goto tr_setup; 335 } 336 return; 337 } 338 } 339 340 static int 341 udbc_pre_param(struct ucom_softc *ucom, struct termios *t) 342 { 343 DPRINTF("\n"); 344 345 return (0); 346 } 347 348 static int 349 udbc_ioctl(struct ucom_softc *ucom, uint32_t cmd, caddr_t data, int flag, 350 struct thread *td) 351 { 352 return (ENOIOCTL); 353 } 354 355 static void 356 udbc_start_read(struct ucom_softc *ucom) 357 { 358 struct udbc_softc *sc = ucom->sc_parent; 359 360 usbd_transfer_start(sc->sc_xfer[UDBC_BULK_DT_RD]); 361 } 362 363 static void 364 udbc_stop_read(struct ucom_softc *ucom) 365 { 366 struct udbc_softc *sc = ucom->sc_parent; 367 368 usbd_transfer_stop(sc->sc_xfer[UDBC_BULK_DT_RD]); 369 } 370 371 static void 372 udbc_start_write(struct ucom_softc *ucom) 373 { 374 struct udbc_softc *sc = ucom->sc_parent; 375 376 usbd_transfer_start(sc->sc_xfer[UDBC_BULK_DT_WR]); 377 } 378 379 static void 380 udbc_stop_write(struct ucom_softc *ucom) 381 { 382 struct udbc_softc *sc = ucom->sc_parent; 383 384 usbd_transfer_stop(sc->sc_xfer[UDBC_BULK_DT_WR]); 385 } 386 387 static void 388 udbc_poll(struct ucom_softc *ucom) 389 { 390 struct udbc_softc *sc = ucom->sc_parent; 391 392 usbd_transfer_poll(sc->sc_xfer, UDBC_N_TRANSFER); 393 } 394 395 static driver_t udbc_driver = { 396 .name = "udbc", 397 .methods = udbc_methods, 398 .size = sizeof(struct udbc_softc), 399 }; 400 401 DRIVER_MODULE(udbc, uhub, udbc_driver, NULL, NULL); 402 MODULE_DEPEND(udbc, ucom, 1, 1, 1); 403 MODULE_DEPEND(udbc, usb, 1, 1, 1); 404 MODULE_VERSION(udbc, 1); 405