xref: /netbsd-src/sys/dev/usb/utoppy.c (revision a4ddc2c8fb9af816efe3b1c375a5530aef0e89e9)
1 /*	$NetBSD: utoppy.c,v 1.21 2012/10/27 17:18:38 chs 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.21 2012/10/27 17:18:38 chs 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 /*
516  * Very much like usbd_bulk_transfer(), except don't catch signals
517  */
518 static void
519 utoppy_bulk_transfer_cb(usbd_xfer_handle xfer,
520     usbd_private_handle priv,
521     usbd_status status)
522 {
523 
524 	if (xfer->pipe->device->bus->lock)
525 		cv_broadcast(&xfer->cv);
526 	else
527 		wakeup(xfer);
528 }
529 
530 static usbd_status
531 utoppy_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
532     u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size,
533     const char *lbl)
534 {
535 	usbd_status err;
536 	int s, error;
537 
538 	usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
539 	    utoppy_bulk_transfer_cb);
540 	usbd_lock_pipe(pipe);	/* don't want callback until tsleep() */
541 	err = usbd_transfer(xfer);
542 	if (err != USBD_IN_PROGRESS) {
543 		usbd_unlock_pipe(pipe);
544 		return (err);
545 	}
546 	if (pipe->device->bus->lock)
547 		error = cv_wait_sig(&xfer->cv, pipe->device->bus->lock);
548 	else
549 		error = tsleep((void *)xfer, PZERO, lbl, 0);
550 	usbd_unlock_pipe(pipe);
551 	if (error) {
552 		usbd_abort_pipe(pipe);
553 		return (USBD_INTERRUPTED);
554 	}
555 	usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
556 	return (err);
557 }
558 
559 static int
560 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout)
561 {
562 	struct utoppy_header *h;
563 	usbd_status err;
564 	uint32_t len;
565 	uint16_t dlen, crc;
566 	uint8_t *data, *e, t1, t2;
567 
568 	h = sc->sc_out_data;
569 
570 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, "
571 	    "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len));
572 
573 	dlen = h->h_len;
574 	len = dlen + UTOPPY_HEADER_SIZE;
575 
576 	if (len & 1)
577 		len++;
578 	if ((len % 64) == 0)
579 		len += 2;
580 
581 	if (len >= UTOPPY_BSIZE) {
582 		DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
583 		    "packet too big (%d)\n", device_xname(sc->sc_dev), (int)len));
584 		return (EINVAL);
585 	}
586 
587 	h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE);
588 	h->h_cmd2 = 0;
589 	h->h_cmd = htole16(cmd);
590 
591 	/* The command word is part of the CRC */
592 	crc = UTOPPY_CRC16(0,   0);
593 	crc = UTOPPY_CRC16(crc, 0);
594 	crc = UTOPPY_CRC16(crc, cmd >> 8);
595 	crc = UTOPPY_CRC16(crc, cmd);
596 
597 	/*
598 	 * If there is data following the header, calculate the CRC and
599 	 * byte-swap as we go.
600 	 */
601 	if (dlen) {
602 		data = h->h_data;
603 		e = data + (dlen & ~1);
604 
605 		do {
606 			t1 = data[0];
607 			t2 = data[1];
608 			crc = UTOPPY_CRC16(crc, t1);
609 			crc = UTOPPY_CRC16(crc, t2);
610 			*data++ = t2;
611 			*data++ = t1;
612 		} while (data < e);
613 
614 		if (dlen & 1) {
615 			t1 = data[0];
616 			crc = UTOPPY_CRC16(crc, t1);
617 			data[1] = t1;
618 		}
619 	}
620 
621 	h->h_crc = htole16(crc);
622 	data = sc->sc_out_data;
623 
624 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len "
625 	    "%d...\n", device_xname(sc->sc_dev), (int)len));
626 	DDUMP_PACKET(data, len);
627 
628 	do {
629 		uint32_t thislen;
630 
631 		thislen = min(len, UTOPPY_FRAG_SIZE);
632 
633 		memcpy(sc->sc_out_buf, data, thislen);
634 
635 		err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe,
636 		    USBD_NO_COPY, timeout, sc->sc_out_buf, &thislen,
637 		    "utoppytx");
638 
639 		if (thislen != min(len, UTOPPY_FRAG_SIZE)) {
640 			DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: "
641 			    "utoppy_send_packet: sent %ld, err %d\n",
642 			    device_xname(sc->sc_dev), (u_long)thislen, err));
643 		}
644 
645 		if (err == 0) {
646 			len -= thislen;
647 			data += thislen;
648 		}
649 	} while (err == 0 && len);
650 
651 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
652 	    "usbd_bulk_transfer() returned %d.\n", device_xname(sc->sc_dev),err));
653 
654 	return (err ? utoppy_usbd_status2errno(err) : 0);
655 }
656 
657 static int
658 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout)
659 {
660 	struct utoppy_header *h;
661 	usbd_status err;
662 	uint32_t len, thislen, requested, bytesleft;
663 	uint16_t crc;
664 	uint8_t *data, *e, t1, t2;
665 
666 	data = sc->sc_in_data;
667 	len = 0;
668 	bytesleft = UTOPPY_BSIZE;
669 
670 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n",
671 	    device_xname(sc->sc_dev)));
672 
673 	do {
674 		requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE);
675 
676 		err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe,
677 		    USBD_NO_COPY | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf,
678 		    &thislen, "utoppyrx");
679 
680 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
681 		    "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
682 		    device_xname(sc->sc_dev), err, (u_int)thislen, data));
683 
684 		if (err == 0) {
685 			memcpy(data, sc->sc_in_buf, thislen);
686 			DDUMP_PACKET(data, thislen);
687 			len += thislen;
688 			bytesleft -= thislen;
689 			data += thislen;
690 		}
691 	} while (err == 0 && bytesleft && thislen == requested);
692 
693 	if (err)
694 		return (utoppy_usbd_status2errno(err));
695 
696 	h = sc->sc_in_data;
697 
698 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d "
699 	    "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h));
700 	DDUMP_PACKET(h, len);
701 
702 	if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) {
703 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad "
704 		    " length (len %d, h_len %d)\n", device_xname(sc->sc_dev),
705 		    (int)len, le16toh(h->h_len)));
706 		return (EIO);
707 	}
708 
709 	len = h->h_len = le16toh(h->h_len);
710 	h->h_crc = le16toh(h->h_crc);
711 	*respp = h->h_cmd = le16toh(h->h_cmd);
712 	h->h_cmd2 = le16toh(h->h_cmd2);
713 
714 	/*
715 	 * To maximise data throughput when transferring files, acknowledge
716 	 * data blocks as soon as we receive them. If we detect an error
717 	 * later on, we can always cancel.
718 	 */
719 	if (*respp == UTOPPY_RESP_FILE_DATA) {
720 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
721 		    "ACKing file data\n", device_xname(sc->sc_dev)));
722 
723 		UTOPPY_OUT_INIT(sc);
724 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
725 		    UTOPPY_SHORT_TIMEOUT);
726 		if (err) {
727 			DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: "
728 			    "utoppy_recv_packet: failed to ACK file data: %d\n",
729 			    device_xname(sc->sc_dev), err));
730 			return (err);
731 		}
732 	}
733 
734 	/* The command word is part of the CRC */
735 	crc = UTOPPY_CRC16(0,   h->h_cmd2 >> 8);
736 	crc = UTOPPY_CRC16(crc, h->h_cmd2);
737 	crc = UTOPPY_CRC16(crc, h->h_cmd >> 8);
738 	crc = UTOPPY_CRC16(crc, h->h_cmd);
739 
740 	/*
741 	 * Extract any payload, byte-swapping and calculating the CRC16
742 	 * as we go.
743 	 */
744 	if (len > UTOPPY_HEADER_SIZE) {
745 		data = h->h_data;
746 		e = data + ((len & ~1) - UTOPPY_HEADER_SIZE);
747 
748 		while (data < e) {
749 			t1 = data[0];
750 			t2 = data[1];
751 			crc = UTOPPY_CRC16(crc, t2);
752 			crc = UTOPPY_CRC16(crc, t1);
753 			*data++ = t2;
754 			*data++ = t1;
755 		}
756 
757 		if (len & 1) {
758 			t1 = data[1];
759 			crc = UTOPPY_CRC16(crc, t1);
760 			*data = t1;
761 		}
762 	}
763 
764 	sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE;
765 	sc->sc_in_offset = 0;
766 
767 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, "
768 	    "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev),
769 	    (int)len, crc, h->h_crc));
770 	DDUMP_PACKET(h, len);
771 
772 	return ((crc == h->h_crc) ? 0 : EBADMSG);
773 }
774 
775 static __inline void *
776 utoppy_current_ptr(void *b)
777 {
778 	struct utoppy_header *h = b;
779 
780 	return (&h->h_data[h->h_len]);
781 }
782 
783 static __inline void
784 utoppy_advance_ptr(void *b, size_t len)
785 {
786 	struct utoppy_header *h = b;
787 
788 	h->h_len += len;
789 }
790 
791 static __inline void
792 utoppy_add_8(struct utoppy_softc *sc, uint8_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 = v;
799 	utoppy_advance_ptr(h, sizeof(v));
800 }
801 
802 static __inline void
803 utoppy_add_16(struct utoppy_softc *sc, uint16_t v)
804 {
805 	struct utoppy_header *h = sc->sc_out_data;
806 	uint8_t *p;
807 
808 	p = utoppy_current_ptr(h);
809 	*p++ = (uint8_t)(v >> 8);
810 	*p = (uint8_t)v;
811 	utoppy_advance_ptr(h, sizeof(v));
812 }
813 
814 static __inline void
815 utoppy_add_32(struct utoppy_softc *sc, uint32_t v)
816 {
817 	struct utoppy_header *h = sc->sc_out_data;
818 	uint8_t *p;
819 
820 	p = utoppy_current_ptr(h);
821 	*p++ = (uint8_t)(v >> 24);
822 	*p++ = (uint8_t)(v >> 16);
823 	*p++ = (uint8_t)(v >> 8);
824 	*p = (uint8_t)v;
825 	utoppy_advance_ptr(h, sizeof(v));
826 }
827 
828 static __inline void
829 utoppy_add_64(struct utoppy_softc *sc, uint64_t v)
830 {
831 	struct utoppy_header *h = sc->sc_out_data;
832 	uint8_t *p;
833 
834 	p = utoppy_current_ptr(h);
835 	*p++ = (uint8_t)(v >> 56);
836 	*p++ = (uint8_t)(v >> 48);
837 	*p++ = (uint8_t)(v >> 40);
838 	*p++ = (uint8_t)(v >> 32);
839 	*p++ = (uint8_t)(v >> 24);
840 	*p++ = (uint8_t)(v >> 16);
841 	*p++ = (uint8_t)(v >> 8);
842 	*p = (uint8_t)v;
843 	utoppy_advance_ptr(h, sizeof(v));
844 }
845 
846 static __inline void
847 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len)
848 {
849 	struct utoppy_header *h = sc->sc_out_data;
850 	char *p;
851 
852 	p = utoppy_current_ptr(h);
853 	memset(p, 0, len);
854 	strncpy(p, str, len);
855 	utoppy_advance_ptr(h, len);
856 }
857 
858 static int
859 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen)
860 {
861 	struct utoppy_header *h = sc->sc_out_data;
862 	uint8_t *p, *str, *s;
863 	size_t len;
864 	int err;
865 
866 	p = utoppy_current_ptr(h);
867 
868 	str = putlen ? (p + sizeof(uint16_t)) : p;
869 
870 	err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len);
871 
872 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n",
873 	    err, (int)len));
874 
875 	if (err)
876 		return (err);
877 
878 	if (len < 2)
879 		return (EINVAL);
880 
881 	/*
882 	 * copyinstr(9) has already copied the terminating NUL character,
883 	 * but we append another one in case we have to pad the length
884 	 * later on.
885 	 */
886 	str[len] = '\0';
887 
888 	/*
889 	 * The Toppy uses backslash as the directory separator, so convert
890 	 * all forward slashes.
891 	 */
892 	for (s = &str[len - 2]; s >= str; s--)
893 		if (*s == '/')
894 			*s = '\\';
895 
896 	if ((len + h->h_len) & 1)
897 		len++;
898 
899 	if (putlen)
900 		utoppy_add_16(sc, len);
901 
902 	utoppy_advance_ptr(h, len);
903 
904 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n",
905 	    (u_int)len));
906 
907 	return (0);
908 }
909 
910 static __inline int
911 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp)
912 {
913 	uint8_t *p;
914 
915 	if (sc->sc_in_len < sizeof(*vp))
916 		return (1);
917 
918 	p = UTOPPY_IN_DATA(sc);
919 	*vp = *p;
920 	sc->sc_in_offset += sizeof(*vp);
921 	sc->sc_in_len -= sizeof(*vp);
922 	return (0);
923 }
924 
925 static __inline int
926 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp)
927 {
928 	uint16_t v;
929 	uint8_t *p;
930 
931 	if (sc->sc_in_len < sizeof(v))
932 		return (1);
933 
934 	p = UTOPPY_IN_DATA(sc);
935 	v = *p++;
936 	v = (v << 8) | *p;
937 	*vp = v;
938 	sc->sc_in_offset += sizeof(v);
939 	sc->sc_in_len -= sizeof(v);
940 	return (0);
941 }
942 
943 static __inline int
944 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp)
945 {
946 	uint32_t v;
947 	uint8_t *p;
948 
949 	if (sc->sc_in_len < sizeof(v))
950 		return (1);
951 
952 	p = UTOPPY_IN_DATA(sc);
953 	v = *p++;
954 	v = (v << 8) | *p++;
955 	v = (v << 8) | *p++;
956 	v = (v << 8) | *p;
957 	*vp = v;
958 	sc->sc_in_offset += sizeof(v);
959 	sc->sc_in_len -= sizeof(v);
960 	return (0);
961 }
962 
963 static __inline int
964 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp)
965 {
966 	uint64_t v;
967 	uint8_t *p;
968 
969 	if (sc->sc_in_len < sizeof(v))
970 		return (1);
971 
972 	p = UTOPPY_IN_DATA(sc);
973 	v = *p++;
974 	v = (v << 8) | *p++;
975 	v = (v << 8) | *p++;
976 	v = (v << 8) | *p++;
977 	v = (v << 8) | *p++;
978 	v = (v << 8) | *p++;
979 	v = (v << 8) | *p++;
980 	v = (v << 8) | *p;
981 	*vp = v;
982 	sc->sc_in_offset += sizeof(v);
983 	sc->sc_in_len -= sizeof(v);
984 	return (0);
985 }
986 
987 static __inline int
988 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len)
989 {
990 	char *p;
991 
992 	if (sc->sc_in_len < len)
993 		return (1);
994 
995 	memset(str, 0, len);
996 	p = UTOPPY_IN_DATA(sc);
997 	strncpy(str, p, len);
998 	sc->sc_in_offset += len;
999 	sc->sc_in_len -= len;
1000 	return (0);
1001 }
1002 
1003 static int
1004 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout,
1005     uint16_t *presp)
1006 {
1007 	int err;
1008 
1009 	err = utoppy_send_packet(sc, cmd, timeout);
1010 	if (err)
1011 		return (err);
1012 
1013 	err = utoppy_recv_packet(sc, presp, timeout);
1014 	if (err == EBADMSG) {
1015 		UTOPPY_OUT_INIT(sc);
1016 		utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout);
1017 	}
1018 
1019 	return (err);
1020 }
1021 
1022 static int
1023 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp)
1024 {
1025 	uint16_t mjd;
1026 	uint8_t hour, minute, sec;
1027 	uint32_t rv;
1028 
1029 	if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) ||
1030 	    utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec))
1031 		return (1);
1032 
1033 	if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){
1034 		*tp = 0;
1035 		return (0);
1036 	}
1037 
1038 	rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd;
1039 
1040 	/* Calculate seconds since 1970 */
1041 	rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24;
1042 
1043 	/* Add in the hours, minutes, and seconds */
1044 	rv += (uint32_t)hour * 60 * 60;
1045 	rv += (uint32_t)minute * 60;
1046 	rv += sec;
1047 	*tp = (time_t)rv;
1048 
1049 	return (0);
1050 }
1051 
1052 static void
1053 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t)
1054 {
1055 	u_int mjd, hour, minute;
1056 
1057 	mjd = t / (60 * 60 * 24);
1058 	t -= mjd * 60 * 60 * 24;
1059 
1060 	hour = t / (60 * 60);
1061 	t -= hour * 60 * 60;
1062 
1063 	minute = t / 60;
1064 	t -= minute * 60;
1065 
1066 	utoppy_add_16(sc, mjd + UTOPPY_MJD_1970);
1067 	utoppy_add_8(sc, hour);
1068 	utoppy_add_8(sc, minute);
1069 	utoppy_add_8(sc, t);
1070 }
1071 
1072 static int
1073 utoppy_turbo_mode(struct utoppy_softc *sc, int state)
1074 {
1075 	uint16_t r;
1076 	int err;
1077 
1078 	UTOPPY_OUT_INIT(sc);
1079 	utoppy_add_32(sc, state);
1080 
1081 	err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r);
1082 	if (err)
1083 		return (err);
1084 
1085 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1086 }
1087 
1088 static int
1089 utoppy_check_ready(struct utoppy_softc *sc)
1090 {
1091 	uint16_t r;
1092 	int err;
1093 
1094 	UTOPPY_OUT_INIT(sc);
1095 
1096 	err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r);
1097 	if (err)
1098 		return (err);
1099 
1100 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1101 }
1102 
1103 static int
1104 utoppy_cancel(struct utoppy_softc *sc)
1105 {
1106 	uint16_t r;
1107 	int err, i;
1108 
1109 	/*
1110 	 * Issue the cancel command serveral times. the Toppy doesn't
1111 	 * always respond to the first.
1112 	 */
1113 	for (i = 0; i < 3; i++) {
1114 		UTOPPY_OUT_INIT(sc);
1115 		err = utoppy_command(sc, UTOPPY_CMD_CANCEL,
1116 		    UTOPPY_SHORT_TIMEOUT, &r);
1117 		if (err == 0 && r == UTOPPY_RESP_SUCCESS)
1118 			break;
1119 		err = ETIMEDOUT;
1120 	}
1121 
1122 	if (err)
1123 		return (err);
1124 
1125 	/*
1126 	 * Make sure turbo mode is off, otherwise the Toppy will not
1127 	 * respond to remote control input.
1128 	 */
1129 	(void) utoppy_turbo_mode(sc, 0);
1130 
1131 	sc->sc_state = UTOPPY_STATE_IDLE;
1132 	return (0);
1133 }
1134 
1135 static int
1136 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us)
1137 {
1138 	uint32_t hsize, hfree;
1139 	uint16_t r;
1140 	int err;
1141 
1142 	UTOPPY_OUT_INIT(sc);
1143 	err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r);
1144 	if (err)
1145 		return (err);
1146 
1147 	if (r != UTOPPY_RESP_STATS_DATA)
1148 		return (EIO);
1149 
1150 	if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree))
1151 		return (EIO);
1152 
1153 	us->us_hdd_size = hsize;
1154 	us->us_hdd_size *= 1024;
1155 	us->us_hdd_free = hfree;
1156 	us->us_hdd_free *= 1024;
1157 
1158 	return (0);
1159 }
1160 
1161 static int
1162 utoppy_readdir_next(struct utoppy_softc *sc)
1163 {
1164 	uint16_t resp;
1165 	int err;
1166 
1167 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n",
1168 	    device_xname(sc->sc_dev)));
1169 
1170 	/*
1171 	 * Fetch the next READDIR response
1172 	 */
1173 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1174 	if (err) {
1175 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1176 		    "utoppy_recv_packet() returned %d\n",
1177 		    device_xname(sc->sc_dev), err));
1178 		if (err == EBADMSG) {
1179 			UTOPPY_OUT_INIT(sc);
1180 			utoppy_send_packet(sc, UTOPPY_RESP_ERROR,
1181 			    UTOPPY_LONG_TIMEOUT);
1182 		}
1183 		utoppy_cancel(sc);
1184 		return (err);
1185 	}
1186 
1187 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1188 	    "utoppy_recv_packet() returned %d, len %ld\n",
1189 	    device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len));
1190 
1191 	switch (resp) {
1192 	case UTOPPY_RESP_READDIR_DATA:
1193 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1194 		    "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev)));
1195 
1196 		UTOPPY_OUT_INIT(sc);
1197 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1198 		    UTOPPY_LONG_TIMEOUT);
1199 		if (err) {
1200 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1201 			    "utoppy_send_packet(ACK) returned %d\n",
1202 			    device_xname(sc->sc_dev), err));
1203 			utoppy_cancel(sc);
1204 			return (err);
1205 		}
1206 		sc->sc_state = UTOPPY_STATE_READDIR;
1207 		sc->sc_in_offset = 0;
1208 		break;
1209 
1210 	case UTOPPY_RESP_READDIR_END:
1211 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1212 		    "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev)));
1213 
1214 		UTOPPY_OUT_INIT(sc);
1215 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1216 		sc->sc_state = UTOPPY_STATE_IDLE;
1217 		sc->sc_in_len = 0;
1218 		break;
1219 
1220 	default:
1221 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1222 		    "bad response: 0x%x\n", device_xname(sc->sc_dev), resp));
1223 		sc->sc_state = UTOPPY_STATE_IDLE;
1224 		sc->sc_in_len = 0;
1225 		return (EIO);
1226 	}
1227 
1228 	return (0);
1229 }
1230 
1231 static size_t
1232 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud)
1233 {
1234 	uint8_t ftype;
1235 
1236 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left"
1237 	    " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len));
1238 
1239 	if (utoppy_timestamp_decode(sc, &ud->ud_mtime) ||
1240 	    utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) ||
1241 	    utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) ||
1242 	    utoppy_get_32(sc, &ud->ud_attributes)) {
1243 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no "
1244 		    "more to decode\n", device_xname(sc->sc_dev)));
1245 		return (0);
1246 	}
1247 
1248 	switch (ftype) {
1249 	case UTOPPY_FTYPE_DIR:
1250 		ud->ud_type = UTOPPY_DIRENT_DIRECTORY;
1251 		break;
1252 	case UTOPPY_FTYPE_FILE:
1253 		ud->ud_type = UTOPPY_DIRENT_FILE;
1254 		break;
1255 	default:
1256 		ud->ud_type = UTOPPY_DIRENT_UNKNOWN;
1257 		break;
1258 	}
1259 
1260 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', "
1261 	    "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev),
1262 	    (ftype == UTOPPY_FTYPE_DIR) ? "DIR" :
1263 	    ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path,
1264 	    ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes));
1265 
1266 	return (1);
1267 }
1268 
1269 static int
1270 utoppy_readfile_next(struct utoppy_softc *sc)
1271 {
1272 	uint64_t off;
1273 	uint16_t resp;
1274 	int err;
1275 
1276 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1277 	if (err) {
1278 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1279 		    "utoppy_recv_packet() returned %d\n",
1280 		    device_xname(sc->sc_dev), err));
1281 		utoppy_cancel(sc);
1282 		return (err);
1283 	}
1284 
1285 	switch (resp) {
1286 	case UTOPPY_RESP_FILE_HEADER:
1287 		/* ACK it */
1288 		UTOPPY_OUT_INIT(sc);
1289 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1290 		    UTOPPY_LONG_TIMEOUT);
1291 		if (err) {
1292 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1293 			    "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
1294 			    device_xname(sc->sc_dev), err));
1295 			utoppy_cancel(sc);
1296 			return (err);
1297 		}
1298 
1299 		sc->sc_in_len = 0;
1300 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1301 		    "FILE_HEADER done\n", device_xname(sc->sc_dev)));
1302 		break;
1303 
1304 	case UTOPPY_RESP_FILE_DATA:
1305 		/* Already ACK'd */
1306 		if (utoppy_get_64(sc, &off)) {
1307 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1308 			    "UTOPPY_RESP_FILE_DATA did not provide offset\n",
1309 			    device_xname(sc->sc_dev)));
1310 			utoppy_cancel(sc);
1311 			return (EBADMSG);
1312 		}
1313 
1314 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1315 		    "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
1316 		    device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len));
1317 		break;
1318 
1319 	case UTOPPY_RESP_FILE_END:
1320 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1321 		    "UTOPPY_RESP_FILE_END: sending ACK\n",
1322 		    device_xname(sc->sc_dev)));
1323 		UTOPPY_OUT_INIT(sc);
1324 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1325 		/*FALLTHROUGH*/
1326 
1327 	case UTOPPY_RESP_SUCCESS:
1328 		sc->sc_state = UTOPPY_STATE_IDLE;
1329 		(void) utoppy_turbo_mode(sc, 0);
1330 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all "
1331 		    "done\n", device_xname(sc->sc_dev)));
1332 		break;
1333 
1334 	case UTOPPY_RESP_ERROR:
1335 	default:
1336 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad "
1337 		    "response code 0x%0x\n", device_xname(sc->sc_dev), resp));
1338 		utoppy_cancel(sc);
1339 		return (EIO);
1340 	}
1341 
1342 	return (0);
1343 }
1344 
1345 int
1346 utoppyopen(dev_t dev, int flag, int mode,
1347     struct lwp *l)
1348 {
1349 	struct utoppy_softc *sc;
1350 	int error = 0;
1351 
1352 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1353 	if (sc == NULL)
1354 		return ENXIO;
1355 
1356 	if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
1357 		return (ENXIO);
1358 
1359 	if (sc->sc_state != UTOPPY_STATE_CLOSED) {
1360 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n",
1361 		    device_xname(sc->sc_dev)));
1362 		return (EBUSY);
1363 	}
1364 
1365 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n",
1366 	    device_xname(sc->sc_dev)));
1367 
1368 	sc->sc_refcnt++;
1369 	sc->sc_state = UTOPPY_STATE_OPENING;
1370 	sc->sc_turbo_mode = 0;
1371 	sc->sc_out_pipe = NULL;
1372 	sc->sc_in_pipe = NULL;
1373 
1374 	if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) {
1375 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(OUT) "
1376 		    "failed\n", device_xname(sc->sc_dev)));
1377 		error = EIO;
1378 		goto done;
1379 	}
1380 
1381 	if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) {
1382 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(IN) "
1383 		    "failed\n", device_xname(sc->sc_dev)));
1384 		error = EIO;
1385 		usbd_close_pipe(sc->sc_out_pipe);
1386 		sc->sc_out_pipe = NULL;
1387 		goto done;
1388 	}
1389 
1390 	sc->sc_out_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1391 	if (sc->sc_out_data == NULL) {
1392 		error = ENOMEM;
1393 		goto error;
1394 	}
1395 
1396 	sc->sc_in_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1397 	if (sc->sc_in_data == NULL) {
1398 		free(sc->sc_out_data, M_DEVBUF);
1399 		sc->sc_out_data = NULL;
1400 		error = ENOMEM;
1401 		goto error;
1402 	}
1403 
1404 	if ((error = utoppy_cancel(sc)) != 0)
1405 		goto error;
1406 
1407 	if ((error = utoppy_check_ready(sc)) != 0) {
1408 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()"
1409 		    " returned %d\n", device_xname(sc->sc_dev), error));
1410  error:
1411 		usbd_abort_pipe(sc->sc_out_pipe);
1412 		usbd_close_pipe(sc->sc_out_pipe);
1413 		sc->sc_out_pipe = NULL;
1414 		usbd_abort_pipe(sc->sc_in_pipe);
1415 		usbd_close_pipe(sc->sc_in_pipe);
1416 		sc->sc_in_pipe = NULL;
1417 	}
1418 
1419  done:
1420 	sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE;
1421 
1422 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state "
1423 	    "'%s'\n", device_xname(sc->sc_dev), error,
1424 	    utoppy_state_string(sc->sc_state)));
1425 
1426 	if (--sc->sc_refcnt < 0)
1427 		usb_detach_wakeupold(sc->sc_dev);
1428 
1429 	return (error);
1430 }
1431 
1432 int
1433 utoppyclose(dev_t dev, int flag, int mode,
1434     struct lwp *l)
1435 {
1436 	struct utoppy_softc *sc;
1437 	usbd_status err;
1438 
1439 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1440 
1441 	DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n",
1442 	    device_xname(sc->sc_dev)));
1443 
1444 	if (sc->sc_state < UTOPPY_STATE_IDLE) {
1445 		/* We are being forced to close before the open completed. */
1446 		DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly open:"
1447 		    " %s\n", device_xname(sc->sc_dev),
1448 		    utoppy_state_string(sc->sc_state)));
1449 		return (0);
1450 	}
1451 
1452 	if (sc->sc_out_data)
1453 		(void) utoppy_cancel(sc);
1454 
1455 	if (sc->sc_out_pipe != NULL) {
1456 		if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
1457 			printf("usbd_abort_pipe(OUT) returned %d\n", err);
1458 		if ((err = usbd_close_pipe(sc->sc_out_pipe)) != 0)
1459 			printf("usbd_close_pipe(OUT) returned %d\n", err);
1460 		sc->sc_out_pipe = NULL;
1461 	}
1462 
1463 	if (sc->sc_in_pipe != NULL) {
1464 		if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
1465 			printf("usbd_abort_pipe(IN) returned %d\n", err);
1466 		if ((err = usbd_close_pipe(sc->sc_in_pipe)) != 0)
1467 			printf("usbd_close_pipe(IN) returned %d\n", err);
1468 		sc->sc_in_pipe = NULL;
1469 	}
1470 
1471 	if (sc->sc_out_data) {
1472 		free(sc->sc_out_data, M_DEVBUF);
1473 		sc->sc_out_data = NULL;
1474 	}
1475 
1476 	if (sc->sc_in_data) {
1477 		free(sc->sc_in_data, M_DEVBUF);
1478 		sc->sc_in_data = NULL;
1479 	}
1480 
1481 	sc->sc_state = UTOPPY_STATE_CLOSED;
1482 
1483 	DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n",
1484 	    device_xname(sc->sc_dev)));
1485 
1486 	return (0);
1487 }
1488 
1489 int
1490 utoppyread(dev_t dev, struct uio *uio, int flags)
1491 {
1492 	struct utoppy_softc *sc;
1493 	struct utoppy_dirent ud;
1494 	size_t len;
1495 	int err;
1496 
1497 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1498 
1499 	if (sc->sc_dying)
1500 		return (EIO);
1501 
1502 	sc->sc_refcnt++;
1503 
1504 	DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n",
1505 	    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1506 
1507 	switch (sc->sc_state) {
1508 	case UTOPPY_STATE_READDIR:
1509 		err = 0;
1510 		while (err == 0 && uio->uio_resid >= sizeof(ud) &&
1511 		    sc->sc_state != UTOPPY_STATE_IDLE) {
1512 			if (utoppy_readdir_decode(sc, &ud) == 0)
1513 				err = utoppy_readdir_next(sc);
1514 			else
1515 			if ((err = uiomove(&ud, sizeof(ud), uio)) != 0)
1516 				utoppy_cancel(sc);
1517 		}
1518 		break;
1519 
1520 	case UTOPPY_STATE_READFILE:
1521 		err = 0;
1522 		while (err == 0 && uio->uio_resid > 0 &&
1523 		    sc->sc_state != UTOPPY_STATE_IDLE) {
1524 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: "
1525 			    "resid %ld, bytes_left %ld\n",
1526 			    device_xname(sc->sc_dev), (u_long)uio->uio_resid,
1527 			    (u_long)sc->sc_in_len));
1528 
1529 			if (sc->sc_in_len == 0 &&
1530 			    (err = utoppy_readfile_next(sc)) != 0) {
1531 				DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: "
1532 				    "READFILE: utoppy_readfile_next returned "
1533 				    "%d\n", device_xname(sc->sc_dev), err));
1534 				break;
1535 			}
1536 
1537 			len = min(uio->uio_resid, sc->sc_in_len);
1538 			if (len) {
1539 				err = uiomove(UTOPPY_IN_DATA(sc), len, uio);
1540 				if (err == 0) {
1541 					sc->sc_in_offset += len;
1542 					sc->sc_in_len -= len;
1543 				}
1544 			}
1545 		}
1546 		break;
1547 
1548 	case UTOPPY_STATE_IDLE:
1549 		err = 0;
1550 		break;
1551 
1552 	case UTOPPY_STATE_WRITEFILE:
1553 		err = EBUSY;
1554 		break;
1555 
1556 	default:
1557 		err = EIO;
1558 		break;
1559 	}
1560 
1561 	DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n",
1562 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1563 
1564 	if (--sc->sc_refcnt < 0)
1565 		usb_detach_wakeupold(sc->sc_dev);
1566 
1567 	return (err);
1568 }
1569 
1570 int
1571 utoppywrite(dev_t dev, struct uio *uio, int flags)
1572 {
1573 	struct utoppy_softc *sc;
1574 	uint16_t resp;
1575 	size_t len;
1576 	int err;
1577 
1578 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1579 
1580 	if (sc->sc_dying)
1581 		return (EIO);
1582 
1583 	switch(sc->sc_state) {
1584 	case UTOPPY_STATE_WRITEFILE:
1585 		break;
1586 
1587 	case UTOPPY_STATE_IDLE:
1588 		return (0);
1589 
1590 	default:
1591 		return (EIO);
1592 	}
1593 
1594 	sc->sc_refcnt++;
1595 	err = 0;
1596 
1597 	DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid %ld, "
1598 	    "wr_size %lld, wr_offset %lld\n", device_xname(sc->sc_dev),
1599 	    (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset));
1600 
1601 	while (sc->sc_state == UTOPPY_STATE_WRITEFILE &&
1602 	    (len = min(uio->uio_resid, sc->sc_wr_size)) != 0) {
1603 
1604 		len = min(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE +
1605 		    sizeof(uint64_t) + 3));
1606 
1607 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n",
1608 		    device_xname(sc->sc_dev), (u_long)len));
1609 
1610 		UTOPPY_OUT_INIT(sc);
1611 		utoppy_add_64(sc, sc->sc_wr_offset);
1612 
1613 		err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio);
1614 		if (err) {
1615 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove() "
1616 			    "returned %d\n", device_xname(sc->sc_dev), err));
1617 			break;
1618 		}
1619 
1620 		utoppy_advance_ptr(sc->sc_out_data, len);
1621 
1622 		err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA,
1623 		    UTOPPY_LONG_TIMEOUT, &resp);
1624 		if (err) {
1625 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1626 			    "utoppy_command(UTOPPY_RESP_FILE_DATA) "
1627 			    "returned %d\n", device_xname(sc->sc_dev), err));
1628 			break;
1629 		}
1630 		if (resp != UTOPPY_RESP_SUCCESS) {
1631 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1632 			    "utoppy_command(UTOPPY_RESP_FILE_DATA) returned "
1633 			    "bad response 0x%x\n", device_xname(sc->sc_dev),
1634 			    resp));
1635 			utoppy_cancel(sc);
1636 			err = EIO;
1637 			break;
1638 		}
1639 
1640 		sc->sc_wr_offset += len;
1641 		sc->sc_wr_size -= len;
1642 	}
1643 
1644 	DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid %ld,"
1645 	    " wr_size %lld, wr_offset %lld, err %d\n", device_xname(sc->sc_dev),
1646 	    (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset, err));
1647 
1648 	if (err == 0 && sc->sc_wr_size == 0) {
1649 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending "
1650 		    "FILE_END...\n", device_xname(sc->sc_dev)));
1651 		UTOPPY_OUT_INIT(sc);
1652 		err = utoppy_command(sc, UTOPPY_RESP_FILE_END,
1653 		    UTOPPY_LONG_TIMEOUT, &resp);
1654 		if (err) {
1655 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1656 			    "utoppy_command(UTOPPY_RESP_FILE_END) returned "
1657 			    "%d\n", device_xname(sc->sc_dev), err));
1658 
1659 			utoppy_cancel(sc);
1660 		}
1661 
1662 		sc->sc_state = UTOPPY_STATE_IDLE;
1663 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n",
1664 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1665 	}
1666 
1667 	if (--sc->sc_refcnt < 0)
1668 		usb_detach_wakeupold(sc->sc_dev);
1669 
1670 	return (err);
1671 }
1672 
1673 int
1674 utoppyioctl(dev_t dev, u_long cmd, void *data, int flag,
1675     struct lwp *l)
1676 {
1677 	struct utoppy_softc *sc;
1678 	struct utoppy_rename *ur;
1679 	struct utoppy_readfile *urf;
1680 	struct utoppy_writefile *uw;
1681 	char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp;
1682 	uint16_t resp;
1683 	int err;
1684 
1685 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1686 
1687 	if (sc->sc_dying)
1688 		return (EIO);
1689 
1690 	DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1691 	    device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state)));
1692 
1693 	if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) {
1694 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n",
1695 		    device_xname(sc->sc_dev)));
1696 		return (EBUSY);
1697 	}
1698 
1699 	sc->sc_refcnt++;
1700 
1701 	switch (cmd) {
1702 	case UTOPPYIOTURBO:
1703 		err = 0;
1704 		sc->sc_turbo_mode = *((int *)data) ? 1 : 0;
1705 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: "
1706 		    "%s\n", device_xname(sc->sc_dev), sc->sc_turbo_mode ? "On" :
1707 		    "Off"));
1708 		break;
1709 
1710 	case UTOPPYIOCANCEL:
1711 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
1712 		    device_xname(sc->sc_dev)));
1713 		err = utoppy_cancel(sc);
1714 		break;
1715 
1716 	case UTOPPYIOREBOOT:
1717 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1718 		    device_xname(sc->sc_dev)));
1719 		UTOPPY_OUT_INIT(sc);
1720 		err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT,
1721 		    &resp);
1722 		if (err)
1723 			break;
1724 
1725 		if (resp != UTOPPY_RESP_SUCCESS)
1726 			err = EIO;
1727 		break;
1728 
1729 	case UTOPPYIOSTATS:
1730 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
1731 		    device_xname(sc->sc_dev)));
1732 		err = utoppy_stats(sc, (struct utoppy_stats *)data);
1733 		break;
1734 
1735 	case UTOPPYIORENAME:
1736 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n",
1737 		    device_xname(sc->sc_dev)));
1738 		ur = (struct utoppy_rename *)data;
1739 		UTOPPY_OUT_INIT(sc);
1740 
1741 		if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0)
1742 			break;
1743 		if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0)
1744 			break;
1745 
1746 		err = utoppy_command(sc, UTOPPY_CMD_RENAME, UTOPPY_LONG_TIMEOUT,
1747 		    &resp);
1748 		if (err)
1749 			break;
1750 
1751 		if (resp != UTOPPY_RESP_SUCCESS)
1752 			err = EIO;
1753 		break;
1754 
1755 	case UTOPPYIOMKDIR:
1756 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
1757 		    device_xname(sc->sc_dev)));
1758 		UTOPPY_OUT_INIT(sc);
1759 		err = utoppy_add_path(sc, *((const char **)data), 1);
1760 		if (err)
1761 			break;
1762 
1763 		err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT,
1764 		    &resp);
1765 		if (err)
1766 			break;
1767 
1768 		if (resp != UTOPPY_RESP_SUCCESS)
1769 			err = EIO;
1770 		break;
1771 
1772 	case UTOPPYIODELETE:
1773 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n",
1774 		    device_xname(sc->sc_dev)));
1775 		UTOPPY_OUT_INIT(sc);
1776 		err = utoppy_add_path(sc, *((const char **)data), 0);
1777 		if (err)
1778 			break;
1779 
1780 		err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT,
1781 		    &resp);
1782 		if (err)
1783 			break;
1784 
1785 		if (resp != UTOPPY_RESP_SUCCESS)
1786 			err = EIO;
1787 		break;
1788 
1789 	case UTOPPYIOREADDIR:
1790 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
1791 		    device_xname(sc->sc_dev)));
1792 		UTOPPY_OUT_INIT(sc);
1793 		err = utoppy_add_path(sc, *((const char **)data), 0);
1794 		if (err) {
1795 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1796 			    "utoppy_add_path() returned %d\n",
1797 			    device_xname(sc->sc_dev), err));
1798 			break;
1799 		}
1800 
1801 		err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR,
1802 		    UTOPPY_LONG_TIMEOUT);
1803 		if (err != 0) {
1804 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1805 			    "UTOPPY_CMD_READDIR returned %d\n",
1806 			    device_xname(sc->sc_dev), err));
1807 			break;
1808 		}
1809 
1810 		err = utoppy_readdir_next(sc);
1811 		if (err) {
1812 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1813 			    "utoppy_readdir_next() returned %d\n",
1814 			    device_xname(sc->sc_dev), err));
1815 		}
1816 		break;
1817 
1818 	case UTOPPYIOREADFILE:
1819 		urf = (struct utoppy_readfile *)data;
1820 
1821 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE "
1822 		    "%s, offset %lld\n", device_xname(sc->sc_dev), urf->ur_path,
1823 		    urf->ur_offset));
1824 
1825 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1826 			break;
1827 
1828 		UTOPPY_OUT_INIT(sc);
1829 		utoppy_add_8(sc, UTOPPY_FILE_READ);
1830 
1831 		if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0)
1832 			break;
1833 
1834 		utoppy_add_64(sc, urf->ur_offset);
1835 
1836 		sc->sc_state = UTOPPY_STATE_READFILE;
1837 		sc->sc_in_offset = 0;
1838 
1839 		err = utoppy_send_packet(sc, UTOPPY_CMD_FILE,
1840 		    UTOPPY_LONG_TIMEOUT);
1841 		if (err == 0)
1842 			err = utoppy_readfile_next(sc);
1843 		break;
1844 
1845 	case UTOPPYIOWRITEFILE:
1846 		uw = (struct utoppy_writefile *)data;
1847 
1848 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
1849 		    "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev),
1850 		    uw->uw_path, uw->uw_size, uw->uw_offset));
1851 
1852 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1853 			break;
1854 
1855 		UTOPPY_OUT_INIT(sc);
1856 		utoppy_add_8(sc, UTOPPY_FILE_WRITE);
1857 		uwfp = utoppy_current_ptr(sc->sc_out_data);
1858 
1859 		if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) {
1860 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path() "
1861 			    "returned %d\n", device_xname(sc->sc_dev), err));
1862 			break;
1863 		}
1864 
1865 		strncpy(uwf, &uwfp[2], sizeof(uwf));
1866 		utoppy_add_64(sc, uw->uw_offset);
1867 
1868 		err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT,
1869 		    &resp);
1870 		if (err) {
1871 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1872 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
1873 			    "%d\n", device_xname(sc->sc_dev), err));
1874 			break;
1875 		}
1876 		if (resp != UTOPPY_RESP_SUCCESS) {
1877 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1878 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
1879 			    "bad response 0x%x\n", device_xname(sc->sc_dev),
1880 			    resp));
1881 			err = EIO;
1882 			break;
1883 		}
1884 
1885 		UTOPPY_OUT_INIT(sc);
1886 		utoppy_timestamp_encode(sc, uw->uw_mtime);
1887 		utoppy_add_8(sc, UTOPPY_FTYPE_FILE);
1888 		utoppy_add_64(sc, uw->uw_size);
1889 		utoppy_add_string(sc, uwf, sizeof(uwf));
1890 		utoppy_add_32(sc, 0);
1891 
1892 		err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER,
1893 		    UTOPPY_LONG_TIMEOUT, &resp);
1894 		if (err) {
1895 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1896 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1897 			    "returned %d\n", device_xname(sc->sc_dev), err));
1898 			break;
1899 		}
1900 		if (resp != UTOPPY_RESP_SUCCESS) {
1901 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1902 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1903 			    "returned bad response 0x%x\n",
1904 			    device_xname(sc->sc_dev), resp));
1905 			err = EIO;
1906 			break;
1907 		}
1908 
1909 		sc->sc_wr_offset = uw->uw_offset;
1910 		sc->sc_wr_size = uw->uw_size;
1911 		sc->sc_state = UTOPPY_STATE_WRITEFILE;
1912 
1913 		DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to "
1914 		    "%s. wr_offset %lld, wr_size %lld\n",
1915 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state),
1916 		    sc->sc_wr_offset, sc->sc_wr_size));
1917 		break;
1918 
1919 	default:
1920 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n",
1921 		    device_xname(sc->sc_dev)));
1922 		err = ENODEV;
1923 		break;
1924 	}
1925 
1926 	DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
1927 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1928 
1929 	if (err)
1930 		utoppy_cancel(sc);
1931 
1932 	if (--sc->sc_refcnt < 0)
1933 		usb_detach_wakeupold(sc->sc_dev);
1934 
1935 	return (err);
1936 }
1937