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