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