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