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