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