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