1 1.50 thorpej /* $NetBSD: usscanner.c,v 1.50 2021/08/07 16:19:17 thorpej Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.3 augustss * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.1 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.1 augustss * by Lennart Augustsson (lennart (at) augustsson.net) and LLoyd Parkes. 9 1.1 augustss * 10 1.1 augustss * Redistribution and use in source and binary forms, with or without 11 1.1 augustss * modification, are permitted provided that the following conditions 12 1.1 augustss * are met: 13 1.1 augustss * 1. Redistributions of source code must retain the above copyright 14 1.1 augustss * notice, this list of conditions and the following disclaimer. 15 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 augustss * notice, this list of conditions and the following disclaimer in the 17 1.1 augustss * documentation and/or other materials provided with the distribution. 18 1.1 augustss * 19 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 30 1.1 augustss */ 31 1.1 augustss 32 1.2 augustss /* 33 1.2 augustss * This driver is partly based on information taken from the Linux driver 34 1.2 augustss * by John Fremlin, Oliver Neukum, and Jeremy Hall. 35 1.2 augustss */ 36 1.3 augustss /* 37 1.3 augustss * Protocol: 38 1.3 augustss * Send raw SCSI command on the bulk-out pipe. 39 1.3 augustss * If output command then 40 1.3 augustss * send further data on the bulk-out pipe 41 1.3 augustss * else if input command then 42 1.3 augustss * read data on the bulk-in pipe 43 1.3 augustss * else 44 1.3 augustss * don't do anything. 45 1.3 augustss * Read status byte on the interrupt pipe (which doesn't seem to be 46 1.4 augustss * an interrupt pipe at all). This operation sometimes times out. 47 1.3 augustss */ 48 1.9 lukem 49 1.9 lukem #include <sys/cdefs.h> 50 1.50 thorpej __KERNEL_RCSID(0, "$NetBSD: usscanner.c,v 1.50 2021/08/07 16:19:17 thorpej Exp $"); 51 1.41 skrll 52 1.41 skrll #ifdef _KERNEL_OPT 53 1.41 skrll #include "opt_usb.h" 54 1.41 skrll #endif 55 1.2 augustss 56 1.16 augustss #include "scsibus.h" 57 1.1 augustss #include <sys/param.h> 58 1.1 augustss #include <sys/systm.h> 59 1.1 augustss #include <sys/kernel.h> 60 1.34 he #include <sys/lwp.h> 61 1.1 augustss #include <sys/device.h> 62 1.1 augustss #include <sys/conf.h> 63 1.1 augustss #include <sys/buf.h> 64 1.1 augustss 65 1.1 augustss #include <dev/usb/usb.h> 66 1.1 augustss #include <dev/usb/usbdi.h> 67 1.1 augustss #include <dev/usb/usbdi_util.h> 68 1.1 augustss 69 1.1 augustss #include <dev/usb/usbdevs.h> 70 1.1 augustss 71 1.1 augustss #include <sys/scsiio.h> 72 1.15 thorpej #include <dev/scsipi/scsi_spc.h> 73 1.1 augustss #include <dev/scsipi/scsi_all.h> 74 1.1 augustss #include <dev/scsipi/scsipi_all.h> 75 1.1 augustss #include <dev/scsipi/scsiconf.h> 76 1.1 augustss #include <dev/scsipi/atapiconf.h> 77 1.1 augustss 78 1.1 augustss #ifdef USSCANNER_DEBUG 79 1.30 dyoung #define DPRINTF(x) if (usscannerdebug) printf x 80 1.30 dyoung #define DPRINTFN(n,x) if (usscannerdebug>(n)) printf x 81 1.2 augustss int usscannerdebug = 0; 82 1.1 augustss #else 83 1.1 augustss #define DPRINTF(x) 84 1.1 augustss #define DPRINTFN(n,x) 85 1.1 augustss #endif 86 1.1 augustss 87 1.1 augustss 88 1.1 augustss #define USSCANNER_CONFIG_NO 1 89 1.1 augustss #define USSCANNER_IFACE_IDX 0 90 1.1 augustss 91 1.1 augustss #define USSCANNER_SCSIID_HOST 0x00 92 1.1 augustss #define USSCANNER_SCSIID_DEVICE 0x01 93 1.1 augustss 94 1.13 tls #define USSCANNER_MAX_TRANSFER_SIZE MAXPHYS 95 1.1 augustss 96 1.1 augustss #define USSCANNER_TIMEOUT 2000 97 1.1 augustss 98 1.1 augustss struct usscanner_softc { 99 1.42 skrll device_t sc_dev; 100 1.39 skrll struct usbd_device *sc_udev; 101 1.39 skrll struct usbd_interface *sc_iface; 102 1.1 augustss 103 1.1 augustss int sc_in_addr; 104 1.39 skrll struct usbd_pipe *sc_in_pipe; 105 1.1 augustss 106 1.1 augustss int sc_intr_addr; 107 1.39 skrll struct usbd_pipe *sc_intr_pipe; 108 1.39 skrll struct usbd_xfer *sc_intr_xfer; 109 1.1 augustss u_char sc_status; 110 1.1 augustss 111 1.1 augustss int sc_out_addr; 112 1.39 skrll struct usbd_pipe *sc_out_pipe; 113 1.1 augustss 114 1.39 skrll struct usbd_xfer *sc_cmd_xfer; 115 1.1 augustss void *sc_cmd_buffer; 116 1.39 skrll struct usbd_xfer *sc_datain_xfer; 117 1.39 skrll void *sc_datain_buffer; 118 1.39 skrll struct usbd_xfer *sc_dataout_xfer; 119 1.39 skrll void *sc_dataout_buffer; 120 1.1 augustss 121 1.1 augustss int sc_state; 122 1.1 augustss #define UAS_IDLE 0 123 1.1 augustss #define UAS_CMD 1 124 1.1 augustss #define UAS_DATA 2 125 1.1 augustss #define UAS_SENSECMD 3 126 1.1 augustss #define UAS_SENSEDATA 4 127 1.1 augustss #define UAS_STATUS 5 128 1.1 augustss 129 1.1 augustss struct scsipi_xfer *sc_xs; 130 1.1 augustss 131 1.30 dyoung device_t sc_child; /* child device, for detach */ 132 1.1 augustss 133 1.7 bouyer struct scsipi_adapter sc_adapter; 134 1.7 bouyer struct scsipi_channel sc_channel; 135 1.1 augustss 136 1.1 augustss int sc_refcnt; 137 1.1 augustss char sc_dying; 138 1.1 augustss }; 139 1.1 augustss 140 1.1 augustss 141 1.39 skrll Static void usscanner_cleanup(struct usscanner_softc *); 142 1.39 skrll Static void usscanner_scsipi_request(struct scsipi_channel *, 143 1.39 skrll scsipi_adapter_req_t, void *); 144 1.39 skrll Static void usscanner_scsipi_minphys(struct buf *); 145 1.39 skrll Static void usscanner_done(struct usscanner_softc *); 146 1.39 skrll Static void usscanner_sense(struct usscanner_softc *); 147 1.39 skrll typedef void callback(struct usbd_xfer *, void *, usbd_status); 148 1.1 augustss Static callback usscanner_intr_cb; 149 1.1 augustss Static callback usscanner_cmd_cb; 150 1.1 augustss Static callback usscanner_data_cb; 151 1.1 augustss Static callback usscanner_sensecmd_cb; 152 1.1 augustss Static callback usscanner_sensedata_cb; 153 1.1 augustss 154 1.46 maxv static int usscanner_match(device_t, cfdata_t, void *); 155 1.46 maxv static void usscanner_attach(device_t, device_t, void *); 156 1.46 maxv static void usscanner_childdet(device_t, device_t); 157 1.46 maxv static int usscanner_detach(device_t, int); 158 1.46 maxv static int usscanner_activate(device_t, enum devact); 159 1.44 mrg 160 1.25 cube CFATTACH_DECL2_NEW(usscanner, sizeof(struct usscanner_softc), 161 1.23 dyoung usscanner_match, usscanner_attach, usscanner_detach, usscanner_activate, 162 1.25 cube NULL, usscanner_childdet); 163 1.1 augustss 164 1.46 maxv static int 165 1.30 dyoung usscanner_match(device_t parent, cfdata_t match, void *aux) 166 1.1 augustss { 167 1.30 dyoung struct usb_attach_arg *uaa = aux; 168 1.1 augustss 169 1.1 augustss DPRINTFN(50,("usscanner_match\n")); 170 1.1 augustss 171 1.39 skrll if (uaa->uaa_vendor == USB_VENDOR_HP && 172 1.39 skrll uaa->uaa_product == USB_PRODUCT_HP_5300C) 173 1.39 skrll return UMATCH_VENDOR_PRODUCT; 174 1.1 augustss else 175 1.39 skrll return UMATCH_NONE; 176 1.1 augustss } 177 1.1 augustss 178 1.46 maxv static void 179 1.30 dyoung usscanner_attach(device_t parent, device_t self, void *aux) 180 1.1 augustss { 181 1.30 dyoung struct usscanner_softc *sc = device_private(self); 182 1.30 dyoung struct usb_attach_arg *uaa = aux; 183 1.39 skrll struct usbd_device * dev = uaa->uaa_device; 184 1.39 skrll struct usbd_interface * iface; 185 1.17 augustss char *devinfop; 186 1.1 augustss usbd_status err; 187 1.1 augustss usb_endpoint_descriptor_t *ed; 188 1.39 skrll uint8_t epcount; 189 1.1 augustss int i; 190 1.39 skrll int error; 191 1.1 augustss 192 1.1 augustss DPRINTFN(10,("usscanner_attach: sc=%p\n", sc)); 193 1.1 augustss 194 1.25 cube sc->sc_dev = self; 195 1.25 cube 196 1.28 plunky aprint_naive("\n"); 197 1.28 plunky aprint_normal("\n"); 198 1.28 plunky 199 1.17 augustss devinfop = usbd_devinfo_alloc(dev, 0); 200 1.25 cube aprint_normal_dev(self, "%s\n", devinfop); 201 1.17 augustss usbd_devinfo_free(devinfop); 202 1.1 augustss 203 1.1 augustss err = usbd_set_config_no(dev, USSCANNER_CONFIG_NO, 1); 204 1.1 augustss if (err) { 205 1.40 msaitoh aprint_error_dev(self, "failed to set configuration, err=%s\n", 206 1.40 msaitoh usbd_errstr(err)); 207 1.30 dyoung return; 208 1.1 augustss } 209 1.1 augustss 210 1.1 augustss err = usbd_device2interface_handle(dev, USSCANNER_IFACE_IDX, &iface); 211 1.1 augustss if (err) { 212 1.25 cube aprint_error_dev(self, "getting interface handle failed\n"); 213 1.30 dyoung return; 214 1.1 augustss } 215 1.1 augustss 216 1.1 augustss sc->sc_udev = dev; 217 1.1 augustss sc->sc_iface = iface; 218 1.1 augustss 219 1.1 augustss epcount = 0; 220 1.1 augustss (void)usbd_endpoint_count(iface, &epcount); 221 1.1 augustss 222 1.1 augustss sc->sc_in_addr = -1; 223 1.1 augustss sc->sc_intr_addr = -1; 224 1.1 augustss sc->sc_out_addr = -1; 225 1.1 augustss for (i = 0; i < epcount; i++) { 226 1.1 augustss ed = usbd_interface2endpoint_descriptor(iface, i); 227 1.1 augustss if (ed == NULL) { 228 1.25 cube aprint_error_dev(self, "couldn't get ep %d\n", i); 229 1.30 dyoung return; 230 1.1 augustss } 231 1.1 augustss if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 232 1.1 augustss UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 233 1.1 augustss sc->sc_in_addr = ed->bEndpointAddress; 234 1.1 augustss } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 235 1.1 augustss UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 236 1.1 augustss sc->sc_intr_addr = ed->bEndpointAddress; 237 1.1 augustss } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 238 1.1 augustss UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 239 1.1 augustss sc->sc_out_addr = ed->bEndpointAddress; 240 1.1 augustss } 241 1.1 augustss } 242 1.10 augustss if (sc->sc_in_addr == -1 || sc->sc_intr_addr == -1 || 243 1.1 augustss sc->sc_out_addr == -1) { 244 1.25 cube aprint_error_dev(self, "missing endpoint\n"); 245 1.30 dyoung return; 246 1.1 augustss } 247 1.1 augustss 248 1.1 augustss err = usbd_open_pipe(sc->sc_iface, sc->sc_in_addr, 249 1.1 augustss USBD_EXCLUSIVE_USE, &sc->sc_in_pipe); 250 1.1 augustss if (err) { 251 1.25 cube aprint_error_dev(self, "open in pipe failed, err=%d\n", err); 252 1.30 dyoung return; 253 1.1 augustss } 254 1.1 augustss 255 1.1 augustss /* The interrupt endpoint must be opened as a normal pipe. */ 256 1.1 augustss err = usbd_open_pipe(sc->sc_iface, sc->sc_intr_addr, 257 1.1 augustss USBD_EXCLUSIVE_USE, &sc->sc_intr_pipe); 258 1.1 augustss 259 1.1 augustss if (err) { 260 1.25 cube aprint_error_dev(self, "open intr pipe failed, err=%d\n", err); 261 1.1 augustss usscanner_cleanup(sc); 262 1.30 dyoung return; 263 1.1 augustss } 264 1.1 augustss err = usbd_open_pipe(sc->sc_iface, sc->sc_out_addr, 265 1.1 augustss USBD_EXCLUSIVE_USE, &sc->sc_out_pipe); 266 1.1 augustss if (err) { 267 1.25 cube aprint_error_dev(self, "open out pipe failed, err=%d\n", err); 268 1.1 augustss usscanner_cleanup(sc); 269 1.30 dyoung return; 270 1.1 augustss } 271 1.1 augustss 272 1.39 skrll /* XXX too big */ 273 1.39 skrll error = usbd_create_xfer(sc->sc_out_pipe, USSCANNER_MAX_TRANSFER_SIZE, 274 1.39 skrll 0, 0, &sc->sc_cmd_xfer); 275 1.39 skrll if (error) { 276 1.39 skrll aprint_error_dev(self, "alloc cmd xfer failed, error=%d\n", 277 1.39 skrll error); 278 1.1 augustss usscanner_cleanup(sc); 279 1.30 dyoung return; 280 1.1 augustss } 281 1.1 augustss 282 1.39 skrll sc->sc_cmd_buffer = usbd_get_buffer(sc->sc_cmd_xfer); 283 1.39 skrll 284 1.43 skrll error = usbd_create_xfer(sc->sc_intr_pipe, 1, 0, 0, &sc->sc_intr_xfer); 285 1.39 skrll if (error) { 286 1.39 skrll aprint_error_dev(self, "alloc intr xfer failed, error=%d\n", 287 1.39 skrll error); 288 1.1 augustss usscanner_cleanup(sc); 289 1.30 dyoung return; 290 1.1 augustss } 291 1.1 augustss 292 1.39 skrll error = usbd_create_xfer(sc->sc_in_pipe, USSCANNER_MAX_TRANSFER_SIZE, 293 1.43 skrll 0, 0, &sc->sc_datain_xfer); 294 1.39 skrll if (error) { 295 1.39 skrll aprint_error_dev(self, "alloc data xfer failed, error=%d\n", 296 1.39 skrll error); 297 1.1 augustss usscanner_cleanup(sc); 298 1.30 dyoung return; 299 1.1 augustss } 300 1.39 skrll sc->sc_datain_buffer = usbd_get_buffer(sc->sc_datain_xfer); 301 1.39 skrll 302 1.39 skrll error = usbd_create_xfer(sc->sc_out_pipe, USSCANNER_MAX_TRANSFER_SIZE, 303 1.43 skrll 0, 0, &sc->sc_dataout_xfer); 304 1.39 skrll if (error) { 305 1.39 skrll aprint_error_dev(self, "alloc data xfer failed, err=%d\n", err); 306 1.1 augustss usscanner_cleanup(sc); 307 1.30 dyoung return; 308 1.1 augustss } 309 1.39 skrll sc->sc_dataout_buffer = usbd_get_buffer(sc->sc_dataout_xfer); 310 1.1 augustss 311 1.1 augustss /* 312 1.1 augustss * Fill in the adapter. 313 1.1 augustss */ 314 1.7 bouyer sc->sc_adapter.adapt_request = usscanner_scsipi_request; 315 1.25 cube sc->sc_adapter.adapt_dev = sc->sc_dev; 316 1.7 bouyer sc->sc_adapter.adapt_nchannels = 1; 317 1.7 bouyer sc->sc_adapter.adapt_openings = 1; 318 1.7 bouyer sc->sc_adapter.adapt_max_periph = 1; 319 1.7 bouyer sc->sc_adapter.adapt_minphys = usscanner_scsipi_minphys; 320 1.10 augustss 321 1.16 augustss #if NSCSIBUS > 0 322 1.1 augustss /* 323 1.7 bouyer * fill in the scsipi_channel. 324 1.1 augustss */ 325 1.7 bouyer sc->sc_channel.chan_adapter = &sc->sc_adapter; 326 1.7 bouyer sc->sc_channel.chan_bustype = &scsi_bustype; 327 1.7 bouyer sc->sc_channel.chan_channel = 0; 328 1.7 bouyer sc->sc_channel.chan_ntargets = USSCANNER_SCSIID_DEVICE + 1; 329 1.7 bouyer sc->sc_channel.chan_nluns = 1; 330 1.7 bouyer sc->sc_channel.chan_id = USSCANNER_SCSIID_HOST; 331 1.7 bouyer 332 1.40 msaitoh usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); 333 1.6 augustss 334 1.49 thorpej sc->sc_child = config_found(sc->sc_dev, &sc->sc_channel, scsiprint, 335 1.50 thorpej CFARGS_NONE); 336 1.1 augustss 337 1.1 augustss DPRINTFN(10, ("usscanner_attach: %p\n", sc->sc_udev)); 338 1.1 augustss 339 1.30 dyoung return; 340 1.16 augustss 341 1.16 augustss #else 342 1.16 augustss /* No SCSI bus, just ignore it */ 343 1.16 augustss usscanner_cleanup(sc); 344 1.21 martin 345 1.25 cube aprint_error_dev(self, 346 1.25 cube "no scsibus configured, see usscanner(4) for details\n"); 347 1.21 martin 348 1.30 dyoung return; 349 1.16 augustss 350 1.16 augustss #endif 351 1.1 augustss } 352 1.1 augustss 353 1.46 maxv static void 354 1.23 dyoung usscanner_childdet(device_t self, device_t child) 355 1.23 dyoung { 356 1.23 dyoung struct usscanner_softc *sc = device_private(self); 357 1.23 dyoung 358 1.23 dyoung KASSERT(sc->sc_child == NULL); 359 1.23 dyoung sc->sc_child = NULL; 360 1.23 dyoung } 361 1.23 dyoung 362 1.46 maxv static int 363 1.30 dyoung usscanner_detach(device_t self, int flags) 364 1.1 augustss { 365 1.30 dyoung struct usscanner_softc *sc = device_private(self); 366 1.1 augustss int rv, s; 367 1.1 augustss 368 1.1 augustss DPRINTF(("usscanner_detach: sc=%p flags=%d\n", sc, flags)); 369 1.1 augustss 370 1.1 augustss sc->sc_dying = 1; 371 1.1 augustss /* Abort all pipes. Causes processes waiting for transfer to wake. */ 372 1.1 augustss if (sc->sc_in_pipe != NULL) 373 1.1 augustss usbd_abort_pipe(sc->sc_in_pipe); 374 1.1 augustss if (sc->sc_intr_pipe != NULL) 375 1.1 augustss usbd_abort_pipe(sc->sc_intr_pipe); 376 1.1 augustss if (sc->sc_out_pipe != NULL) 377 1.1 augustss usbd_abort_pipe(sc->sc_out_pipe); 378 1.1 augustss 379 1.1 augustss s = splusb(); 380 1.1 augustss if (--sc->sc_refcnt >= 0) { 381 1.1 augustss /* Wait for processes to go away. */ 382 1.35 mrg usb_detach_waitold(sc->sc_dev); 383 1.1 augustss } 384 1.1 augustss splx(s); 385 1.1 augustss 386 1.1 augustss if (sc->sc_child != NULL) 387 1.1 augustss rv = config_detach(sc->sc_child, flags); 388 1.1 augustss else 389 1.1 augustss rv = 0; 390 1.1 augustss 391 1.45 maxv if (sc->sc_udev != NULL) 392 1.45 maxv usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 393 1.45 maxv sc->sc_dev); 394 1.1 augustss 395 1.39 skrll return rv; 396 1.1 augustss } 397 1.1 augustss 398 1.1 augustss Static void 399 1.1 augustss usscanner_cleanup(struct usscanner_softc *sc) 400 1.1 augustss { 401 1.39 skrll if (sc->sc_cmd_xfer != NULL) { 402 1.39 skrll usbd_destroy_xfer(sc->sc_cmd_xfer); 403 1.39 skrll sc->sc_cmd_xfer = NULL; 404 1.39 skrll } 405 1.39 skrll if (sc->sc_datain_xfer != NULL) { 406 1.39 skrll usbd_destroy_xfer(sc->sc_datain_xfer); 407 1.39 skrll sc->sc_datain_xfer = NULL; 408 1.39 skrll } 409 1.39 skrll if (sc->sc_dataout_xfer != NULL) { 410 1.39 skrll usbd_destroy_xfer(sc->sc_dataout_xfer); 411 1.39 skrll sc->sc_dataout_xfer = NULL; 412 1.39 skrll } 413 1.1 augustss if (sc->sc_in_pipe != NULL) { 414 1.1 augustss usbd_close_pipe(sc->sc_in_pipe); 415 1.1 augustss sc->sc_in_pipe = NULL; 416 1.1 augustss } 417 1.1 augustss if (sc->sc_intr_pipe != NULL) { 418 1.1 augustss usbd_close_pipe(sc->sc_intr_pipe); 419 1.1 augustss sc->sc_intr_pipe = NULL; 420 1.1 augustss } 421 1.1 augustss if (sc->sc_out_pipe != NULL) { 422 1.1 augustss usbd_close_pipe(sc->sc_out_pipe); 423 1.1 augustss sc->sc_out_pipe = NULL; 424 1.1 augustss } 425 1.1 augustss } 426 1.1 augustss 427 1.46 maxv static int 428 1.23 dyoung usscanner_activate(device_t self, enum devact act) 429 1.1 augustss { 430 1.23 dyoung struct usscanner_softc *sc = device_private(self); 431 1.1 augustss 432 1.1 augustss switch (act) { 433 1.1 augustss case DVACT_DEACTIVATE: 434 1.1 augustss sc->sc_dying = 1; 435 1.29 dyoung return 0; 436 1.29 dyoung default: 437 1.29 dyoung return EOPNOTSUPP; 438 1.1 augustss } 439 1.1 augustss } 440 1.1 augustss 441 1.1 augustss Static void 442 1.1 augustss usscanner_scsipi_minphys(struct buf *bp) 443 1.1 augustss { 444 1.1 augustss if (bp->b_bcount > USSCANNER_MAX_TRANSFER_SIZE) 445 1.1 augustss bp->b_bcount = USSCANNER_MAX_TRANSFER_SIZE; 446 1.1 augustss minphys(bp); 447 1.1 augustss } 448 1.1 augustss 449 1.1 augustss Static void 450 1.1 augustss usscanner_sense(struct usscanner_softc *sc) 451 1.1 augustss { 452 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 453 1.7 bouyer struct scsipi_periph *periph = xs->xs_periph; 454 1.15 thorpej struct scsi_request_sense sense_cmd; 455 1.1 augustss usbd_status err; 456 1.1 augustss 457 1.1 augustss /* fetch sense data */ 458 1.1 augustss memset(&sense_cmd, 0, sizeof(sense_cmd)); 459 1.15 thorpej sense_cmd.opcode = SCSI_REQUEST_SENSE; 460 1.7 bouyer sense_cmd.byte2 = periph->periph_lun << SCSI_CMD_LUN_SHIFT; 461 1.39 skrll sense_cmd.length = sizeof(xs->sense); 462 1.1 augustss 463 1.1 augustss sc->sc_state = UAS_SENSECMD; 464 1.39 skrll memcpy(sc->sc_cmd_buffer, &sense_cmd, sizeof(sense_cmd)); 465 1.39 skrll 466 1.39 skrll usbd_setup_xfer(sc->sc_cmd_xfer, sc, sc->sc_cmd_buffer, 467 1.39 skrll sizeof(sense_cmd), 0, USSCANNER_TIMEOUT, 468 1.1 augustss usscanner_sensecmd_cb); 469 1.1 augustss err = usbd_transfer(sc->sc_cmd_xfer); 470 1.1 augustss if (err == USBD_IN_PROGRESS) 471 1.1 augustss return; 472 1.1 augustss 473 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 474 1.1 augustss usscanner_done(sc); 475 1.1 augustss } 476 1.1 augustss 477 1.1 augustss Static void 478 1.40 msaitoh usscanner_intr_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 479 1.1 augustss { 480 1.1 augustss struct usscanner_softc *sc = priv; 481 1.1 augustss int s; 482 1.1 augustss 483 1.1 augustss DPRINTFN(10, ("usscanner_data_cb status=%d\n", status)); 484 1.1 augustss 485 1.1 augustss #ifdef USSCANNER_DEBUG 486 1.1 augustss if (sc->sc_state != UAS_STATUS) { 487 1.30 dyoung printf("%s: !UAS_STATUS\n", device_xname(sc->sc_dev)); 488 1.1 augustss } 489 1.3 augustss if (sc->sc_status != 0) { 490 1.48 christos printf("%s: status byte=0x%02x\n", device_xname(sc->sc_dev), 491 1.40 msaitoh sc->sc_status); 492 1.3 augustss } 493 1.1 augustss #endif 494 1.3 augustss /* XXX what should we do on non-0 status */ 495 1.1 augustss 496 1.1 augustss sc->sc_state = UAS_IDLE; 497 1.10 augustss 498 1.1 augustss s = splbio(); 499 1.33 mrg KERNEL_LOCK(1, curlwp); 500 1.1 augustss scsipi_done(sc->sc_xs); 501 1.33 mrg KERNEL_UNLOCK_ONE(curlwp); 502 1.1 augustss splx(s); 503 1.1 augustss } 504 1.1 augustss 505 1.1 augustss Static void 506 1.40 msaitoh usscanner_data_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 507 1.1 augustss { 508 1.1 augustss struct usscanner_softc *sc = priv; 509 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 510 1.39 skrll uint32_t len; 511 1.1 augustss 512 1.1 augustss DPRINTFN(10, ("usscanner_data_cb status=%d\n", status)); 513 1.1 augustss 514 1.1 augustss #ifdef USSCANNER_DEBUG 515 1.1 augustss if (sc->sc_state != UAS_DATA) { 516 1.30 dyoung printf("%s: !UAS_DATA\n", device_xname(sc->sc_dev)); 517 1.1 augustss } 518 1.1 augustss #endif 519 1.1 augustss 520 1.1 augustss usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 521 1.1 augustss 522 1.1 augustss xs->resid = xs->datalen - len; 523 1.1 augustss 524 1.1 augustss switch (status) { 525 1.1 augustss case USBD_NORMAL_COMPLETION: 526 1.1 augustss xs->error = XS_NOERROR; 527 1.1 augustss break; 528 1.1 augustss case USBD_TIMEOUT: 529 1.1 augustss xs->error = XS_TIMEOUT; 530 1.1 augustss break; 531 1.1 augustss case USBD_CANCELLED: 532 1.1 augustss if (xs->error == XS_SENSE) { 533 1.1 augustss usscanner_sense(sc); 534 1.1 augustss return; 535 1.1 augustss } 536 1.1 augustss break; 537 1.1 augustss default: 538 1.1 augustss xs->error = XS_DRIVER_STUFFUP; /* XXX ? */ 539 1.1 augustss break; 540 1.1 augustss } 541 1.1 augustss usscanner_done(sc); 542 1.1 augustss } 543 1.1 augustss 544 1.1 augustss Static void 545 1.40 msaitoh usscanner_sensedata_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 546 1.1 augustss { 547 1.1 augustss struct usscanner_softc *sc = priv; 548 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 549 1.39 skrll uint32_t len; 550 1.1 augustss 551 1.1 augustss DPRINTFN(10, ("usscanner_sensedata_cb status=%d\n", status)); 552 1.1 augustss 553 1.1 augustss #ifdef USSCANNER_DEBUG 554 1.1 augustss if (sc->sc_state != UAS_SENSEDATA) { 555 1.30 dyoung printf("%s: !UAS_SENSEDATA\n", device_xname(sc->sc_dev)); 556 1.1 augustss } 557 1.1 augustss #endif 558 1.1 augustss 559 1.1 augustss usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 560 1.1 augustss 561 1.1 augustss switch (status) { 562 1.1 augustss case USBD_NORMAL_COMPLETION: 563 1.39 skrll memcpy(&xs->sense, sc->sc_datain_buffer, len); 564 1.39 skrll if (len < sizeof(xs->sense)) 565 1.1 augustss xs->error = XS_SHORTSENSE; 566 1.1 augustss break; 567 1.1 augustss case USBD_TIMEOUT: 568 1.1 augustss xs->error = XS_TIMEOUT; 569 1.1 augustss break; 570 1.1 augustss case USBD_CANCELLED: 571 1.1 augustss xs->error = XS_RESET; 572 1.1 augustss break; 573 1.1 augustss default: 574 1.1 augustss xs->error = XS_DRIVER_STUFFUP; /* XXX ? */ 575 1.1 augustss break; 576 1.1 augustss } 577 1.1 augustss usscanner_done(sc); 578 1.1 augustss } 579 1.1 augustss 580 1.1 augustss Static void 581 1.1 augustss usscanner_done(struct usscanner_softc *sc) 582 1.1 augustss { 583 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 584 1.1 augustss usbd_status err; 585 1.1 augustss 586 1.1 augustss DPRINTFN(10,("usscanner_done: error=%d\n", sc->sc_xs->error)); 587 1.1 augustss 588 1.1 augustss sc->sc_state = UAS_STATUS; 589 1.39 skrll usbd_setup_xfer(sc->sc_intr_xfer, sc, &sc->sc_status, 1, 590 1.39 skrll USBD_SHORT_XFER_OK, USSCANNER_TIMEOUT, usscanner_intr_cb); 591 1.1 augustss err = usbd_transfer(sc->sc_intr_xfer); 592 1.1 augustss if (err == USBD_IN_PROGRESS) 593 1.1 augustss return; 594 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 595 1.1 augustss } 596 1.1 augustss 597 1.1 augustss Static void 598 1.40 msaitoh usscanner_sensecmd_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 599 1.1 augustss { 600 1.1 augustss struct usscanner_softc *sc = priv; 601 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 602 1.1 augustss usbd_status err; 603 1.1 augustss 604 1.1 augustss DPRINTFN(10, ("usscanner_sensecmd_cb status=%d\n", status)); 605 1.1 augustss 606 1.1 augustss #ifdef USSCANNER_DEBUG 607 1.1 augustss if (usscannerdebug > 15) 608 1.8 augustss xs->xs_periph->periph_flags |= 1; /* XXX 1 */ 609 1.1 augustss 610 1.1 augustss if (sc->sc_state != UAS_SENSECMD) { 611 1.26 cegger aprint_error_dev(sc->sc_dev, "!UAS_SENSECMD\n"); 612 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 613 1.1 augustss goto done; 614 1.1 augustss } 615 1.1 augustss #endif 616 1.1 augustss 617 1.1 augustss switch (status) { 618 1.1 augustss case USBD_NORMAL_COMPLETION: 619 1.1 augustss break; 620 1.1 augustss case USBD_TIMEOUT: 621 1.1 augustss xs->error = XS_TIMEOUT; 622 1.1 augustss goto done; 623 1.1 augustss default: 624 1.1 augustss xs->error = XS_DRIVER_STUFFUP; /* XXX ? */ 625 1.1 augustss goto done; 626 1.1 augustss } 627 1.1 augustss 628 1.1 augustss sc->sc_state = UAS_SENSEDATA; 629 1.39 skrll usbd_setup_xfer(sc->sc_datain_xfer, sc, sc->sc_datain_buffer, 630 1.39 skrll sizeof(xs->sense), USBD_SHORT_XFER_OK, 631 1.1 augustss USSCANNER_TIMEOUT, usscanner_sensedata_cb); 632 1.39 skrll err = usbd_transfer(sc->sc_datain_xfer); 633 1.1 augustss if (err == USBD_IN_PROGRESS) 634 1.1 augustss return; 635 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 636 1.1 augustss done: 637 1.1 augustss usscanner_done(sc); 638 1.1 augustss } 639 1.1 augustss 640 1.1 augustss Static void 641 1.40 msaitoh usscanner_cmd_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 642 1.1 augustss { 643 1.1 augustss struct usscanner_softc *sc = priv; 644 1.1 augustss struct scsipi_xfer *xs = sc->sc_xs; 645 1.39 skrll struct usbd_xfer *dxfer; 646 1.1 augustss usbd_status err; 647 1.1 augustss 648 1.1 augustss DPRINTFN(10, ("usscanner_cmd_cb status=%d\n", status)); 649 1.1 augustss 650 1.1 augustss #ifdef USSCANNER_DEBUG 651 1.1 augustss if (usscannerdebug > 15) 652 1.8 augustss xs->xs_periph->periph_flags |= 1; /* XXX 1 */ 653 1.1 augustss 654 1.1 augustss if (sc->sc_state != UAS_CMD) { 655 1.26 cegger aprint_error_dev(sc->sc_dev, "!UAS_CMD\n"); 656 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 657 1.1 augustss goto done; 658 1.1 augustss } 659 1.1 augustss #endif 660 1.1 augustss 661 1.1 augustss switch (status) { 662 1.1 augustss case USBD_NORMAL_COMPLETION: 663 1.1 augustss break; 664 1.1 augustss case USBD_TIMEOUT: 665 1.1 augustss xs->error = XS_TIMEOUT; 666 1.1 augustss goto done; 667 1.1 augustss case USBD_CANCELLED: 668 1.1 augustss goto done; 669 1.1 augustss default: 670 1.1 augustss xs->error = XS_DRIVER_STUFFUP; /* XXX ? */ 671 1.1 augustss goto done; 672 1.1 augustss } 673 1.1 augustss 674 1.1 augustss if (xs->datalen == 0) { 675 1.1 augustss DPRINTFN(4, ("usscanner_cmd_cb: no data phase\n")); 676 1.1 augustss xs->error = XS_NOERROR; 677 1.1 augustss goto done; 678 1.1 augustss } 679 1.1 augustss 680 1.1 augustss if (xs->xs_control & XS_CTL_DATA_IN) { 681 1.1 augustss DPRINTFN(4, ("usscanner_cmd_cb: data in len=%d\n", 682 1.1 augustss xs->datalen)); 683 1.39 skrll dxfer = sc->sc_datain_xfer; 684 1.1 augustss } else { 685 1.1 augustss DPRINTFN(4, ("usscanner_cmd_cb: data out len=%d\n", 686 1.1 augustss xs->datalen)); 687 1.39 skrll dxfer = sc->sc_dataout_xfer; 688 1.1 augustss } 689 1.1 augustss sc->sc_state = UAS_DATA; 690 1.39 skrll usbd_setup_xfer(dxfer, sc, xs->data, xs->datalen, 691 1.39 skrll USBD_SHORT_XFER_OK, xs->timeout, usscanner_data_cb); 692 1.39 skrll err = usbd_transfer(dxfer); 693 1.1 augustss if (err == USBD_IN_PROGRESS) 694 1.1 augustss return; 695 1.1 augustss xs->error = XS_DRIVER_STUFFUP; 696 1.1 augustss 697 1.1 augustss done: 698 1.1 augustss usscanner_done(sc); 699 1.1 augustss } 700 1.1 augustss 701 1.7 bouyer Static void 702 1.40 msaitoh usscanner_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 703 1.40 msaitoh void *arg) 704 1.7 bouyer { 705 1.7 bouyer struct scsipi_xfer *xs; 706 1.25 cube struct usscanner_softc *sc = 707 1.25 cube device_private(chan->chan_adapter->adapt_dev); 708 1.1 augustss usbd_status err; 709 1.1 augustss 710 1.7 bouyer switch (req) { 711 1.7 bouyer case ADAPTER_REQ_RUN_XFER: 712 1.7 bouyer xs = arg; 713 1.7 bouyer 714 1.11 wiz DPRINTFN(8, ("%s: usscanner_scsipi_request: %d:%d " 715 1.48 christos "xs=%p cmd=0x%02x datalen=%d (quirks=%#x, poll=%d)\n", 716 1.30 dyoung device_xname(sc->sc_dev), 717 1.37 martin xs->xs_periph->periph_target, xs->xs_periph->periph_lun, 718 1.7 bouyer xs, xs->cmd->opcode, xs->datalen, 719 1.38 martin xs->xs_periph->periph_quirks, 720 1.38 martin xs->xs_control & XS_CTL_POLL)); 721 1.7 bouyer 722 1.7 bouyer if (sc->sc_dying) { 723 1.7 bouyer xs->error = XS_DRIVER_STUFFUP; 724 1.7 bouyer goto done; 725 1.7 bouyer } 726 1.1 augustss 727 1.1 augustss #ifdef USSCANNER_DEBUG 728 1.37 martin if (xs->xs_periph->periph_target != USSCANNER_SCSIID_DEVICE) { 729 1.7 bouyer DPRINTF(("%s: wrong SCSI ID %d\n", 730 1.37 martin device_xname(sc->sc_dev), 731 1.37 martin xs->xs_periph->periph_target)); 732 1.7 bouyer xs->error = XS_DRIVER_STUFFUP; 733 1.7 bouyer goto done; 734 1.7 bouyer } 735 1.7 bouyer if (sc->sc_state != UAS_IDLE) { 736 1.30 dyoung printf("%s: !UAS_IDLE\n", device_xname(sc->sc_dev)); 737 1.7 bouyer xs->error = XS_DRIVER_STUFFUP; 738 1.7 bouyer goto done; 739 1.7 bouyer } 740 1.1 augustss #endif 741 1.1 augustss 742 1.7 bouyer if (xs->datalen > USSCANNER_MAX_TRANSFER_SIZE) { 743 1.25 cube aprint_normal_dev(sc->sc_dev, 744 1.25 cube "usscanner_scsipi_request: large datalen, %d\n", 745 1.25 cube xs->datalen); 746 1.7 bouyer xs->error = XS_DRIVER_STUFFUP; 747 1.7 bouyer goto done; 748 1.7 bouyer } 749 1.1 augustss 750 1.11 wiz DPRINTFN(4, ("%s: usscanner_scsipi_request: async cmdlen=%d" 751 1.30 dyoung " datalen=%d\n", device_xname(sc->sc_dev), xs->cmdlen, 752 1.11 wiz xs->datalen)); 753 1.7 bouyer sc->sc_state = UAS_CMD; 754 1.7 bouyer sc->sc_xs = xs; 755 1.7 bouyer memcpy(sc->sc_cmd_buffer, xs->cmd, xs->cmdlen); 756 1.39 skrll usbd_setup_xfer(sc->sc_cmd_xfer, sc, sc->sc_cmd_buffer, 757 1.39 skrll xs->cmdlen, 0, USSCANNER_TIMEOUT, usscanner_cmd_cb); 758 1.7 bouyer err = usbd_transfer(sc->sc_cmd_xfer); 759 1.7 bouyer if (err != USBD_IN_PROGRESS) { 760 1.7 bouyer xs->error = XS_DRIVER_STUFFUP; 761 1.7 bouyer goto done; 762 1.7 bouyer } 763 1.1 augustss 764 1.7 bouyer return; 765 1.1 augustss 766 1.1 augustss 767 1.1 augustss done: 768 1.7 bouyer sc->sc_state = UAS_IDLE; 769 1.33 mrg KERNEL_LOCK(1, curlwp); 770 1.7 bouyer scsipi_done(xs); 771 1.33 mrg KERNEL_UNLOCK_ONE(curlwp); 772 1.7 bouyer return; 773 1.7 bouyer 774 1.7 bouyer case ADAPTER_REQ_GROW_RESOURCES: 775 1.7 bouyer /* XXX Not supported. */ 776 1.7 bouyer return; 777 1.7 bouyer case ADAPTER_REQ_SET_XFER_MODE: 778 1.7 bouyer /* XXX Not supported. */ 779 1.7 bouyer return; 780 1.7 bouyer } 781 1.7 bouyer 782 1.1 augustss } 783