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