xref: /netbsd-src/sys/dev/usb/utoppy.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: utoppy.c,v 1.24 2014/07/25 08:10:39 dholland 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.24 2014/07/25 08:10:39 dholland Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/proc.h>
38 #include <sys/kernel.h>
39 #include <sys/fcntl.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/ioctl.h>
43 #include <sys/uio.h>
44 #include <sys/conf.h>
45 #include <sys/vnode.h>
46 #include <sys/bus.h>
47 
48 #include <dev/usb/usb.h>
49 #include <dev/usb/usbdi.h>
50 #include <dev/usb/usbdivar.h>
51 #include <dev/usb/usbdi_util.h>
52 #include <dev/usb/usbdevs.h>
53 #include <dev/usb/usb_quirks.h>
54 #include <dev/usb/utoppy.h>
55 
56 #undef UTOPPY_DEBUG
57 #ifdef UTOPPY_DEBUG
58 #define	UTOPPY_DBG_OPEN		0x0001
59 #define	UTOPPY_DBG_CLOSE	0x0002
60 #define	UTOPPY_DBG_READ		0x0004
61 #define	UTOPPY_DBG_WRITE	0x0008
62 #define	UTOPPY_DBG_IOCTL	0x0010
63 #define	UTOPPY_DBG_SEND_PACKET	0x0020
64 #define	UTOPPY_DBG_RECV_PACKET	0x0040
65 #define	UTOPPY_DBG_ADDPATH	0x0080
66 #define	UTOPPY_DBG_READDIR	0x0100
67 #define	UTOPPY_DBG_DUMP		0x0200
68 #define	DPRINTF(l, m)				\
69 		do {				\
70 			if (utoppy_debug & l)	\
71 				printf m;	\
72 		} while (/*CONSTCOND*/0)
73 static int utoppy_debug = 0;
74 static void utoppy_dump_packet(const void *, size_t);
75 #define	DDUMP_PACKET(p, l)					\
76 		do {						\
77 			if (utoppy_debug & UTOPPY_DBG_DUMP)	\
78 				utoppy_dump_packet((p), (l));	\
79 		} while (/*CONSTCOND*/0)
80 #else
81 #define	DPRINTF(l, m)		/* nothing */
82 #define	DDUMP_PACKET(p, l)	/* nothing */
83 #endif
84 
85 
86 #define	UTOPPY_CONFIG_NO	1
87 #define	UTOPPY_NUMENDPOINTS	2
88 
89 #define	UTOPPY_BSIZE		0xffff
90 #define	UTOPPY_FRAG_SIZE	0x1000
91 #define	UTOPPY_HEADER_SIZE	8
92 #define	UTOPPY_SHORT_TIMEOUT	(500)		/* 0.5 seconds */
93 #define	UTOPPY_LONG_TIMEOUT	(10 * 1000)	/* 10 seconds */
94 
95 /* Protocol Commands and Responses */
96 #define	UTOPPY_RESP_ERROR		0x0001
97 #define	UTOPPY_CMD_ACK			0x0002
98 #define	 UTOPPY_RESP_SUCCESS		UTOPPY_CMD_ACK
99 #define	UTOPPY_CMD_CANCEL		0x0003
100 #define	UTOPPY_CMD_READY		0x0100
101 #define	UTOPPY_CMD_RESET		0x0101
102 #define	UTOPPY_CMD_TURBO		0x0102
103 #define	UTOPPY_CMD_STATS		0x1000
104 #define  UTOPPY_RESP_STATS_DATA		0x1001
105 #define	UTOPPY_CMD_READDIR		0x1002
106 #define	 UTOPPY_RESP_READDIR_DATA	0x1003
107 #define	 UTOPPY_RESP_READDIR_END	0x1004
108 #define	UTOPPY_CMD_DELETE		0x1005
109 #define	UTOPPY_CMD_RENAME		0x1006
110 #define	UTOPPY_CMD_MKDIR		0x1007
111 #define	UTOPPY_CMD_FILE			0x1008
112 #define  UTOPPY_FILE_WRITE		0
113 #define  UTOPPY_FILE_READ		1
114 #define	 UTOPPY_RESP_FILE_HEADER	0x1009
115 #define	 UTOPPY_RESP_FILE_DATA		0x100a
116 #define	 UTOPPY_RESP_FILE_END		0x100b
117 
118 enum utoppy_state {
119 	UTOPPY_STATE_CLOSED,
120 	UTOPPY_STATE_OPENING,
121 	UTOPPY_STATE_IDLE,
122 	UTOPPY_STATE_READDIR,
123 	UTOPPY_STATE_READFILE,
124 	UTOPPY_STATE_WRITEFILE
125 };
126 
127 struct utoppy_softc {
128 	device_t sc_dev;
129 	usbd_device_handle sc_udev;	/* device */
130 	usbd_interface_handle sc_iface;	/* interface */
131 	int sc_dying;
132 	int sc_refcnt;
133 
134 	enum utoppy_state sc_state;
135 	u_int sc_turbo_mode;
136 
137 	int sc_out;
138 	usbd_pipe_handle sc_out_pipe;	/* bulk out pipe */
139 	usbd_xfer_handle sc_out_xfer;
140 	void *sc_out_buf;
141 	void *sc_out_data;
142 	uint64_t sc_wr_offset;
143 	uint64_t sc_wr_size;
144 
145 	int sc_in;
146 	usbd_pipe_handle sc_in_pipe;	/* bulk in pipe */
147 	usbd_xfer_handle sc_in_xfer;
148 	void *sc_in_buf;
149 	void *sc_in_data;
150 	size_t sc_in_len;
151 	u_int sc_in_offset;
152 };
153 
154 struct utoppy_header {
155 	uint16_t h_len;
156 	uint16_t h_crc;
157 	uint16_t h_cmd2;
158 	uint16_t h_cmd;
159 	uint8_t h_data[0];
160 };
161 #define	UTOPPY_OUT_INIT(sc)					\
162 	do {							\
163 		struct utoppy_header *_h = sc->sc_out_data;	\
164 		_h->h_len = 0;					\
165 	} while (/*CONSTCOND*/0)
166 
167 #define	UTOPPY_MJD_1970 40587u	/* MJD value for Jan 1 00:00:00 1970 */
168 
169 #define	UTOPPY_FTYPE_DIR	1
170 #define	UTOPPY_FTYPE_FILE	2
171 
172 #define	UTOPPY_IN_DATA(sc)	\
173  ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE]))
174 
175 dev_type_open(utoppyopen);
176 dev_type_close(utoppyclose);
177 dev_type_read(utoppyread);
178 dev_type_write(utoppywrite);
179 dev_type_ioctl(utoppyioctl);
180 
181 const struct cdevsw utoppy_cdevsw = {
182 	.d_open = utoppyopen,
183 	.d_close = utoppyclose,
184 	.d_read = utoppyread,
185 	.d_write = utoppywrite,
186 	.d_ioctl = utoppyioctl,
187 	.d_stop = nostop,
188 	.d_tty = notty,
189 	.d_poll = nopoll,
190 	.d_mmap = nommap,
191 	.d_kqfilter = nokqfilter,
192 	.d_discard = nodiscard,
193 	.d_flag = D_OTHER
194 };
195 
196 #define	UTOPPYUNIT(n)	(minor(n))
197 
198 int             utoppy_match(device_t, cfdata_t, void *);
199 void            utoppy_attach(device_t, device_t, void *);
200 int             utoppy_detach(device_t, int);
201 int             utoppy_activate(device_t, enum devact);
202 extern struct cfdriver utoppy_cd;
203 CFATTACH_DECL_NEW(utoppy, sizeof(struct utoppy_softc), utoppy_match, utoppy_attach, utoppy_detach, utoppy_activate);
204 
205 int
206 utoppy_match(device_t parent, cfdata_t match, void *aux)
207 {
208 	struct usb_attach_arg *uaa = aux;
209 
210 	if (uaa->vendor == USB_VENDOR_TOPFIELD &&
211 	    uaa->product == USB_PRODUCT_TOPFIELD_TF5000PVR)
212 		return (UMATCH_VENDOR_PRODUCT);
213 
214 	return (UMATCH_NONE);
215 }
216 
217 void
218 utoppy_attach(device_t parent, device_t self, void *aux)
219 {
220 	struct utoppy_softc *sc = device_private(self);
221 	struct usb_attach_arg *uaa = aux;
222 	usbd_device_handle dev = uaa->device;
223 	usbd_interface_handle iface;
224 	usb_endpoint_descriptor_t *ed;
225 	char *devinfop;
226 	u_int8_t epcount;
227 	int i;
228 
229 	sc->sc_dev = self;
230 
231 	aprint_naive("\n");
232 	aprint_normal("\n");
233 
234 	devinfop = usbd_devinfo_alloc(dev, 0);
235 	aprint_normal_dev(self, "%s\n", devinfop);
236 	usbd_devinfo_free(devinfop);
237 
238 	sc->sc_dying = 0;
239 	sc->sc_refcnt = 0;
240 	sc->sc_udev = dev;
241 
242 	if (usbd_set_config_index(dev, 0, 1)
243 	    || usbd_device2interface_handle(dev, 0, &iface)) {
244 		aprint_error_dev(self, "Configuration failed\n");
245 		return;
246 	}
247 
248 	epcount = 0;
249 	(void) usbd_endpoint_count(iface, &epcount);
250 	if (epcount != UTOPPY_NUMENDPOINTS) {
251 		aprint_error_dev(self, "Expected %d endpoints, got %d\n",
252 		    UTOPPY_NUMENDPOINTS, epcount);
253 		return;
254 	}
255 
256 	sc->sc_in = -1;
257 	sc->sc_out = -1;
258 
259 	for (i = 0; i < epcount; i++) {
260 		ed = usbd_interface2endpoint_descriptor(iface, i);
261 		if (ed == NULL) {
262 			aprint_error_dev(self, "couldn't get ep %d\n", i);
263 			return;
264 		}
265 
266 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
267 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
268 			sc->sc_in = ed->bEndpointAddress;
269 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
270 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
271 			sc->sc_out = ed->bEndpointAddress;
272 		}
273 	}
274 
275 	if (sc->sc_out == -1 || sc->sc_in == -1) {
276 		aprint_error_dev(self,
277 		    "could not find bulk in/out endpoints\n");
278 		sc->sc_dying = 1;
279 		return;
280 	}
281 
282 	sc->sc_iface = iface;
283 	sc->sc_udev = dev;
284 
285 	sc->sc_out_xfer = usbd_alloc_xfer(sc->sc_udev);
286 	if (sc->sc_out_xfer == NULL) {
287 		aprint_error_dev(self, "could not allocate bulk out xfer\n");
288 		goto fail0;
289 	}
290 
291 	sc->sc_out_buf = usbd_alloc_buffer(sc->sc_out_xfer, UTOPPY_FRAG_SIZE);
292 	if (sc->sc_out_buf == NULL) {
293 		aprint_error_dev(self, "could not allocate bulk out buffer\n");
294 		goto fail1;
295 	}
296 
297 	sc->sc_in_xfer = usbd_alloc_xfer(sc->sc_udev);
298 	if (sc->sc_in_xfer == NULL) {
299 		aprint_error_dev(self, "could not allocate bulk in xfer\n");
300 		goto fail1;
301 	}
302 
303 	sc->sc_in_buf = usbd_alloc_buffer(sc->sc_in_xfer, UTOPPY_FRAG_SIZE);
304 	if (sc->sc_in_buf == NULL) {
305 		aprint_error_dev(self, "could not allocate bulk in buffer\n");
306 		goto fail2;
307 	}
308 
309 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
310 			   sc->sc_dev);
311 
312 	return;
313 
314  fail2:	usbd_free_xfer(sc->sc_in_xfer);
315 	sc->sc_in_xfer = NULL;
316 
317  fail1:	usbd_free_xfer(sc->sc_out_xfer);
318 	sc->sc_out_xfer = NULL;
319 
320  fail0:	sc->sc_dying = 1;
321 	return;
322 }
323 
324 int
325 utoppy_activate(device_t self, enum devact act)
326 {
327 	struct utoppy_softc *sc = device_private(self);
328 
329 	switch (act) {
330 	case DVACT_DEACTIVATE:
331 		sc->sc_dying = 1;
332 		return 0;
333 	default:
334 		return EOPNOTSUPP;
335 	}
336 }
337 
338 int
339 utoppy_detach(device_t self, int flags)
340 {
341 	struct utoppy_softc *sc = device_private(self);
342 	int maj, mn;
343 	int s;
344 
345 	sc->sc_dying = 1;
346 	if (sc->sc_out_pipe != NULL)
347 		usbd_abort_pipe(sc->sc_out_pipe);
348 	if (sc->sc_in_pipe != NULL)
349 		usbd_abort_pipe(sc->sc_in_pipe);
350 
351 	if (sc->sc_in_xfer != NULL)
352 		usbd_free_xfer(sc->sc_in_xfer);
353 	if (sc->sc_out_xfer != NULL)
354 		usbd_free_xfer(sc->sc_out_xfer);
355 
356 	s = splusb();
357 	if (--sc->sc_refcnt >= 0)
358 		usb_detach_waitold(sc->sc_dev);
359 	splx(s);
360 
361 	/* locate the major number */
362 	maj = cdevsw_lookup_major(&utoppy_cdevsw);
363 
364 	/* Nuke the vnodes for any open instances (calls close). */
365 	mn = device_unit(self);
366 	vdevgone(maj, mn, mn, VCHR);
367 
368 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
369 			   sc->sc_dev);
370 
371 	return (0);
372 }
373 
374 static const uint16_t utoppy_crc16_lookup[] = {
375 	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
376 	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
377 	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
378 	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
379 	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
380 	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
381 	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
382 	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
383 	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
384 	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
385 	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
386 	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
387 	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
388 	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
389 	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
390 	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
391 	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
392 	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
393 	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
394 	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
395 	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
396 	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
397 	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
398 	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
399 	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
400 	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
401 	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
402 	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
403 	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
404 	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
405 	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
406 	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
407 };
408 
409 #define	UTOPPY_CRC16(ccrc,b)	\
410 	(utoppy_crc16_lookup[((ccrc) ^ (b)) & 0xffu] ^ ((ccrc) >> 8))
411 
412 static const int utoppy_usbdstatus_lookup[] = {
413 	0,		/* USBD_NORMAL_COMPLETION */
414 	EINPROGRESS,	/* USBD_IN_PROGRESS */
415 	EALREADY,	/* USBD_PENDING_REQUESTS */
416 	EAGAIN,		/* USBD_NOT_STARTED */
417 	EINVAL,		/* USBD_INVAL */
418 	ENOMEM,		/* USBD_NOMEM */
419 	ECONNRESET,	/* USBD_CANCELLED */
420 	EFAULT,		/* USBD_BAD_ADDRESS */
421 	EBUSY,		/* USBD_IN_USE */
422 	EADDRNOTAVAIL,	/* USBD_NO_ADDR */
423 	ENETDOWN,	/* USBD_SET_ADDR_FAILED */
424 	EIO,		/* USBD_NO_POWER */
425 	EMLINK,		/* USBD_TOO_DEEP */
426 	EIO,		/* USBD_IOERROR */
427 	ENXIO,		/* USBD_NOT_CONFIGURED */
428 	ETIMEDOUT,	/* USBD_TIMEOUT */
429 	EBADMSG,	/* USBD_SHORT_XFER */
430 	EHOSTDOWN,	/* USBD_STALLED */
431 	EINTR		/* USBD_INTERRUPTED */
432 };
433 
434 static __inline int
435 utoppy_usbd_status2errno(usbd_status err)
436 {
437 
438 	if (err >= USBD_ERROR_MAX)
439 		return (EFAULT);
440 	return (utoppy_usbdstatus_lookup[err]);
441 }
442 
443 #ifdef UTOPPY_DEBUG
444 static const char *
445 utoppy_state_string(enum utoppy_state state)
446 {
447 	const char *str;
448 
449 	switch (state) {
450 	case UTOPPY_STATE_CLOSED:
451 		str = "CLOSED";
452 		break;
453 	case UTOPPY_STATE_OPENING:
454 		str = "OPENING";
455 		break;
456 	case UTOPPY_STATE_IDLE:
457 		str = "IDLE";
458 		break;
459 	case UTOPPY_STATE_READDIR:
460 		str = "READ DIRECTORY";
461 		break;
462 	case UTOPPY_STATE_READFILE:
463 		str = "READ FILE";
464 		break;
465 	case UTOPPY_STATE_WRITEFILE:
466 		str = "WRITE FILE";
467 		break;
468 	default:
469 		str = "INVALID!";
470 		break;
471 	}
472 
473 	return (str);
474 }
475 
476 static void
477 utoppy_dump_packet(const void *b, size_t len)
478 {
479 	const uint8_t *buf = b, *l;
480 	uint8_t c;
481 	size_t i, j;
482 
483 	if (len == 0)
484 		return;
485 
486 	len = min(len, 256);
487 
488 	printf("00: ");
489 
490 	for (i = 0, l = buf; i < len; i++) {
491 		printf("%02x ", *buf++);
492 
493 		if ((i % 16) == 15) {
494 			for (j = 0; j < 16; j++) {
495 				c = *l++;
496 				if (c < ' ' || c > 0x7e)
497 					c = '.';
498 				printf("%c", c);
499 			}
500 
501 			printf("\n");
502 			l = buf;
503 
504 			if ((i + 1) < len)
505 				printf("%02x: ", (u_int)i + 1);
506 		}
507 	}
508 
509 	while ((i++ % 16) != 0)
510 		printf("   ");
511 
512 	if (l < buf) {
513 		while (l < buf) {
514 			c = *l++;
515 			if (c < ' ' || c > 0x7e)
516 				c = '.';
517 			printf("%c", c);
518 		}
519 
520 		printf("\n");
521 	}
522 }
523 #endif
524 
525 static usbd_status
526 utoppy_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
527     u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size,
528     const char *lbl)
529 {
530 	usbd_status err;
531 
532 	usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL);
533 
534 	err = usbd_sync_transfer_sig(xfer);
535 
536 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
537 	return (err);
538 }
539 
540 static int
541 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout)
542 {
543 	struct utoppy_header *h;
544 	usbd_status err;
545 	uint32_t len;
546 	uint16_t dlen, crc;
547 	uint8_t *data, *e, t1, t2;
548 
549 	h = sc->sc_out_data;
550 
551 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, "
552 	    "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len));
553 
554 	dlen = h->h_len;
555 	len = dlen + UTOPPY_HEADER_SIZE;
556 
557 	if (len & 1)
558 		len++;
559 	if ((len % 64) == 0)
560 		len += 2;
561 
562 	if (len >= UTOPPY_BSIZE) {
563 		DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
564 		    "packet too big (%d)\n", device_xname(sc->sc_dev), (int)len));
565 		return (EINVAL);
566 	}
567 
568 	h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE);
569 	h->h_cmd2 = 0;
570 	h->h_cmd = htole16(cmd);
571 
572 	/* The command word is part of the CRC */
573 	crc = UTOPPY_CRC16(0,   0);
574 	crc = UTOPPY_CRC16(crc, 0);
575 	crc = UTOPPY_CRC16(crc, cmd >> 8);
576 	crc = UTOPPY_CRC16(crc, cmd);
577 
578 	/*
579 	 * If there is data following the header, calculate the CRC and
580 	 * byte-swap as we go.
581 	 */
582 	if (dlen) {
583 		data = h->h_data;
584 		e = data + (dlen & ~1);
585 
586 		do {
587 			t1 = data[0];
588 			t2 = data[1];
589 			crc = UTOPPY_CRC16(crc, t1);
590 			crc = UTOPPY_CRC16(crc, t2);
591 			*data++ = t2;
592 			*data++ = t1;
593 		} while (data < e);
594 
595 		if (dlen & 1) {
596 			t1 = data[0];
597 			crc = UTOPPY_CRC16(crc, t1);
598 			data[1] = t1;
599 		}
600 	}
601 
602 	h->h_crc = htole16(crc);
603 	data = sc->sc_out_data;
604 
605 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len "
606 	    "%d...\n", device_xname(sc->sc_dev), (int)len));
607 	DDUMP_PACKET(data, len);
608 
609 	do {
610 		uint32_t thislen;
611 
612 		thislen = min(len, UTOPPY_FRAG_SIZE);
613 
614 		memcpy(sc->sc_out_buf, data, thislen);
615 
616 		err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe,
617 		    USBD_NO_COPY, timeout, sc->sc_out_buf, &thislen,
618 		    "utoppytx");
619 
620 		if (thislen != min(len, UTOPPY_FRAG_SIZE)) {
621 			DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: "
622 			    "utoppy_send_packet: sent %ld, err %d\n",
623 			    device_xname(sc->sc_dev), (u_long)thislen, err));
624 		}
625 
626 		if (err == 0) {
627 			len -= thislen;
628 			data += thislen;
629 		}
630 	} while (err == 0 && len);
631 
632 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
633 	    "usbd_bulk_transfer() returned %d.\n", device_xname(sc->sc_dev),err));
634 
635 	return (err ? utoppy_usbd_status2errno(err) : 0);
636 }
637 
638 static int
639 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout)
640 {
641 	struct utoppy_header *h;
642 	usbd_status err;
643 	uint32_t len, thislen, requested, bytesleft;
644 	uint16_t crc;
645 	uint8_t *data, *e, t1, t2;
646 
647 	data = sc->sc_in_data;
648 	len = 0;
649 	bytesleft = UTOPPY_BSIZE;
650 
651 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n",
652 	    device_xname(sc->sc_dev)));
653 
654 	do {
655 		requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE);
656 
657 		err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe,
658 		    USBD_NO_COPY | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf,
659 		    &thislen, "utoppyrx");
660 
661 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
662 		    "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
663 		    device_xname(sc->sc_dev), err, (u_int)thislen, data));
664 
665 		if (err == 0) {
666 			memcpy(data, sc->sc_in_buf, thislen);
667 			DDUMP_PACKET(data, thislen);
668 			len += thislen;
669 			bytesleft -= thislen;
670 			data += thislen;
671 		}
672 	} while (err == 0 && bytesleft && thislen == requested);
673 
674 	if (err)
675 		return (utoppy_usbd_status2errno(err));
676 
677 	h = sc->sc_in_data;
678 
679 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d "
680 	    "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h));
681 	DDUMP_PACKET(h, len);
682 
683 	if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) {
684 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad "
685 		    " length (len %d, h_len %d)\n", device_xname(sc->sc_dev),
686 		    (int)len, le16toh(h->h_len)));
687 		return (EIO);
688 	}
689 
690 	len = h->h_len = le16toh(h->h_len);
691 	h->h_crc = le16toh(h->h_crc);
692 	*respp = h->h_cmd = le16toh(h->h_cmd);
693 	h->h_cmd2 = le16toh(h->h_cmd2);
694 
695 	/*
696 	 * To maximise data throughput when transferring files, acknowledge
697 	 * data blocks as soon as we receive them. If we detect an error
698 	 * later on, we can always cancel.
699 	 */
700 	if (*respp == UTOPPY_RESP_FILE_DATA) {
701 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
702 		    "ACKing file data\n", device_xname(sc->sc_dev)));
703 
704 		UTOPPY_OUT_INIT(sc);
705 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
706 		    UTOPPY_SHORT_TIMEOUT);
707 		if (err) {
708 			DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: "
709 			    "utoppy_recv_packet: failed to ACK file data: %d\n",
710 			    device_xname(sc->sc_dev), err));
711 			return (err);
712 		}
713 	}
714 
715 	/* The command word is part of the CRC */
716 	crc = UTOPPY_CRC16(0,   h->h_cmd2 >> 8);
717 	crc = UTOPPY_CRC16(crc, h->h_cmd2);
718 	crc = UTOPPY_CRC16(crc, h->h_cmd >> 8);
719 	crc = UTOPPY_CRC16(crc, h->h_cmd);
720 
721 	/*
722 	 * Extract any payload, byte-swapping and calculating the CRC16
723 	 * as we go.
724 	 */
725 	if (len > UTOPPY_HEADER_SIZE) {
726 		data = h->h_data;
727 		e = data + ((len & ~1) - UTOPPY_HEADER_SIZE);
728 
729 		while (data < e) {
730 			t1 = data[0];
731 			t2 = data[1];
732 			crc = UTOPPY_CRC16(crc, t2);
733 			crc = UTOPPY_CRC16(crc, t1);
734 			*data++ = t2;
735 			*data++ = t1;
736 		}
737 
738 		if (len & 1) {
739 			t1 = data[1];
740 			crc = UTOPPY_CRC16(crc, t1);
741 			*data = t1;
742 		}
743 	}
744 
745 	sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE;
746 	sc->sc_in_offset = 0;
747 
748 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, "
749 	    "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev),
750 	    (int)len, crc, h->h_crc));
751 	DDUMP_PACKET(h, len);
752 
753 	return ((crc == h->h_crc) ? 0 : EBADMSG);
754 }
755 
756 static __inline void *
757 utoppy_current_ptr(void *b)
758 {
759 	struct utoppy_header *h = b;
760 
761 	return (&h->h_data[h->h_len]);
762 }
763 
764 static __inline void
765 utoppy_advance_ptr(void *b, size_t len)
766 {
767 	struct utoppy_header *h = b;
768 
769 	h->h_len += len;
770 }
771 
772 static __inline void
773 utoppy_add_8(struct utoppy_softc *sc, uint8_t v)
774 {
775 	struct utoppy_header *h = sc->sc_out_data;
776 	uint8_t *p;
777 
778 	p = utoppy_current_ptr(h);
779 	*p = v;
780 	utoppy_advance_ptr(h, sizeof(v));
781 }
782 
783 static __inline void
784 utoppy_add_16(struct utoppy_softc *sc, uint16_t v)
785 {
786 	struct utoppy_header *h = sc->sc_out_data;
787 	uint8_t *p;
788 
789 	p = utoppy_current_ptr(h);
790 	*p++ = (uint8_t)(v >> 8);
791 	*p = (uint8_t)v;
792 	utoppy_advance_ptr(h, sizeof(v));
793 }
794 
795 static __inline void
796 utoppy_add_32(struct utoppy_softc *sc, uint32_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 >> 24);
803 	*p++ = (uint8_t)(v >> 16);
804 	*p++ = (uint8_t)(v >> 8);
805 	*p = (uint8_t)v;
806 	utoppy_advance_ptr(h, sizeof(v));
807 }
808 
809 static __inline void
810 utoppy_add_64(struct utoppy_softc *sc, uint64_t v)
811 {
812 	struct utoppy_header *h = sc->sc_out_data;
813 	uint8_t *p;
814 
815 	p = utoppy_current_ptr(h);
816 	*p++ = (uint8_t)(v >> 56);
817 	*p++ = (uint8_t)(v >> 48);
818 	*p++ = (uint8_t)(v >> 40);
819 	*p++ = (uint8_t)(v >> 32);
820 	*p++ = (uint8_t)(v >> 24);
821 	*p++ = (uint8_t)(v >> 16);
822 	*p++ = (uint8_t)(v >> 8);
823 	*p = (uint8_t)v;
824 	utoppy_advance_ptr(h, sizeof(v));
825 }
826 
827 static __inline void
828 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len)
829 {
830 	struct utoppy_header *h = sc->sc_out_data;
831 	char *p;
832 
833 	p = utoppy_current_ptr(h);
834 	memset(p, 0, len);
835 	strncpy(p, str, len);
836 	utoppy_advance_ptr(h, len);
837 }
838 
839 static int
840 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen)
841 {
842 	struct utoppy_header *h = sc->sc_out_data;
843 	uint8_t *p, *str, *s;
844 	size_t len;
845 	int err;
846 
847 	p = utoppy_current_ptr(h);
848 
849 	str = putlen ? (p + sizeof(uint16_t)) : p;
850 
851 	err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len);
852 
853 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n",
854 	    err, (int)len));
855 
856 	if (err)
857 		return (err);
858 
859 	if (len < 2)
860 		return (EINVAL);
861 
862 	/*
863 	 * copyinstr(9) has already copied the terminating NUL character,
864 	 * but we append another one in case we have to pad the length
865 	 * later on.
866 	 */
867 	str[len] = '\0';
868 
869 	/*
870 	 * The Toppy uses backslash as the directory separator, so convert
871 	 * all forward slashes.
872 	 */
873 	for (s = &str[len - 2]; s >= str; s--)
874 		if (*s == '/')
875 			*s = '\\';
876 
877 	if ((len + h->h_len) & 1)
878 		len++;
879 
880 	if (putlen)
881 		utoppy_add_16(sc, len);
882 
883 	utoppy_advance_ptr(h, len);
884 
885 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n",
886 	    (u_int)len));
887 
888 	return (0);
889 }
890 
891 static __inline int
892 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp)
893 {
894 	uint8_t *p;
895 
896 	if (sc->sc_in_len < sizeof(*vp))
897 		return (1);
898 
899 	p = UTOPPY_IN_DATA(sc);
900 	*vp = *p;
901 	sc->sc_in_offset += sizeof(*vp);
902 	sc->sc_in_len -= sizeof(*vp);
903 	return (0);
904 }
905 
906 static __inline int
907 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp)
908 {
909 	uint16_t v;
910 	uint8_t *p;
911 
912 	if (sc->sc_in_len < sizeof(v))
913 		return (1);
914 
915 	p = UTOPPY_IN_DATA(sc);
916 	v = *p++;
917 	v = (v << 8) | *p;
918 	*vp = v;
919 	sc->sc_in_offset += sizeof(v);
920 	sc->sc_in_len -= sizeof(v);
921 	return (0);
922 }
923 
924 static __inline int
925 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp)
926 {
927 	uint32_t v;
928 	uint8_t *p;
929 
930 	if (sc->sc_in_len < sizeof(v))
931 		return (1);
932 
933 	p = UTOPPY_IN_DATA(sc);
934 	v = *p++;
935 	v = (v << 8) | *p++;
936 	v = (v << 8) | *p++;
937 	v = (v << 8) | *p;
938 	*vp = v;
939 	sc->sc_in_offset += sizeof(v);
940 	sc->sc_in_len -= sizeof(v);
941 	return (0);
942 }
943 
944 static __inline int
945 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp)
946 {
947 	uint64_t v;
948 	uint8_t *p;
949 
950 	if (sc->sc_in_len < sizeof(v))
951 		return (1);
952 
953 	p = UTOPPY_IN_DATA(sc);
954 	v = *p++;
955 	v = (v << 8) | *p++;
956 	v = (v << 8) | *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 	*vp = v;
963 	sc->sc_in_offset += sizeof(v);
964 	sc->sc_in_len -= sizeof(v);
965 	return (0);
966 }
967 
968 static __inline int
969 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len)
970 {
971 	char *p;
972 
973 	if (sc->sc_in_len < len)
974 		return (1);
975 
976 	memset(str, 0, len);
977 	p = UTOPPY_IN_DATA(sc);
978 	strncpy(str, p, len);
979 	sc->sc_in_offset += len;
980 	sc->sc_in_len -= len;
981 	return (0);
982 }
983 
984 static int
985 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout,
986     uint16_t *presp)
987 {
988 	int err;
989 
990 	err = utoppy_send_packet(sc, cmd, timeout);
991 	if (err)
992 		return (err);
993 
994 	err = utoppy_recv_packet(sc, presp, timeout);
995 	if (err == EBADMSG) {
996 		UTOPPY_OUT_INIT(sc);
997 		utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout);
998 	}
999 
1000 	return (err);
1001 }
1002 
1003 static int
1004 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp)
1005 {
1006 	uint16_t mjd;
1007 	uint8_t hour, minute, sec;
1008 	uint32_t rv;
1009 
1010 	if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) ||
1011 	    utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec))
1012 		return (1);
1013 
1014 	if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){
1015 		*tp = 0;
1016 		return (0);
1017 	}
1018 
1019 	rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd;
1020 
1021 	/* Calculate seconds since 1970 */
1022 	rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24;
1023 
1024 	/* Add in the hours, minutes, and seconds */
1025 	rv += (uint32_t)hour * 60 * 60;
1026 	rv += (uint32_t)minute * 60;
1027 	rv += sec;
1028 	*tp = (time_t)rv;
1029 
1030 	return (0);
1031 }
1032 
1033 static void
1034 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t)
1035 {
1036 	u_int mjd, hour, minute;
1037 
1038 	mjd = t / (60 * 60 * 24);
1039 	t -= mjd * 60 * 60 * 24;
1040 
1041 	hour = t / (60 * 60);
1042 	t -= hour * 60 * 60;
1043 
1044 	minute = t / 60;
1045 	t -= minute * 60;
1046 
1047 	utoppy_add_16(sc, mjd + UTOPPY_MJD_1970);
1048 	utoppy_add_8(sc, hour);
1049 	utoppy_add_8(sc, minute);
1050 	utoppy_add_8(sc, t);
1051 }
1052 
1053 static int
1054 utoppy_turbo_mode(struct utoppy_softc *sc, int state)
1055 {
1056 	uint16_t r;
1057 	int err;
1058 
1059 	UTOPPY_OUT_INIT(sc);
1060 	utoppy_add_32(sc, state);
1061 
1062 	err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r);
1063 	if (err)
1064 		return (err);
1065 
1066 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1067 }
1068 
1069 static int
1070 utoppy_check_ready(struct utoppy_softc *sc)
1071 {
1072 	uint16_t r;
1073 	int err;
1074 
1075 	UTOPPY_OUT_INIT(sc);
1076 
1077 	err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r);
1078 	if (err)
1079 		return (err);
1080 
1081 	return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1082 }
1083 
1084 static int
1085 utoppy_cancel(struct utoppy_softc *sc)
1086 {
1087 	uint16_t r;
1088 	int err, i;
1089 
1090 	/*
1091 	 * Issue the cancel command serveral times. the Toppy doesn't
1092 	 * always respond to the first.
1093 	 */
1094 	for (i = 0; i < 3; i++) {
1095 		UTOPPY_OUT_INIT(sc);
1096 		err = utoppy_command(sc, UTOPPY_CMD_CANCEL,
1097 		    UTOPPY_SHORT_TIMEOUT, &r);
1098 		if (err == 0 && r == UTOPPY_RESP_SUCCESS)
1099 			break;
1100 		err = ETIMEDOUT;
1101 	}
1102 
1103 	if (err)
1104 		return (err);
1105 
1106 	/*
1107 	 * Make sure turbo mode is off, otherwise the Toppy will not
1108 	 * respond to remote control input.
1109 	 */
1110 	(void) utoppy_turbo_mode(sc, 0);
1111 
1112 	sc->sc_state = UTOPPY_STATE_IDLE;
1113 	return (0);
1114 }
1115 
1116 static int
1117 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us)
1118 {
1119 	uint32_t hsize, hfree;
1120 	uint16_t r;
1121 	int err;
1122 
1123 	UTOPPY_OUT_INIT(sc);
1124 	err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r);
1125 	if (err)
1126 		return (err);
1127 
1128 	if (r != UTOPPY_RESP_STATS_DATA)
1129 		return (EIO);
1130 
1131 	if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree))
1132 		return (EIO);
1133 
1134 	us->us_hdd_size = hsize;
1135 	us->us_hdd_size *= 1024;
1136 	us->us_hdd_free = hfree;
1137 	us->us_hdd_free *= 1024;
1138 
1139 	return (0);
1140 }
1141 
1142 static int
1143 utoppy_readdir_next(struct utoppy_softc *sc)
1144 {
1145 	uint16_t resp;
1146 	int err;
1147 
1148 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n",
1149 	    device_xname(sc->sc_dev)));
1150 
1151 	/*
1152 	 * Fetch the next READDIR response
1153 	 */
1154 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1155 	if (err) {
1156 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1157 		    "utoppy_recv_packet() returned %d\n",
1158 		    device_xname(sc->sc_dev), err));
1159 		if (err == EBADMSG) {
1160 			UTOPPY_OUT_INIT(sc);
1161 			utoppy_send_packet(sc, UTOPPY_RESP_ERROR,
1162 			    UTOPPY_LONG_TIMEOUT);
1163 		}
1164 		utoppy_cancel(sc);
1165 		return (err);
1166 	}
1167 
1168 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1169 	    "utoppy_recv_packet() returned %d, len %ld\n",
1170 	    device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len));
1171 
1172 	switch (resp) {
1173 	case UTOPPY_RESP_READDIR_DATA:
1174 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1175 		    "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev)));
1176 
1177 		UTOPPY_OUT_INIT(sc);
1178 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1179 		    UTOPPY_LONG_TIMEOUT);
1180 		if (err) {
1181 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1182 			    "utoppy_send_packet(ACK) returned %d\n",
1183 			    device_xname(sc->sc_dev), err));
1184 			utoppy_cancel(sc);
1185 			return (err);
1186 		}
1187 		sc->sc_state = UTOPPY_STATE_READDIR;
1188 		sc->sc_in_offset = 0;
1189 		break;
1190 
1191 	case UTOPPY_RESP_READDIR_END:
1192 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1193 		    "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev)));
1194 
1195 		UTOPPY_OUT_INIT(sc);
1196 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1197 		sc->sc_state = UTOPPY_STATE_IDLE;
1198 		sc->sc_in_len = 0;
1199 		break;
1200 
1201 	default:
1202 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1203 		    "bad response: 0x%x\n", device_xname(sc->sc_dev), resp));
1204 		sc->sc_state = UTOPPY_STATE_IDLE;
1205 		sc->sc_in_len = 0;
1206 		return (EIO);
1207 	}
1208 
1209 	return (0);
1210 }
1211 
1212 static size_t
1213 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud)
1214 {
1215 	uint8_t ftype;
1216 
1217 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left"
1218 	    " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len));
1219 
1220 	if (utoppy_timestamp_decode(sc, &ud->ud_mtime) ||
1221 	    utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) ||
1222 	    utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) ||
1223 	    utoppy_get_32(sc, &ud->ud_attributes)) {
1224 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no "
1225 		    "more to decode\n", device_xname(sc->sc_dev)));
1226 		return (0);
1227 	}
1228 
1229 	switch (ftype) {
1230 	case UTOPPY_FTYPE_DIR:
1231 		ud->ud_type = UTOPPY_DIRENT_DIRECTORY;
1232 		break;
1233 	case UTOPPY_FTYPE_FILE:
1234 		ud->ud_type = UTOPPY_DIRENT_FILE;
1235 		break;
1236 	default:
1237 		ud->ud_type = UTOPPY_DIRENT_UNKNOWN;
1238 		break;
1239 	}
1240 
1241 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', "
1242 	    "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev),
1243 	    (ftype == UTOPPY_FTYPE_DIR) ? "DIR" :
1244 	    ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path,
1245 	    ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes));
1246 
1247 	return (1);
1248 }
1249 
1250 static int
1251 utoppy_readfile_next(struct utoppy_softc *sc)
1252 {
1253 	uint64_t off;
1254 	uint16_t resp;
1255 	int err;
1256 
1257 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1258 	if (err) {
1259 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1260 		    "utoppy_recv_packet() returned %d\n",
1261 		    device_xname(sc->sc_dev), err));
1262 		utoppy_cancel(sc);
1263 		return (err);
1264 	}
1265 
1266 	switch (resp) {
1267 	case UTOPPY_RESP_FILE_HEADER:
1268 		/* ACK it */
1269 		UTOPPY_OUT_INIT(sc);
1270 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1271 		    UTOPPY_LONG_TIMEOUT);
1272 		if (err) {
1273 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1274 			    "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
1275 			    device_xname(sc->sc_dev), err));
1276 			utoppy_cancel(sc);
1277 			return (err);
1278 		}
1279 
1280 		sc->sc_in_len = 0;
1281 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1282 		    "FILE_HEADER done\n", device_xname(sc->sc_dev)));
1283 		break;
1284 
1285 	case UTOPPY_RESP_FILE_DATA:
1286 		/* Already ACK'd */
1287 		if (utoppy_get_64(sc, &off)) {
1288 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1289 			    "UTOPPY_RESP_FILE_DATA did not provide offset\n",
1290 			    device_xname(sc->sc_dev)));
1291 			utoppy_cancel(sc);
1292 			return (EBADMSG);
1293 		}
1294 
1295 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1296 		    "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
1297 		    device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len));
1298 		break;
1299 
1300 	case UTOPPY_RESP_FILE_END:
1301 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1302 		    "UTOPPY_RESP_FILE_END: sending ACK\n",
1303 		    device_xname(sc->sc_dev)));
1304 		UTOPPY_OUT_INIT(sc);
1305 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1306 		/*FALLTHROUGH*/
1307 
1308 	case UTOPPY_RESP_SUCCESS:
1309 		sc->sc_state = UTOPPY_STATE_IDLE;
1310 		(void) utoppy_turbo_mode(sc, 0);
1311 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all "
1312 		    "done\n", device_xname(sc->sc_dev)));
1313 		break;
1314 
1315 	case UTOPPY_RESP_ERROR:
1316 	default:
1317 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad "
1318 		    "response code 0x%0x\n", device_xname(sc->sc_dev), resp));
1319 		utoppy_cancel(sc);
1320 		return (EIO);
1321 	}
1322 
1323 	return (0);
1324 }
1325 
1326 int
1327 utoppyopen(dev_t dev, int flag, int mode,
1328     struct lwp *l)
1329 {
1330 	struct utoppy_softc *sc;
1331 	int error = 0;
1332 
1333 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1334 	if (sc == NULL)
1335 		return ENXIO;
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 		    device_xname(sc->sc_dev)));
1343 		return (EBUSY);
1344 	}
1345 
1346 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n",
1347 	    device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(sc->sc_dev), error,
1405 	    utoppy_state_string(sc->sc_state)));
1406 
1407 	if (--sc->sc_refcnt < 0)
1408 		usb_detach_wakeupold(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 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1421 
1422 	DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n",
1423 	    device_xname(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", device_xname(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 	    device_xname(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 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
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 	    device_xname(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 			    device_xname(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", device_xname(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 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1544 
1545 	if (--sc->sc_refcnt < 0)
1546 		usb_detach_wakeupold(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 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
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", device_xname(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 		    device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1646 	}
1647 
1648 	if (--sc->sc_refcnt < 0)
1649 		usb_detach_wakeupold(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 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
1667 
1668 	if (sc->sc_dying)
1669 		return (EIO);
1670 
1671 	DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1672 	    device_xname(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 		    device_xname(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", device_xname(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 		    device_xname(sc->sc_dev)));
1694 		err = utoppy_cancel(sc);
1695 		break;
1696 
1697 	case UTOPPYIOREBOOT:
1698 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1699 		    device_xname(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 		    device_xname(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 		    device_xname(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 		    device_xname(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 		    device_xname(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 		    device_xname(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 			    device_xname(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 			    device_xname(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 			    device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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", device_xname(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 			    device_xname(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 		    device_xname(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 		    device_xname(sc->sc_dev)));
1903 		err = ENODEV;
1904 		break;
1905 	}
1906 
1907 	DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
1908 	    device_xname(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_wakeupold(sc->sc_dev);
1915 
1916 	return (err);
1917 }
1918