xref: /netbsd-src/sys/dev/usb/utoppy.c (revision daf6c4152fcddc27c445489775ed1f66ab4ea9a9)
1 /*	$NetBSD: utoppy.c,v 1.15 2010/11/03 22:34:24 dyoung Exp $	*/
2 
3 /*-
4  * Copyright (c) 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Steve C. Woodford.
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 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.15 2010/11/03 22:34:24 dyoung Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/kernel.h>
39 #include <sys/fcntl.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/ioctl.h>
43 #include <sys/uio.h>
44 #include <sys/conf.h>
45 #include <sys/vnode.h>
46 
47 #include <dev/usb/usb.h>
48 #include <dev/usb/usbdi.h>
49 #include <dev/usb/usbdi_util.h>
50 #include <dev/usb/usbdevs.h>
51 #include <dev/usb/usb_quirks.h>
52 #include <dev/usb/utoppy.h>
53 
54 #undef UTOPPY_DEBUG
55 #ifdef UTOPPY_DEBUG
56 #define	UTOPPY_DBG_OPEN		0x0001
57 #define	UTOPPY_DBG_CLOSE	0x0002
58 #define	UTOPPY_DBG_READ		0x0004
59 #define	UTOPPY_DBG_WRITE	0x0008
60 #define	UTOPPY_DBG_IOCTL	0x0010
61 #define	UTOPPY_DBG_SEND_PACKET	0x0020
62 #define	UTOPPY_DBG_RECV_PACKET	0x0040
63 #define	UTOPPY_DBG_ADDPATH	0x0080
64 #define	UTOPPY_DBG_READDIR	0x0100
65 #define	UTOPPY_DBG_DUMP		0x0200
66 #define	DPRINTF(l, m)				\
67 		do {				\
68 			if (utoppy_debug & l)	\
69 				printf m;	\
70 		} while (/*CONSTCOND*/0)
71 static int utoppy_debug = 0;
72 static void utoppy_dump_packet(const void *, size_t);
73 #define	DDUMP_PACKET(p, l)					\
74 		do {						\
75 			if (utoppy_debug & UTOPPY_DBG_DUMP)	\
76 				utoppy_dump_packet((p), (l));	\
77 		} while (/*CONSTCOND*/0)
78 #else
79 #define	DPRINTF(l, m)		/* nothing */
80 #define	DDUMP_PACKET(p, l)	/* nothing */
81 #endif
82 
83 
84 #define	UTOPPY_CONFIG_NO	1
85 #define	UTOPPY_NUMENDPOINTS	2
86 
87 #define	UTOPPY_BSIZE		0xffff
88 #define	UTOPPY_FRAG_SIZE	0x1000
89 #define	UTOPPY_HEADER_SIZE	8
90 #define	UTOPPY_SHORT_TIMEOUT	(500)		/* 0.5 seconds */
91 #define	UTOPPY_LONG_TIMEOUT	(10 * 1000)	/* 10 seconds */
92 
93 /* Protocol Commands and Responses */
94 #define	UTOPPY_RESP_ERROR		0x0001
95 #define	UTOPPY_CMD_ACK			0x0002
96 #define	 UTOPPY_RESP_SUCCESS		UTOPPY_CMD_ACK
97 #define	UTOPPY_CMD_CANCEL		0x0003
98 #define	UTOPPY_CMD_READY		0x0100
99 #define	UTOPPY_CMD_RESET		0x0101
100 #define	UTOPPY_CMD_TURBO		0x0102
101 #define	UTOPPY_CMD_STATS		0x1000
102 #define  UTOPPY_RESP_STATS_DATA		0x1001
103 #define	UTOPPY_CMD_READDIR		0x1002
104 #define	 UTOPPY_RESP_READDIR_DATA	0x1003
105 #define	 UTOPPY_RESP_READDIR_END	0x1004
106 #define	UTOPPY_CMD_DELETE		0x1005
107 #define	UTOPPY_CMD_RENAME		0x1006
108 #define	UTOPPY_CMD_MKDIR		0x1007
109 #define	UTOPPY_CMD_FILE			0x1008
110 #define  UTOPPY_FILE_WRITE		0
111 #define  UTOPPY_FILE_READ		1
112 #define	 UTOPPY_RESP_FILE_HEADER	0x1009
113 #define	 UTOPPY_RESP_FILE_DATA		0x100a
114 #define	 UTOPPY_RESP_FILE_END		0x100b
115 
116 enum utoppy_state {
117 	UTOPPY_STATE_CLOSED,
118 	UTOPPY_STATE_OPENING,
119 	UTOPPY_STATE_IDLE,
120 	UTOPPY_STATE_READDIR,
121 	UTOPPY_STATE_READFILE,
122 	UTOPPY_STATE_WRITEFILE
123 };
124 
125 struct utoppy_softc {
126 	device_t sc_dev;
127 	usbd_device_handle sc_udev;	/* device */
128 	usbd_interface_handle sc_iface;	/* interface */
129 	int sc_dying;
130 	int sc_refcnt;
131 
132 	enum utoppy_state sc_state;
133 	u_int sc_turbo_mode;
134 
135 	int sc_out;
136 	usbd_pipe_handle sc_out_pipe;	/* bulk out pipe */
137 	usbd_xfer_handle sc_out_xfer;
138 	void *sc_out_buf;
139 	void *sc_out_data;
140 	uint64_t sc_wr_offset;
141 	uint64_t sc_wr_size;
142 
143 	int sc_in;
144 	usbd_pipe_handle sc_in_pipe;	/* bulk in pipe */
145 	usbd_xfer_handle sc_in_xfer;
146 	void *sc_in_buf;
147 	void *sc_in_data;
148 	size_t sc_in_len;
149 	u_int sc_in_offset;
150 };
151 
152 struct utoppy_header {
153 	uint16_t h_len;
154 	uint16_t h_crc;
155 	uint16_t h_cmd2;
156 	uint16_t h_cmd;
157 	uint8_t h_data[0];
158 };
159 #define	UTOPPY_OUT_INIT(sc)					\
160 	do {							\
161 		struct utoppy_header *_h = sc->sc_out_data;	\
162 		_h->h_len = 0;					\
163 	} while (/*CONSTCOND*/0)
164 
165 #define	UTOPPY_MJD_1970 40587u	/* MJD value for Jan 1 00:00:00 1970 */
166 
167 #define	UTOPPY_FTYPE_DIR	1
168 #define	UTOPPY_FTYPE_FILE	2
169 
170 #define	UTOPPY_IN_DATA(sc)	\
171  ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE]))
172 
173 dev_type_open(utoppyopen);
174 dev_type_close(utoppyclose);
175 dev_type_read(utoppyread);
176 dev_type_write(utoppywrite);
177 dev_type_ioctl(utoppyioctl);
178 
179 const struct cdevsw utoppy_cdevsw = {
180 	utoppyopen, utoppyclose, utoppyread, utoppywrite, utoppyioctl,
181 	nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
182 };
183 
184 #define	UTOPPYUNIT(n)	(minor(n))
185 
186 int             utoppy_match(device_t, cfdata_t, void *);
187 void            utoppy_attach(device_t, device_t, void *);
188 int             utoppy_detach(device_t, int);
189 int             utoppy_activate(device_t, enum devact);
190 extern struct cfdriver utoppy_cd;
191 CFATTACH_DECL_NEW(utoppy, sizeof(struct utoppy_softc), utoppy_match, utoppy_attach, utoppy_detach, utoppy_activate);
192 
193 int
194 utoppy_match(device_t parent, cfdata_t match, void *aux)
195 {
196 	struct usb_attach_arg *uaa = aux;
197 
198 	if (uaa->vendor == USB_VENDOR_TOPFIELD &&
199 	    uaa->product == USB_PRODUCT_TOPFIELD_TF5000PVR)
200 		return (UMATCH_VENDOR_PRODUCT);
201 
202 	return (UMATCH_NONE);
203 }
204 
205 void
206 utoppy_attach(device_t parent, device_t self, void *aux)
207 {
208 	struct utoppy_softc *sc = device_private(self);
209 	struct usb_attach_arg *uaa = aux;
210 	usbd_device_handle dev = uaa->device;
211 	usbd_interface_handle iface;
212 	usb_endpoint_descriptor_t *ed;
213 	char *devinfop;
214 	u_int8_t epcount;
215 	int i;
216 
217 	sc->sc_dev = self;
218 
219 	aprint_naive("\n");
220 	aprint_normal("\n");
221 
222 	devinfop = usbd_devinfo_alloc(dev, 0);
223 	aprint_normal_dev(self, "%s\n", devinfop);
224 	usbd_devinfo_free(devinfop);
225 
226 	sc->sc_dying = 0;
227 	sc->sc_refcnt = 0;
228 	sc->sc_udev = dev;
229 
230 	if (usbd_set_config_index(dev, 0, 1)
231 	    || usbd_device2interface_handle(dev, 0, &iface)) {
232 		aprint_error_dev(self, "Configuration failed\n");
233 		return;
234 	}
235 
236 	epcount = 0;
237 	(void) usbd_endpoint_count(iface, &epcount);
238 	if (epcount != UTOPPY_NUMENDPOINTS) {
239 		aprint_error_dev(self, "Expected %d endpoints, got %d\n",
240 		    UTOPPY_NUMENDPOINTS, epcount);
241 		return;
242 	}
243 
244 	sc->sc_in = -1;
245 	sc->sc_out = -1;
246 
247 	for (i = 0; i < epcount; i++) {
248 		ed = usbd_interface2endpoint_descriptor(iface, i);
249 		if (ed == NULL) {
250 			aprint_error_dev(self, "couldn't get ep %d\n", i);
251 			return;
252 		}
253 
254 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
255 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
256 			sc->sc_in = ed->bEndpointAddress;
257 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
258 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
259 			sc->sc_out = ed->bEndpointAddress;
260 		}
261 	}
262 
263 	if (sc->sc_out == -1 || sc->sc_in == -1) {
264 		aprint_error_dev(self,
265 		    "could not find bulk in/out endpoints\n");
266 		sc->sc_dying = 1;
267 		return;
268 	}
269 
270 	sc->sc_iface = iface;
271 	sc->sc_udev = dev;
272 
273 	sc->sc_out_xfer = usbd_alloc_xfer(sc->sc_udev);
274 	if (sc->sc_out_xfer == NULL) {
275 		aprint_error_dev(self, "could not allocate bulk out xfer\n");
276 		goto fail0;
277 	}
278 
279 	sc->sc_out_buf = usbd_alloc_buffer(sc->sc_out_xfer, UTOPPY_FRAG_SIZE);
280 	if (sc->sc_out_buf == NULL) {
281 		aprint_error_dev(self, "could not allocate bulk out buffer\n");
282 		goto fail1;
283 	}
284 
285 	sc->sc_in_xfer = usbd_alloc_xfer(sc->sc_udev);
286 	if (sc->sc_in_xfer == NULL) {
287 		aprint_error_dev(self, "could not allocate bulk in xfer\n");
288 		goto fail1;
289 	}
290 
291 	sc->sc_in_buf = usbd_alloc_buffer(sc->sc_in_xfer, UTOPPY_FRAG_SIZE);
292 	if (sc->sc_in_buf == NULL) {
293 		aprint_error_dev(self, "could not allocate bulk in buffer\n");
294 		goto fail2;
295 	}
296 
297 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
298 			   sc->sc_dev);
299 
300 	return;
301 
302  fail2:	usbd_free_xfer(sc->sc_in_xfer);
303 	sc->sc_in_xfer = NULL;
304 
305  fail1:	usbd_free_xfer(sc->sc_out_xfer);
306 	sc->sc_out_xfer = NULL;
307 
308  fail0:	sc->sc_dying = 1;
309 	return;
310 }
311 
312 int
313 utoppy_activate(device_t self, enum devact act)
314 {
315 	struct utoppy_softc *sc = device_private(self);
316 
317 	switch (act) {
318 	case DVACT_DEACTIVATE:
319 		sc->sc_dying = 1;
320 		return 0;
321 	default:
322 		return EOPNOTSUPP;
323 	}
324 }
325 
326 int
327 utoppy_detach(device_t self, int flags)
328 {
329 	struct utoppy_softc *sc = device_private(self);
330 	int maj, mn;
331 	int s;
332 
333 	sc->sc_dying = 1;
334 	if (sc->sc_out_pipe != NULL)
335 		usbd_abort_pipe(sc->sc_out_pipe);
336 	if (sc->sc_in_pipe != NULL)
337 		usbd_abort_pipe(sc->sc_in_pipe);
338 
339 	if (sc->sc_in_xfer != NULL)
340 		usbd_free_xfer(sc->sc_in_xfer);
341 	if (sc->sc_out_xfer != NULL)
342 		usbd_free_xfer(sc->sc_out_xfer);
343 
344 	s = splusb();
345 	if (--sc->sc_refcnt >= 0)
346 		usb_detach_wait(sc->sc_dev);
347 	splx(s);
348 
349 	/* locate the major number */
350 	maj = cdevsw_lookup_major(&utoppy_cdevsw);
351 
352 	/* Nuke the vnodes for any open instances (calls close). */
353 	mn = self->dv_unit;
354 	vdevgone(maj, mn, mn, VCHR);
355 
356 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
357 			   sc->sc_dev);
358 
359 	return (0);
360 }
361 
362 static const uint16_t utoppy_crc16_lookup[] = {
363 	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
364 	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
365 	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
366 	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
367 	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
368 	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
369 	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
370 	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
371 	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
372 	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
373 	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
374 	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
375 	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
376 	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
377 	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
378 	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
379 	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
380 	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
381 	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
382 	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
383 	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
384 	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
385 	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
386 	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
387 	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
388 	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
389 	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
390 	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
391 	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
392 	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
393 	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
394 	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
395 };
396 
397 #define	UTOPPY_CRC16(ccrc,b)	\
398 	(utoppy_crc16_lookup[((ccrc) ^ (b)) & 0xffu] ^ ((ccrc) >> 8))
399 
400 static const int utoppy_usbdstatus_lookup[] = {
401 	0,		/* USBD_NORMAL_COMPLETION */
402 	EINPROGRESS,	/* USBD_IN_PROGRESS */
403 	EALREADY,	/* USBD_PENDING_REQUESTS */
404 	EAGAIN,		/* USBD_NOT_STARTED */
405 	EINVAL,		/* USBD_INVAL */
406 	ENOMEM,		/* USBD_NOMEM */
407 	ECONNRESET,	/* USBD_CANCELLED */
408 	EFAULT,		/* USBD_BAD_ADDRESS */
409 	EBUSY,		/* USBD_IN_USE */
410 	EADDRNOTAVAIL,	/* USBD_NO_ADDR */
411 	ENETDOWN,	/* USBD_SET_ADDR_FAILED */
412 	EIO,		/* USBD_NO_POWER */
413 	EMLINK,		/* USBD_TOO_DEEP */
414 	EIO,		/* USBD_IOERROR */
415 	ENXIO,		/* USBD_NOT_CONFIGURED */
416 	ETIMEDOUT,	/* USBD_TIMEOUT */
417 	EBADMSG,	/* USBD_SHORT_XFER */
418 	EHOSTDOWN,	/* USBD_STALLED */
419 	EINTR		/* USBD_INTERRUPTED */
420 };
421 
422 static __inline int
423 utoppy_usbd_status2errno(usbd_status err)
424 {
425 
426 	if (err >= USBD_ERROR_MAX)
427 		return (EFAULT);
428 	return (utoppy_usbdstatus_lookup[err]);
429 }
430 
431 #ifdef UTOPPY_DEBUG
432 static const char *
433 utoppy_state_string(enum utoppy_state state)
434 {
435 	const char *str;
436 
437 	switch (state) {
438 	case UTOPPY_STATE_CLOSED:
439 		str = "CLOSED";
440 		break;
441 	case UTOPPY_STATE_OPENING:
442 		str = "OPENING";
443 		break;
444 	case UTOPPY_STATE_IDLE:
445 		str = "IDLE";
446 		break;
447 	case UTOPPY_STATE_READDIR:
448 		str = "READ DIRECTORY";
449 		break;
450 	case UTOPPY_STATE_READFILE:
451 		str = "READ FILE";
452 		break;
453 	case UTOPPY_STATE_WRITEFILE:
454 		str = "WRITE FILE";
455 		break;
456 	default:
457 		str = "INVALID!";
458 		break;
459 	}
460 
461 	return (str);
462 }
463 
464 static void
465 utoppy_dump_packet(const void *b, size_t len)
466 {
467 	const uint8_t *buf = b, *l;
468 	uint8_t c;
469 	size_t i, j;
470 
471 	if (len == 0)
472 		return;
473 
474 	len = min(len, 256);
475 
476 	printf("00: ");
477 
478 	for (i = 0, l = buf; i < len; i++) {
479 		printf("%02x ", *buf++);
480 
481 		if ((i % 16) == 15) {
482 			for (j = 0; j < 16; j++) {
483 				c = *l++;
484 				if (c < ' ' || c > 0x7e)
485 					c = '.';
486 				printf("%c", c);
487 			}
488 
489 			printf("\n");
490 			l = buf;
491 
492 			if ((i + 1) < len)
493 				printf("%02x: ", (u_int)i + 1);
494 		}
495 	}
496 
497 	while ((i++ % 16) != 0)
498 		printf("   ");
499 
500 	if (l < buf) {
501 		while (l < buf) {
502 			c = *l++;
503 			if (c < ' ' || c > 0x7e)
504 				c = '.';
505 			printf("%c", c);
506 		}
507 
508 		printf("\n");
509 	}
510 }
511 #endif
512 
513 /*
514  * Very much like usbd_bulk_transfer(), except don't catch signals
515  */
516 static void
517 utoppy_bulk_transfer_cb(usbd_xfer_handle xfer,
518     usbd_private_handle priv,
519     usbd_status status)
520 {
521 
522 	wakeup(xfer);
523 }
524 
525 static usbd_status
526 utoppy_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
527     u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size,
528     const char *lbl)
529 {
530 	usbd_status err;
531 	int s, error;
532 
533 	usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
534 	    utoppy_bulk_transfer_cb);
535 	s = splusb();
536 	err = usbd_transfer(xfer);
537 	if (err != USBD_IN_PROGRESS) {
538 		splx(s);
539 		return (err);
540 	}
541 	error = tsleep((void *)xfer, PZERO, lbl, 0);
542 	splx(s);
543 	if (error) {
544 		usbd_abort_pipe(pipe);
545 		return (USBD_INTERRUPTED);
546 	}
547 	usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
548 	return (err);
549 }
550 
551 static int
552 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout)
553 {
554 	struct utoppy_header *h;
555 	usbd_status err;
556 	uint32_t len;
557 	uint16_t dlen, crc;
558 	uint8_t *data, *e, t1, t2;
559 
560 	h = sc->sc_out_data;
561 
562 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, "
563 	    "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len));
564 
565 	dlen = h->h_len;
566 	len = dlen + UTOPPY_HEADER_SIZE;
567 
568 	if (len & 1)
569 		len++;
570 	if ((len % 64) == 0)
571 		len += 2;
572 
573 	if (len >= UTOPPY_BSIZE) {
574 		DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
575 		    "packet too big (%d)\n", device_xname(sc->sc_dev), (int)len));
576 		return (EINVAL);
577 	}
578 
579 	h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE);
580 	h->h_cmd2 = 0;
581 	h->h_cmd = htole16(cmd);
582 
583 	/* The command word is part of the CRC */
584 	crc = UTOPPY_CRC16(0,   0);
585 	crc = UTOPPY_CRC16(crc, 0);
586 	crc = UTOPPY_CRC16(crc, cmd >> 8);
587 	crc = UTOPPY_CRC16(crc, cmd);
588 
589 	/*
590 	 * If there is data following the header, calculate the CRC and
591 	 * byte-swap as we go.
592 	 */
593 	if (dlen) {
594 		data = h->h_data;
595 		e = data + (dlen & ~1);
596 
597 		do {
598 			t1 = data[0];
599 			t2 = data[1];
600 			crc = UTOPPY_CRC16(crc, t1);
601 			crc = UTOPPY_CRC16(crc, t2);
602 			*data++ = t2;
603 			*data++ = t1;
604 		} while (data < e);
605 
606 		if (dlen & 1) {
607 			t1 = data[0];
608 			crc = UTOPPY_CRC16(crc, t1);
609 			data[1] = t1;
610 		}
611 	}
612 
613 	h->h_crc = htole16(crc);
614 	data = sc->sc_out_data;
615 
616 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len "
617 	    "%d...\n", device_xname(sc->sc_dev), (int)len));
618 	DDUMP_PACKET(data, len);
619 
620 	do {
621 		uint32_t thislen;
622 
623 		thislen = min(len, UTOPPY_FRAG_SIZE);
624 
625 		memcpy(sc->sc_out_buf, data, thislen);
626 
627 		err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe,
628 		    USBD_NO_COPY, timeout, sc->sc_out_buf, &thislen,
629 		    "utoppytx");
630 
631 		if (thislen != min(len, UTOPPY_FRAG_SIZE)) {
632 			DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: "
633 			    "utoppy_send_packet: sent %ld, err %d\n",
634 			    device_xname(sc->sc_dev), (u_long)thislen, err));
635 		}
636 
637 		if (err == 0) {
638 			len -= thislen;
639 			data += thislen;
640 		}
641 	} while (err == 0 && len);
642 
643 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
644 	    "usbd_bulk_transfer() returned %d.\n", device_xname(sc->sc_dev),err));
645 
646 	return (err ? utoppy_usbd_status2errno(err) : 0);
647 }
648 
649 static int
650 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout)
651 {
652 	struct utoppy_header *h;
653 	usbd_status err;
654 	uint32_t len, thislen, requested, bytesleft;
655 	uint16_t crc;
656 	uint8_t *data, *e, t1, t2;
657 
658 	data = sc->sc_in_data;
659 	len = 0;
660 	bytesleft = UTOPPY_BSIZE;
661 
662 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n",
663 	    device_xname(sc->sc_dev)));
664 
665 	do {
666 		requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE);
667 
668 		err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe,
669 		    USBD_NO_COPY | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf,
670 		    &thislen, "utoppyrx");
671 
672 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
673 		    "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
674 		    device_xname(sc->sc_dev), err, (u_int)thislen, data));
675 
676 		if (err == 0) {
677 			memcpy(data, sc->sc_in_buf, thislen);
678 			DDUMP_PACKET(data, thislen);
679 			len += thislen;
680 			bytesleft -= thislen;
681 			data += thislen;
682 		}
683 	} while (err == 0 && bytesleft && thislen == requested);
684 
685 	if (err)
686 		return (utoppy_usbd_status2errno(err));
687 
688 	h = sc->sc_in_data;
689 
690 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d "
691 	    "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h));
692 	DDUMP_PACKET(h, len);
693 
694 	if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) {
695 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad "
696 		    " length (len %d, h_len %d)\n", device_xname(sc->sc_dev),
697 		    (int)len, le16toh(h->h_len)));
698 		return (EIO);
699 	}
700 
701 	len = h->h_len = le16toh(h->h_len);
702 	h->h_crc = le16toh(h->h_crc);
703 	*respp = h->h_cmd = le16toh(h->h_cmd);
704 	h->h_cmd2 = le16toh(h->h_cmd2);
705 
706 	/*
707 	 * To maximise data throughput when transferring files, acknowledge
708 	 * data blocks as soon as we receive them. If we detect an error
709 	 * later on, we can always cancel.
710 	 */
711 	if (*respp == UTOPPY_RESP_FILE_DATA) {
712 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
713 		    "ACKing file data\n", device_xname(sc->sc_dev)));
714 
715 		UTOPPY_OUT_INIT(sc);
716 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
717 		    UTOPPY_SHORT_TIMEOUT);
718 		if (err) {
719 			DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: "
720 			    "utoppy_recv_packet: failed to ACK file data: %d\n",
721 			    device_xname(sc->sc_dev), err));
722 			return (err);
723 		}
724 	}
725 
726 	/* The command word is part of the CRC */
727 	crc = UTOPPY_CRC16(0,   h->h_cmd2 >> 8);
728 	crc = UTOPPY_CRC16(crc, h->h_cmd2);
729 	crc = UTOPPY_CRC16(crc, h->h_cmd >> 8);
730 	crc = UTOPPY_CRC16(crc, h->h_cmd);
731 
732 	/*
733 	 * Extract any payload, byte-swapping and calculating the CRC16
734 	 * as we go.
735 	 */
736 	if (len > UTOPPY_HEADER_SIZE) {
737 		data = h->h_data;
738 		e = data + ((len & ~1) - UTOPPY_HEADER_SIZE);
739 
740 		while (data < e) {
741 			t1 = data[0];
742 			t2 = data[1];
743 			crc = UTOPPY_CRC16(crc, t2);
744 			crc = UTOPPY_CRC16(crc, t1);
745 			*data++ = t2;
746 			*data++ = t1;
747 		}
748 
749 		if (len & 1) {
750 			t1 = data[1];
751 			crc = UTOPPY_CRC16(crc, t1);
752 			*data = t1;
753 		}
754 	}
755 
756 	sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE;
757 	sc->sc_in_offset = 0;
758 
759 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, "
760 	    "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev),
761 	    (int)len, crc, h->h_crc));
762 	DDUMP_PACKET(h, len);
763 
764 	return ((crc == h->h_crc) ? 0 : EBADMSG);
765 }
766 
767 static __inline void *
768 utoppy_current_ptr(void *b)
769 {
770 	struct utoppy_header *h = b;
771 
772 	return (&h->h_data[h->h_len]);
773 }
774 
775 static __inline void
776 utoppy_advance_ptr(void *b, size_t len)
777 {
778 	struct utoppy_header *h = b;
779 
780 	h->h_len += len;
781 }
782 
783 static __inline void
784 utoppy_add_8(struct utoppy_softc *sc, uint8_t v)
785 {
786 	struct utoppy_header *h = sc->sc_out_data;
787 	uint8_t *p;
788 
789 	p = utoppy_current_ptr(h);
790 	*p = v;
791 	utoppy_advance_ptr(h, sizeof(v));
792 }
793 
794 static __inline void
795 utoppy_add_16(struct utoppy_softc *sc, uint16_t v)
796 {
797 	struct utoppy_header *h = sc->sc_out_data;
798 	uint8_t *p;
799 
800 	p = utoppy_current_ptr(h);
801 	*p++ = (uint8_t)(v >> 8);
802 	*p = (uint8_t)v;
803 	utoppy_advance_ptr(h, sizeof(v));
804 }
805 
806 static __inline void
807 utoppy_add_32(struct utoppy_softc *sc, uint32_t v)
808 {
809 	struct utoppy_header *h = sc->sc_out_data;
810 	uint8_t *p;
811 
812 	p = utoppy_current_ptr(h);
813 	*p++ = (uint8_t)(v >> 24);
814 	*p++ = (uint8_t)(v >> 16);
815 	*p++ = (uint8_t)(v >> 8);
816 	*p = (uint8_t)v;
817 	utoppy_advance_ptr(h, sizeof(v));
818 }
819 
820 static __inline void
821 utoppy_add_64(struct utoppy_softc *sc, uint64_t v)
822 {
823 	struct utoppy_header *h = sc->sc_out_data;
824 	uint8_t *p;
825 
826 	p = utoppy_current_ptr(h);
827 	*p++ = (uint8_t)(v >> 56);
828 	*p++ = (uint8_t)(v >> 48);
829 	*p++ = (uint8_t)(v >> 40);
830 	*p++ = (uint8_t)(v >> 32);
831 	*p++ = (uint8_t)(v >> 24);
832 	*p++ = (uint8_t)(v >> 16);
833 	*p++ = (uint8_t)(v >> 8);
834 	*p = (uint8_t)v;
835 	utoppy_advance_ptr(h, sizeof(v));
836 }
837 
838 static __inline void
839 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len)
840 {
841 	struct utoppy_header *h = sc->sc_out_data;
842 	char *p;
843 
844 	p = utoppy_current_ptr(h);
845 	memset(p, 0, len);
846 	strncpy(p, str, len);
847 	utoppy_advance_ptr(h, len);
848 }
849 
850 static int
851 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen)
852 {
853 	struct utoppy_header *h = sc->sc_out_data;
854 	uint8_t *p, *str, *s;
855 	size_t len;
856 	int err;
857 
858 	p = utoppy_current_ptr(h);
859 
860 	str = putlen ? (p + sizeof(uint16_t)) : p;
861 
862 	err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len);
863 
864 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n",
865 	    err, (int)len));
866 
867 	if (err)
868 		return (err);
869 
870 	if (len < 2)
871 		return (EINVAL);
872 
873 	/*
874 	 * copyinstr(9) has already copied the terminating NUL character,
875 	 * but we append another one in case we have to pad the length
876 	 * later on.
877 	 */
878 	str[len] = '\0';
879 
880 	/*
881 	 * The Toppy uses backslash as the directory separator, so convert
882 	 * all forward slashes.
883 	 */
884 	for (s = &str[len - 2]; s >= str; s--)
885 		if (*s == '/')
886 			*s = '\\';
887 
888 	if ((len + h->h_len) & 1)
889 		len++;
890 
891 	if (putlen)
892 		utoppy_add_16(sc, len);
893 
894 	utoppy_advance_ptr(h, len);
895 
896 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n",
897 	    (u_int)len));
898 
899 	return (0);
900 }
901 
902 static __inline int
903 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp)
904 {
905 	uint8_t *p;
906 
907 	if (sc->sc_in_len < sizeof(*vp))
908 		return (1);
909 
910 	p = UTOPPY_IN_DATA(sc);
911 	*vp = *p;
912 	sc->sc_in_offset += sizeof(*vp);
913 	sc->sc_in_len -= sizeof(*vp);
914 	return (0);
915 }
916 
917 static __inline int
918 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp)
919 {
920 	uint16_t v;
921 	uint8_t *p;
922 
923 	if (sc->sc_in_len < sizeof(v))
924 		return (1);
925 
926 	p = UTOPPY_IN_DATA(sc);
927 	v = *p++;
928 	v = (v << 8) | *p;
929 	*vp = v;
930 	sc->sc_in_offset += sizeof(v);
931 	sc->sc_in_len -= sizeof(v);
932 	return (0);
933 }
934 
935 static __inline int
936 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp)
937 {
938 	uint32_t v;
939 	uint8_t *p;
940 
941 	if (sc->sc_in_len < sizeof(v))
942 		return (1);
943 
944 	p = UTOPPY_IN_DATA(sc);
945 	v = *p++;
946 	v = (v << 8) | *p++;
947 	v = (v << 8) | *p++;
948 	v = (v << 8) | *p;
949 	*vp = v;
950 	sc->sc_in_offset += sizeof(v);
951 	sc->sc_in_len -= sizeof(v);
952 	return (0);
953 }
954 
955 static __inline int
956 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp)
957 {
958 	uint64_t v;
959 	uint8_t *p;
960 
961 	if (sc->sc_in_len < sizeof(v))
962 		return (1);
963 
964 	p = UTOPPY_IN_DATA(sc);
965 	v = *p++;
966 	v = (v << 8) | *p++;
967 	v = (v << 8) | *p++;
968 	v = (v << 8) | *p++;
969 	v = (v << 8) | *p++;
970 	v = (v << 8) | *p++;
971 	v = (v << 8) | *p++;
972 	v = (v << 8) | *p;
973 	*vp = v;
974 	sc->sc_in_offset += sizeof(v);
975 	sc->sc_in_len -= sizeof(v);
976 	return (0);
977 }
978 
979 static __inline int
980 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len)
981 {
982 	char *p;
983 
984 	if (sc->sc_in_len < len)
985 		return (1);
986 
987 	memset(str, 0, len);
988 	p = UTOPPY_IN_DATA(sc);
989 	strncpy(str, p, len);
990 	sc->sc_in_offset += len;
991 	sc->sc_in_len -= len;
992 	return (0);
993 }
994 
995 static int
996 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout,
997     uint16_t *presp)
998 {
999 	int err;
1000 
1001 	err = utoppy_send_packet(sc, cmd, timeout);
1002 	if (err)
1003 		return (err);
1004 
1005 	err = utoppy_recv_packet(sc, presp, timeout);
1006 	if (err == EBADMSG) {
1007 		UTOPPY_OUT_INIT(sc);
1008 		utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout);
1009 	}
1010 
1011 	return (err);
1012 }
1013 
1014 static int
1015 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp)
1016 {
1017 	uint16_t mjd;
1018 	uint8_t hour, minute, sec;
1019 	uint32_t rv;
1020 
1021 	if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) ||
1022 	    utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec))
1023 		return (1);
1024 
1025 	if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){
1026 		*tp = 0;
1027 		return (0);
1028 	}
1029 
1030 	rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd;
1031 
1032 	/* Calculate seconds since 1970 */
1033 	rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24;
1034 
1035 	/* Add in the hours, minutes, and seconds */
1036 	rv += (uint32_t)hour * 60 * 60;
1037 	rv += (uint32_t)minute * 60;
1038 	rv += sec;
1039 	*tp = (time_t)rv;
1040 
1041 	return (0);
1042 }
1043 
1044 static void
1045 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t)
1046 {
1047 	u_int mjd, hour, minute;
1048 
1049 	mjd = t / (60 * 60 * 24);
1050 	t -= mjd * 60 * 60 * 24;
1051 
1052 	hour = t / (60 * 60);
1053 	t -= hour * 60 * 60;
1054 
1055 	minute = t / 60;
1056 	t -= minute * 60;
1057 
1058 	utoppy_add_16(sc, mjd + UTOPPY_MJD_1970);
1059 	utoppy_add_8(sc, hour);
1060 	utoppy_add_8(sc, minute);
1061 	utoppy_add_8(sc, t);
1062 }
1063 
1064 static int
1065 utoppy_turbo_mode(struct utoppy_softc *sc, int state)
1066 {
1067 	uint16_t r;
1068 	int err;
1069 
1070 	UTOPPY_OUT_INIT(sc);
1071 	utoppy_add_32(sc, state);
1072 
1073 	err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r);
1074 	if (err)
1075 		return (err);
1076 
1077 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1078 }
1079 
1080 static int
1081 utoppy_check_ready(struct utoppy_softc *sc)
1082 {
1083 	uint16_t r;
1084 	int err;
1085 
1086 	UTOPPY_OUT_INIT(sc);
1087 
1088 	err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r);
1089 	if (err)
1090 		return (err);
1091 
1092 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1093 }
1094 
1095 static int
1096 utoppy_cancel(struct utoppy_softc *sc)
1097 {
1098 	uint16_t r;
1099 	int err, i;
1100 
1101 	/*
1102 	 * Issue the cancel command serveral times. the Toppy doesn't
1103 	 * always respond to the first.
1104 	 */
1105 	for (i = 0; i < 3; i++) {
1106 		UTOPPY_OUT_INIT(sc);
1107 		err = utoppy_command(sc, UTOPPY_CMD_CANCEL,
1108 		    UTOPPY_SHORT_TIMEOUT, &r);
1109 		if (err == 0 && r == UTOPPY_RESP_SUCCESS)
1110 			break;
1111 		err = ETIMEDOUT;
1112 	}
1113 
1114 	if (err)
1115 		return (err);
1116 
1117 	/*
1118 	 * Make sure turbo mode is off, otherwise the Toppy will not
1119 	 * respond to remote control input.
1120 	 */
1121 	(void) utoppy_turbo_mode(sc, 0);
1122 
1123 	sc->sc_state = UTOPPY_STATE_IDLE;
1124 	return (0);
1125 }
1126 
1127 static int
1128 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us)
1129 {
1130 	uint32_t hsize, hfree;
1131 	uint16_t r;
1132 	int err;
1133 
1134 	UTOPPY_OUT_INIT(sc);
1135 	err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r);
1136 	if (err)
1137 		return (err);
1138 
1139 	if (r != UTOPPY_RESP_STATS_DATA)
1140 		return (EIO);
1141 
1142 	if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree))
1143 		return (EIO);
1144 
1145 	us->us_hdd_size = hsize;
1146 	us->us_hdd_size *= 1024;
1147 	us->us_hdd_free = hfree;
1148 	us->us_hdd_free *= 1024;
1149 
1150 	return (0);
1151 }
1152 
1153 static int
1154 utoppy_readdir_next(struct utoppy_softc *sc)
1155 {
1156 	uint16_t resp;
1157 	int err;
1158 
1159 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n",
1160 	    device_xname(sc->sc_dev)));
1161 
1162 	/*
1163 	 * Fetch the next READDIR response
1164 	 */
1165 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1166 	if (err) {
1167 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1168 		    "utoppy_recv_packet() returned %d\n",
1169 		    device_xname(sc->sc_dev), err));
1170 		if (err == EBADMSG) {
1171 			UTOPPY_OUT_INIT(sc);
1172 			utoppy_send_packet(sc, UTOPPY_RESP_ERROR,
1173 			    UTOPPY_LONG_TIMEOUT);
1174 		}
1175 		utoppy_cancel(sc);
1176 		return (err);
1177 	}
1178 
1179 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1180 	    "utoppy_recv_packet() returned %d, len %ld\n",
1181 	    device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len));
1182 
1183 	switch (resp) {
1184 	case UTOPPY_RESP_READDIR_DATA:
1185 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1186 		    "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev)));
1187 
1188 		UTOPPY_OUT_INIT(sc);
1189 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1190 		    UTOPPY_LONG_TIMEOUT);
1191 		if (err) {
1192 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1193 			    "utoppy_send_packet(ACK) returned %d\n",
1194 			    device_xname(sc->sc_dev), err));
1195 			utoppy_cancel(sc);
1196 			return (err);
1197 		}
1198 		sc->sc_state = UTOPPY_STATE_READDIR;
1199 		sc->sc_in_offset = 0;
1200 		break;
1201 
1202 	case UTOPPY_RESP_READDIR_END:
1203 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1204 		    "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev)));
1205 
1206 		UTOPPY_OUT_INIT(sc);
1207 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1208 		sc->sc_state = UTOPPY_STATE_IDLE;
1209 		sc->sc_in_len = 0;
1210 		break;
1211 
1212 	default:
1213 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1214 		    "bad response: 0x%x\n", device_xname(sc->sc_dev), resp));
1215 		sc->sc_state = UTOPPY_STATE_IDLE;
1216 		sc->sc_in_len = 0;
1217 		return (EIO);
1218 	}
1219 
1220 	return (0);
1221 }
1222 
1223 static size_t
1224 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud)
1225 {
1226 	uint8_t ftype;
1227 
1228 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left"
1229 	    " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len));
1230 
1231 	if (utoppy_timestamp_decode(sc, &ud->ud_mtime) ||
1232 	    utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) ||
1233 	    utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) ||
1234 	    utoppy_get_32(sc, &ud->ud_attributes)) {
1235 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no "
1236 		    "more to decode\n", device_xname(sc->sc_dev)));
1237 		return (0);
1238 	}
1239 
1240 	switch (ftype) {
1241 	case UTOPPY_FTYPE_DIR:
1242 		ud->ud_type = UTOPPY_DIRENT_DIRECTORY;
1243 		break;
1244 	case UTOPPY_FTYPE_FILE:
1245 		ud->ud_type = UTOPPY_DIRENT_FILE;
1246 		break;
1247 	default:
1248 		ud->ud_type = UTOPPY_DIRENT_UNKNOWN;
1249 		break;
1250 	}
1251 
1252 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', "
1253 	    "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev),
1254 	    (ftype == UTOPPY_FTYPE_DIR) ? "DIR" :
1255 	    ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path,
1256 	    ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes));
1257 
1258 	return (1);
1259 }
1260 
1261 static int
1262 utoppy_readfile_next(struct utoppy_softc *sc)
1263 {
1264 	uint64_t off;
1265 	uint16_t resp;
1266 	int err;
1267 
1268 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1269 	if (err) {
1270 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1271 		    "utoppy_recv_packet() returned %d\n",
1272 		    device_xname(sc->sc_dev), err));
1273 		utoppy_cancel(sc);
1274 		return (err);
1275 	}
1276 
1277 	switch (resp) {
1278 	case UTOPPY_RESP_FILE_HEADER:
1279 		/* ACK it */
1280 		UTOPPY_OUT_INIT(sc);
1281 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1282 		    UTOPPY_LONG_TIMEOUT);
1283 		if (err) {
1284 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1285 			    "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
1286 			    device_xname(sc->sc_dev), err));
1287 			utoppy_cancel(sc);
1288 			return (err);
1289 		}
1290 
1291 		sc->sc_in_len = 0;
1292 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1293 		    "FILE_HEADER done\n", device_xname(sc->sc_dev)));
1294 		break;
1295 
1296 	case UTOPPY_RESP_FILE_DATA:
1297 		/* Already ACK'd */
1298 		if (utoppy_get_64(sc, &off)) {
1299 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1300 			    "UTOPPY_RESP_FILE_DATA did not provide offset\n",
1301 			    device_xname(sc->sc_dev)));
1302 			utoppy_cancel(sc);
1303 			return (EBADMSG);
1304 		}
1305 
1306 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1307 		    "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
1308 		    device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len));
1309 		break;
1310 
1311 	case UTOPPY_RESP_FILE_END:
1312 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1313 		    "UTOPPY_RESP_FILE_END: sending ACK\n",
1314 		    device_xname(sc->sc_dev)));
1315 		UTOPPY_OUT_INIT(sc);
1316 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1317 		/*FALLTHROUGH*/
1318 
1319 	case UTOPPY_RESP_SUCCESS:
1320 		sc->sc_state = UTOPPY_STATE_IDLE;
1321 		(void) utoppy_turbo_mode(sc, 0);
1322 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all "
1323 		    "done\n", device_xname(sc->sc_dev)));
1324 		break;
1325 
1326 	case UTOPPY_RESP_ERROR:
1327 	default:
1328 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad "
1329 		    "response code 0x%0x\n", device_xname(sc->sc_dev), resp));
1330 		utoppy_cancel(sc);
1331 		return (EIO);
1332 	}
1333 
1334 	return (0);
1335 }
1336 
1337 int
1338 utoppyopen(dev_t dev, int flag, int mode,
1339     struct lwp *l)
1340 {
1341 	struct utoppy_softc *sc;
1342 	int error = 0;
1343 
1344 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1345 	if (sc == NULL)
1346 		return ENXIO;
1347 
1348 	if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
1349 		return (ENXIO);
1350 
1351 	if (sc->sc_state != UTOPPY_STATE_CLOSED) {
1352 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n",
1353 		    device_xname(sc->sc_dev)));
1354 		return (EBUSY);
1355 	}
1356 
1357 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n",
1358 	    device_xname(sc->sc_dev)));
1359 
1360 	sc->sc_refcnt++;
1361 	sc->sc_state = UTOPPY_STATE_OPENING;
1362 	sc->sc_turbo_mode = 0;
1363 	sc->sc_out_pipe = NULL;
1364 	sc->sc_in_pipe = NULL;
1365 
1366 	if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) {
1367 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(OUT) "
1368 		    "failed\n", device_xname(sc->sc_dev)));
1369 		error = EIO;
1370 		goto done;
1371 	}
1372 
1373 	if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) {
1374 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(IN) "
1375 		    "failed\n", device_xname(sc->sc_dev)));
1376 		error = EIO;
1377 		usbd_close_pipe(sc->sc_out_pipe);
1378 		sc->sc_out_pipe = NULL;
1379 		goto done;
1380 	}
1381 
1382 	sc->sc_out_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1383 	if (sc->sc_out_data == NULL) {
1384 		error = ENOMEM;
1385 		goto error;
1386 	}
1387 
1388 	sc->sc_in_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1389 	if (sc->sc_in_data == NULL) {
1390 		free(sc->sc_out_data, M_DEVBUF);
1391 		sc->sc_out_data = NULL;
1392 		error = ENOMEM;
1393 		goto error;
1394 	}
1395 
1396 	if ((error = utoppy_cancel(sc)) != 0)
1397 		goto error;
1398 
1399 	if ((error = utoppy_check_ready(sc)) != 0) {
1400 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()"
1401 		    " returned %d\n", device_xname(sc->sc_dev), error));
1402  error:
1403 		usbd_abort_pipe(sc->sc_out_pipe);
1404 		usbd_close_pipe(sc->sc_out_pipe);
1405 		sc->sc_out_pipe = NULL;
1406 		usbd_abort_pipe(sc->sc_in_pipe);
1407 		usbd_close_pipe(sc->sc_in_pipe);
1408 		sc->sc_in_pipe = NULL;
1409 	}
1410 
1411  done:
1412 	sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE;
1413 
1414 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state "
1415 	    "'%s'\n", device_xname(sc->sc_dev), error,
1416 	    utoppy_state_string(sc->sc_state)));
1417 
1418 	if (--sc->sc_refcnt < 0)
1419 		usb_detach_wakeup(sc->sc_dev);
1420 
1421 	return (error);
1422 }
1423 
1424 int
1425 utoppyclose(dev_t dev, int flag, int mode,
1426     struct lwp *l)
1427 {
1428 	struct utoppy_softc *sc;
1429 	usbd_status err;
1430 
1431 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1432 
1433 	DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n",
1434 	    device_xname(sc->sc_dev)));
1435 
1436 	if (sc->sc_state < UTOPPY_STATE_IDLE) {
1437 		/* We are being forced to close before the open completed. */
1438 		DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly open:"
1439 		    " %s\n", device_xname(sc->sc_dev),
1440 		    utoppy_state_string(sc->sc_state)));
1441 		return (0);
1442 	}
1443 
1444 	if (sc->sc_out_data)
1445 		(void) utoppy_cancel(sc);
1446 
1447 	if (sc->sc_out_pipe != NULL) {
1448 		if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
1449 			printf("usbd_abort_pipe(OUT) returned %d\n", err);
1450 		if ((err = usbd_close_pipe(sc->sc_out_pipe)) != 0)
1451 			printf("usbd_close_pipe(OUT) returned %d\n", err);
1452 		sc->sc_out_pipe = NULL;
1453 	}
1454 
1455 	if (sc->sc_in_pipe != NULL) {
1456 		if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
1457 			printf("usbd_abort_pipe(IN) returned %d\n", err);
1458 		if ((err = usbd_close_pipe(sc->sc_in_pipe)) != 0)
1459 			printf("usbd_close_pipe(IN) returned %d\n", err);
1460 		sc->sc_in_pipe = NULL;
1461 	}
1462 
1463 	if (sc->sc_out_data) {
1464 		free(sc->sc_out_data, M_DEVBUF);
1465 		sc->sc_out_data = NULL;
1466 	}
1467 
1468 	if (sc->sc_in_data) {
1469 		free(sc->sc_in_data, M_DEVBUF);
1470 		sc->sc_in_data = NULL;
1471 	}
1472 
1473 	sc->sc_state = UTOPPY_STATE_CLOSED;
1474 
1475 	DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n",
1476 	    device_xname(sc->sc_dev)));
1477 
1478 	return (0);
1479 }
1480 
1481 int
1482 utoppyread(dev_t dev, struct uio *uio, int flags)
1483 {
1484 	struct utoppy_softc *sc;
1485 	struct utoppy_dirent ud;
1486 	size_t len;
1487 	int err;
1488 
1489 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1490 
1491 	if (sc->sc_dying)
1492 		return (EIO);
1493 
1494 	sc->sc_refcnt++;
1495 
1496 	DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n",
1497 	    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1498 
1499 	switch (sc->sc_state) {
1500 	case UTOPPY_STATE_READDIR:
1501 		err = 0;
1502 		while (err == 0 && uio->uio_resid >= sizeof(ud) &&
1503 		    sc->sc_state != UTOPPY_STATE_IDLE) {
1504 			if (utoppy_readdir_decode(sc, &ud) == 0)
1505 				err = utoppy_readdir_next(sc);
1506 			else
1507 			if ((err = uiomove(&ud, sizeof(ud), uio)) != 0)
1508 				utoppy_cancel(sc);
1509 		}
1510 		break;
1511 
1512 	case UTOPPY_STATE_READFILE:
1513 		err = 0;
1514 		while (err == 0 && uio->uio_resid > 0 &&
1515 		    sc->sc_state != UTOPPY_STATE_IDLE) {
1516 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: "
1517 			    "resid %ld, bytes_left %ld\n",
1518 			    device_xname(sc->sc_dev), (u_long)uio->uio_resid,
1519 			    (u_long)sc->sc_in_len));
1520 
1521 			if (sc->sc_in_len == 0 &&
1522 			    (err = utoppy_readfile_next(sc)) != 0) {
1523 				DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: "
1524 				    "READFILE: utoppy_readfile_next returned "
1525 				    "%d\n", device_xname(sc->sc_dev), err));
1526 				break;
1527 			}
1528 
1529 			len = min(uio->uio_resid, sc->sc_in_len);
1530 			if (len) {
1531 				err = uiomove(UTOPPY_IN_DATA(sc), len, uio);
1532 				if (err == 0) {
1533 					sc->sc_in_offset += len;
1534 					sc->sc_in_len -= len;
1535 				}
1536 			}
1537 		}
1538 		break;
1539 
1540 	case UTOPPY_STATE_IDLE:
1541 		err = 0;
1542 		break;
1543 
1544 	case UTOPPY_STATE_WRITEFILE:
1545 		err = EBUSY;
1546 		break;
1547 
1548 	default:
1549 		err = EIO;
1550 		break;
1551 	}
1552 
1553 	DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n",
1554 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1555 
1556 	if (--sc->sc_refcnt < 0)
1557 		usb_detach_wakeup(sc->sc_dev);
1558 
1559 	return (err);
1560 }
1561 
1562 int
1563 utoppywrite(dev_t dev, struct uio *uio, int flags)
1564 {
1565 	struct utoppy_softc *sc;
1566 	uint16_t resp;
1567 	size_t len;
1568 	int err;
1569 
1570 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1571 
1572 	if (sc->sc_dying)
1573 		return (EIO);
1574 
1575 	switch(sc->sc_state) {
1576 	case UTOPPY_STATE_WRITEFILE:
1577 		break;
1578 
1579 	case UTOPPY_STATE_IDLE:
1580 		return (0);
1581 
1582 	default:
1583 		return (EIO);
1584 	}
1585 
1586 	sc->sc_refcnt++;
1587 	err = 0;
1588 
1589 	DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid %ld, "
1590 	    "wr_size %lld, wr_offset %lld\n", device_xname(sc->sc_dev),
1591 	    (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset));
1592 
1593 	while (sc->sc_state == UTOPPY_STATE_WRITEFILE &&
1594 	    (len = min(uio->uio_resid, sc->sc_wr_size)) != 0) {
1595 
1596 		len = min(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE +
1597 		    sizeof(uint64_t) + 3));
1598 
1599 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n",
1600 		    device_xname(sc->sc_dev), (u_long)len));
1601 
1602 		UTOPPY_OUT_INIT(sc);
1603 		utoppy_add_64(sc, sc->sc_wr_offset);
1604 
1605 		err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio);
1606 		if (err) {
1607 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove() "
1608 			    "returned %d\n", device_xname(sc->sc_dev), err));
1609 			break;
1610 		}
1611 
1612 		utoppy_advance_ptr(sc->sc_out_data, len);
1613 
1614 		err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA,
1615 		    UTOPPY_LONG_TIMEOUT, &resp);
1616 		if (err) {
1617 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1618 			    "utoppy_command(UTOPPY_RESP_FILE_DATA) "
1619 			    "returned %d\n", device_xname(sc->sc_dev), err));
1620 			break;
1621 		}
1622 		if (resp != UTOPPY_RESP_SUCCESS) {
1623 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1624 			    "utoppy_command(UTOPPY_RESP_FILE_DATA) returned "
1625 			    "bad response 0x%x\n", device_xname(sc->sc_dev),
1626 			    resp));
1627 			utoppy_cancel(sc);
1628 			err = EIO;
1629 			break;
1630 		}
1631 
1632 		sc->sc_wr_offset += len;
1633 		sc->sc_wr_size -= len;
1634 	}
1635 
1636 	DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid %ld,"
1637 	    " wr_size %lld, wr_offset %lld, err %d\n", device_xname(sc->sc_dev),
1638 	    (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset, err));
1639 
1640 	if (err == 0 && sc->sc_wr_size == 0) {
1641 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending "
1642 		    "FILE_END...\n", device_xname(sc->sc_dev)));
1643 		UTOPPY_OUT_INIT(sc);
1644 		err = utoppy_command(sc, UTOPPY_RESP_FILE_END,
1645 		    UTOPPY_LONG_TIMEOUT, &resp);
1646 		if (err) {
1647 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1648 			    "utoppy_command(UTOPPY_RESP_FILE_END) returned "
1649 			    "%d\n", device_xname(sc->sc_dev), err));
1650 
1651 			utoppy_cancel(sc);
1652 		}
1653 
1654 		sc->sc_state = UTOPPY_STATE_IDLE;
1655 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n",
1656 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1657 	}
1658 
1659 	if (--sc->sc_refcnt < 0)
1660 		usb_detach_wakeup(sc->sc_dev);
1661 
1662 	return (err);
1663 }
1664 
1665 int
1666 utoppyioctl(dev_t dev, u_long cmd, void *data, int flag,
1667     struct lwp *l)
1668 {
1669 	struct utoppy_softc *sc;
1670 	struct utoppy_rename *ur;
1671 	struct utoppy_readfile *urf;
1672 	struct utoppy_writefile *uw;
1673 	char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp;
1674 	uint16_t resp;
1675 	int err;
1676 
1677 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1678 
1679 	if (sc->sc_dying)
1680 		return (EIO);
1681 
1682 	DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1683 	    device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state)));
1684 
1685 	if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) {
1686 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n",
1687 		    device_xname(sc->sc_dev)));
1688 		return (EBUSY);
1689 	}
1690 
1691 	sc->sc_refcnt++;
1692 
1693 	switch (cmd) {
1694 	case UTOPPYIOTURBO:
1695 		err = 0;
1696 		sc->sc_turbo_mode = *((int *)data) ? 1 : 0;
1697 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: "
1698 		    "%s\n", device_xname(sc->sc_dev), sc->sc_turbo_mode ? "On" :
1699 		    "Off"));
1700 		break;
1701 
1702 	case UTOPPYIOCANCEL:
1703 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
1704 		    device_xname(sc->sc_dev)));
1705 		err = utoppy_cancel(sc);
1706 		break;
1707 
1708 	case UTOPPYIOREBOOT:
1709 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1710 		    device_xname(sc->sc_dev)));
1711 		UTOPPY_OUT_INIT(sc);
1712 		err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT,
1713 		    &resp);
1714 		if (err)
1715 			break;
1716 
1717 		if (resp != UTOPPY_RESP_SUCCESS)
1718 			err = EIO;
1719 		break;
1720 
1721 	case UTOPPYIOSTATS:
1722 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
1723 		    device_xname(sc->sc_dev)));
1724 		err = utoppy_stats(sc, (struct utoppy_stats *)data);
1725 		break;
1726 
1727 	case UTOPPYIORENAME:
1728 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n",
1729 		    device_xname(sc->sc_dev)));
1730 		ur = (struct utoppy_rename *)data;
1731 		UTOPPY_OUT_INIT(sc);
1732 
1733 		if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0)
1734 			break;
1735 		if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0)
1736 			break;
1737 
1738 		err = utoppy_command(sc, UTOPPY_CMD_RENAME, UTOPPY_LONG_TIMEOUT,
1739 		    &resp);
1740 		if (err)
1741 			break;
1742 
1743 		if (resp != UTOPPY_RESP_SUCCESS)
1744 			err = EIO;
1745 		break;
1746 
1747 	case UTOPPYIOMKDIR:
1748 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
1749 		    device_xname(sc->sc_dev)));
1750 		UTOPPY_OUT_INIT(sc);
1751 		err = utoppy_add_path(sc, *((const char **)data), 1);
1752 		if (err)
1753 			break;
1754 
1755 		err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT,
1756 		    &resp);
1757 		if (err)
1758 			break;
1759 
1760 		if (resp != UTOPPY_RESP_SUCCESS)
1761 			err = EIO;
1762 		break;
1763 
1764 	case UTOPPYIODELETE:
1765 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n",
1766 		    device_xname(sc->sc_dev)));
1767 		UTOPPY_OUT_INIT(sc);
1768 		err = utoppy_add_path(sc, *((const char **)data), 0);
1769 		if (err)
1770 			break;
1771 
1772 		err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT,
1773 		    &resp);
1774 		if (err)
1775 			break;
1776 
1777 		if (resp != UTOPPY_RESP_SUCCESS)
1778 			err = EIO;
1779 		break;
1780 
1781 	case UTOPPYIOREADDIR:
1782 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
1783 		    device_xname(sc->sc_dev)));
1784 		UTOPPY_OUT_INIT(sc);
1785 		err = utoppy_add_path(sc, *((const char **)data), 0);
1786 		if (err) {
1787 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1788 			    "utoppy_add_path() returned %d\n",
1789 			    device_xname(sc->sc_dev), err));
1790 			break;
1791 		}
1792 
1793 		err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR,
1794 		    UTOPPY_LONG_TIMEOUT);
1795 		if (err != 0) {
1796 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1797 			    "UTOPPY_CMD_READDIR returned %d\n",
1798 			    device_xname(sc->sc_dev), err));
1799 			break;
1800 		}
1801 
1802 		err = utoppy_readdir_next(sc);
1803 		if (err) {
1804 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1805 			    "utoppy_readdir_next() returned %d\n",
1806 			    device_xname(sc->sc_dev), err));
1807 		}
1808 		break;
1809 
1810 	case UTOPPYIOREADFILE:
1811 		urf = (struct utoppy_readfile *)data;
1812 
1813 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE "
1814 		    "%s, offset %lld\n", device_xname(sc->sc_dev), urf->ur_path,
1815 		    urf->ur_offset));
1816 
1817 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1818 			break;
1819 
1820 		UTOPPY_OUT_INIT(sc);
1821 		utoppy_add_8(sc, UTOPPY_FILE_READ);
1822 
1823 		if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0)
1824 			break;
1825 
1826 		utoppy_add_64(sc, urf->ur_offset);
1827 
1828 		sc->sc_state = UTOPPY_STATE_READFILE;
1829 		sc->sc_in_offset = 0;
1830 
1831 		err = utoppy_send_packet(sc, UTOPPY_CMD_FILE,
1832 		    UTOPPY_LONG_TIMEOUT);
1833 		if (err == 0)
1834 			err = utoppy_readfile_next(sc);
1835 		break;
1836 
1837 	case UTOPPYIOWRITEFILE:
1838 		uw = (struct utoppy_writefile *)data;
1839 
1840 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
1841 		    "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev),
1842 		    uw->uw_path, uw->uw_size, uw->uw_offset));
1843 
1844 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1845 			break;
1846 
1847 		UTOPPY_OUT_INIT(sc);
1848 		utoppy_add_8(sc, UTOPPY_FILE_WRITE);
1849 		uwfp = utoppy_current_ptr(sc->sc_out_data);
1850 
1851 		if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) {
1852 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path() "
1853 			    "returned %d\n", device_xname(sc->sc_dev), err));
1854 			break;
1855 		}
1856 
1857 		strncpy(uwf, &uwfp[2], sizeof(uwf));
1858 		utoppy_add_64(sc, uw->uw_offset);
1859 
1860 		err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT,
1861 		    &resp);
1862 		if (err) {
1863 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1864 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
1865 			    "%d\n", device_xname(sc->sc_dev), err));
1866 			break;
1867 		}
1868 		if (resp != UTOPPY_RESP_SUCCESS) {
1869 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1870 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
1871 			    "bad response 0x%x\n", device_xname(sc->sc_dev),
1872 			    resp));
1873 			err = EIO;
1874 			break;
1875 		}
1876 
1877 		UTOPPY_OUT_INIT(sc);
1878 		utoppy_timestamp_encode(sc, uw->uw_mtime);
1879 		utoppy_add_8(sc, UTOPPY_FTYPE_FILE);
1880 		utoppy_add_64(sc, uw->uw_size);
1881 		utoppy_add_string(sc, uwf, sizeof(uwf));
1882 		utoppy_add_32(sc, 0);
1883 
1884 		err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER,
1885 		    UTOPPY_LONG_TIMEOUT, &resp);
1886 		if (err) {
1887 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1888 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1889 			    "returned %d\n", device_xname(sc->sc_dev), err));
1890 			break;
1891 		}
1892 		if (resp != UTOPPY_RESP_SUCCESS) {
1893 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1894 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1895 			    "returned bad response 0x%x\n",
1896 			    device_xname(sc->sc_dev), resp));
1897 			err = EIO;
1898 			break;
1899 		}
1900 
1901 		sc->sc_wr_offset = uw->uw_offset;
1902 		sc->sc_wr_size = uw->uw_size;
1903 		sc->sc_state = UTOPPY_STATE_WRITEFILE;
1904 
1905 		DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to "
1906 		    "%s. wr_offset %lld, wr_size %lld\n",
1907 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state),
1908 		    sc->sc_wr_offset, sc->sc_wr_size));
1909 		break;
1910 
1911 	default:
1912 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n",
1913 		    device_xname(sc->sc_dev)));
1914 		err = ENODEV;
1915 		break;
1916 	}
1917 
1918 	DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
1919 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1920 
1921 	if (err)
1922 		utoppy_cancel(sc);
1923 
1924 	if (--sc->sc_refcnt < 0)
1925 		usb_detach_wakeup(sc->sc_dev);
1926 
1927 	return (err);
1928 }
1929