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