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