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