Home | History | Annotate | Line # | Download | only in usb
utoppy.c revision 1.25
      1 /*	$NetBSD: utoppy.c,v 1.25 2016/04/23 10:15:32 skrll 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.25 2016/04/23 10:15:32 skrll 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, utoppy_attach, utoppy_detach, utoppy_activate);
    203 
    204 int
    205 utoppy_match(device_t parent, cfdata_t match, void *aux)
    206 {
    207 	struct usb_attach_arg *uaa = aux;
    208 
    209 	if (uaa->uaa_vendor == USB_VENDOR_TOPFIELD &&
    210 	    uaa->uaa_product == USB_PRODUCT_TOPFIELD_TF5000PVR)
    211 		return UMATCH_VENDOR_PRODUCT;
    212 
    213 	return UMATCH_NONE;
    214 }
    215 
    216 void
    217 utoppy_attach(device_t parent, device_t self, void *aux)
    218 {
    219 	struct utoppy_softc *sc = device_private(self);
    220 	struct usb_attach_arg *uaa = aux;
    221 	struct usbd_device *dev = uaa->uaa_device;
    222 	struct usbd_interface *iface;
    223 	usb_endpoint_descriptor_t *ed;
    224 	char *devinfop;
    225 	uint8_t epcount;
    226 	int i;
    227 
    228 	sc->sc_dev = self;
    229 
    230 	aprint_naive("\n");
    231 	aprint_normal("\n");
    232 
    233 	devinfop = usbd_devinfo_alloc(dev, 0);
    234 	aprint_normal_dev(self, "%s\n", devinfop);
    235 	usbd_devinfo_free(devinfop);
    236 
    237 	sc->sc_dying = 0;
    238 	sc->sc_refcnt = 0;
    239 	sc->sc_udev = dev;
    240 
    241 	if (usbd_set_config_index(dev, 0, 1)
    242 	    || usbd_device2interface_handle(dev, 0, &iface)) {
    243 		aprint_error_dev(self, "Configuration failed\n");
    244 		return;
    245 	}
    246 
    247 	epcount = 0;
    248 	(void) usbd_endpoint_count(iface, &epcount);
    249 	if (epcount != UTOPPY_NUMENDPOINTS) {
    250 		aprint_error_dev(self, "Expected %d endpoints, got %d\n",
    251 		    UTOPPY_NUMENDPOINTS, epcount);
    252 		return;
    253 	}
    254 
    255 	sc->sc_in = -1;
    256 	sc->sc_out = -1;
    257 
    258 	for (i = 0; i < epcount; i++) {
    259 		ed = usbd_interface2endpoint_descriptor(iface, i);
    260 		if (ed == NULL) {
    261 			aprint_error_dev(self, "couldn't get ep %d\n", i);
    262 			return;
    263 		}
    264 
    265 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
    266 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    267 			sc->sc_in = ed->bEndpointAddress;
    268 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
    269 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
    270 			sc->sc_out = ed->bEndpointAddress;
    271 		}
    272 	}
    273 
    274 	if (sc->sc_out == -1 || sc->sc_in == -1) {
    275 		aprint_error_dev(self,
    276 		    "could not find bulk in/out endpoints\n");
    277 		sc->sc_dying = 1;
    278 		return;
    279 	}
    280 
    281 	sc->sc_iface = iface;
    282 	sc->sc_udev = dev;
    283 
    284 	sc->sc_out_pipe = NULL;
    285 	sc->sc_in_pipe = NULL;
    286 
    287 	if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) {
    288 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(OUT) failed\n",
    289 		    device_xname(sc->sc_dev)));
    290 		aprint_error_dev(self, "could not open OUT pipe\n");
    291 		sc->sc_dying = 1;
    292 		return;
    293 	}
    294 
    295 	if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) {
    296 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: usbd_open_pipe(IN) failed\n",
    297 		    device_xname(sc->sc_dev)));
    298 		aprint_error_dev(self, "could not open IN pipe\n");
    299 
    300 		usbd_close_pipe(sc->sc_out_pipe);
    301 		sc->sc_out_pipe = NULL;
    302 		sc->sc_dying = 1;
    303 		return;
    304 	}
    305 
    306 	int error;
    307 	error = usbd_create_xfer(sc->sc_out_pipe, UTOPPY_FRAG_SIZE, 0, 0,
    308 	    &sc->sc_out_xfer);
    309 	if (error) {
    310 		aprint_error_dev(self, "could not allocate bulk out xfer\n");
    311 		goto fail0;
    312 	}
    313 
    314 	error = usbd_create_xfer(sc->sc_in_pipe, UTOPPY_FRAG_SIZE,
    315 	    USBD_SHORT_XFER_OK, 0, &sc->sc_in_xfer);
    316 	if (error) {
    317 		aprint_error_dev(self, "could not allocate bulk in xfer\n");
    318 		goto fail1;
    319 	}
    320 
    321 	sc->sc_out_buf = usbd_get_buffer(sc->sc_out_xfer);
    322 	sc->sc_in_buf = usbd_get_buffer(sc->sc_in_xfer);
    323 
    324 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
    325 			   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,
    386 			   sc->sc_dev);
    387 
    388 	return 0;
    389 }
    390 
    391 static const uint16_t utoppy_crc16_lookup[] = {
    392 	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
    393 	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
    394 	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
    395 	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
    396 	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
    397 	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
    398 	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
    399 	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
    400 	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
    401 	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
    402 	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
    403 	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
    404 	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
    405 	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
    406 	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
    407 	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
    408 	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
    409 	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
    410 	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
    411 	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
    412 	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
    413 	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
    414 	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
    415 	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
    416 	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
    417 	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
    418 	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
    419 	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
    420 	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
    421 	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
    422 	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
    423 	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
    424 };
    425 
    426 #define	UTOPPY_CRC16(ccrc,b)	\
    427 	(utoppy_crc16_lookup[((ccrc) ^ (b)) & 0xffu] ^ ((ccrc) >> 8))
    428 
    429 static const int utoppy_usbdstatus_lookup[] = {
    430 	0,		/* USBD_NORMAL_COMPLETION */
    431 	EINPROGRESS,	/* USBD_IN_PROGRESS */
    432 	EALREADY,	/* USBD_PENDING_REQUESTS */
    433 	EAGAIN,		/* USBD_NOT_STARTED */
    434 	EINVAL,		/* USBD_INVAL */
    435 	ENOMEM,		/* USBD_NOMEM */
    436 	ECONNRESET,	/* USBD_CANCELLED */
    437 	EFAULT,		/* USBD_BAD_ADDRESS */
    438 	EBUSY,		/* USBD_IN_USE */
    439 	EADDRNOTAVAIL,	/* USBD_NO_ADDR */
    440 	ENETDOWN,	/* USBD_SET_ADDR_FAILED */
    441 	EIO,		/* USBD_NO_POWER */
    442 	EMLINK,		/* USBD_TOO_DEEP */
    443 	EIO,		/* USBD_IOERROR */
    444 	ENXIO,		/* USBD_NOT_CONFIGURED */
    445 	ETIMEDOUT,	/* USBD_TIMEOUT */
    446 	EBADMSG,	/* USBD_SHORT_XFER */
    447 	EHOSTDOWN,	/* USBD_STALLED */
    448 	EINTR		/* USBD_INTERRUPTED */
    449 };
    450 
    451 static __inline int
    452 utoppy_usbd_status2errno(usbd_status err)
    453 {
    454 
    455 	if (err >= USBD_ERROR_MAX)
    456 		return EFAULT;
    457 	return utoppy_usbdstatus_lookup[err];
    458 }
    459 
    460 #ifdef UTOPPY_DEBUG
    461 static const char *
    462 utoppy_state_string(enum utoppy_state state)
    463 {
    464 	const char *str;
    465 
    466 	switch (state) {
    467 	case UTOPPY_STATE_CLOSED:
    468 		str = "CLOSED";
    469 		break;
    470 	case UTOPPY_STATE_OPENING:
    471 		str = "OPENING";
    472 		break;
    473 	case UTOPPY_STATE_IDLE:
    474 		str = "IDLE";
    475 		break;
    476 	case UTOPPY_STATE_READDIR:
    477 		str = "READ DIRECTORY";
    478 		break;
    479 	case UTOPPY_STATE_READFILE:
    480 		str = "READ FILE";
    481 		break;
    482 	case UTOPPY_STATE_WRITEFILE:
    483 		str = "WRITE FILE";
    484 		break;
    485 	default:
    486 		str = "INVALID!";
    487 		break;
    488 	}
    489 
    490 	return str;
    491 }
    492 
    493 static void
    494 utoppy_dump_packet(const void *b, size_t len)
    495 {
    496 	const uint8_t *buf = b, *l;
    497 	uint8_t c;
    498 	size_t i, j;
    499 
    500 	if (len == 0)
    501 		return;
    502 
    503 	len = min(len, 256);
    504 
    505 	printf("00: ");
    506 
    507 	for (i = 0, l = buf; i < len; i++) {
    508 		printf("%02x ", *buf++);
    509 
    510 		if ((i % 16) == 15) {
    511 			for (j = 0; j < 16; j++) {
    512 				c = *l++;
    513 				if (c < ' ' || c > 0x7e)
    514 					c = '.';
    515 				printf("%c", c);
    516 			}
    517 
    518 			printf("\n");
    519 			l = buf;
    520 
    521 			if ((i + 1) < len)
    522 				printf("%02x: ", (u_int)i + 1);
    523 		}
    524 	}
    525 
    526 	while ((i++ % 16) != 0)
    527 		printf("   ");
    528 
    529 	if (l < buf) {
    530 		while (l < buf) {
    531 			c = *l++;
    532 			if (c < ' ' || c > 0x7e)
    533 				c = '.';
    534 			printf("%c", c);
    535 		}
    536 
    537 		printf("\n");
    538 	}
    539 }
    540 #endif
    541 
    542 static usbd_status
    543 utoppy_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe,
    544     uint16_t flags, uint32_t timeout, void *buf, uint32_t *size)
    545 {
    546 	usbd_status err;
    547 
    548 	usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL);
    549 
    550 	err = usbd_sync_transfer_sig(xfer);
    551 
    552 	usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
    553 	return err;
    554 }
    555 
    556 static int
    557 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout)
    558 {
    559 	struct utoppy_header *h;
    560 	usbd_status err;
    561 	uint32_t len;
    562 	uint16_t dlen, crc;
    563 	uint8_t *data, *e, t1, t2;
    564 
    565 	h = sc->sc_out_data;
    566 
    567 	DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, "
    568 	    "len %d\n", device_xname(sc->sc_dev), (u_int)cmd, h->h_len));
    569 
    570 	dlen = h->h_len;
    571 	len = dlen + UTOPPY_HEADER_SIZE;
    572 
    573 	if (len & 1)
    574 		len++;
    575 	if ((len % 64) == 0)
    576 		len += 2;
    577 
    578 	if (len >= UTOPPY_BSIZE) {
    579 		DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
    580 		    "packet too big (%d)\n", device_xname(sc->sc_dev), (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", device_xname(sc->sc_dev),err));
    649 
    650 	return err ? utoppy_usbd_status2errno(err) : 0;
    651 }
    652 
    653 static int
    654 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout)
    655 {
    656 	struct utoppy_header *h;
    657 	usbd_status err;
    658 	uint32_t len, thislen, requested, bytesleft;
    659 	uint16_t crc;
    660 	uint8_t *data, *e, t1, t2;
    661 
    662 	data = sc->sc_in_data;
    663 	len = 0;
    664 	bytesleft = UTOPPY_BSIZE;
    665 
    666 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n",
    667 	    device_xname(sc->sc_dev)));
    668 
    669 	do {
    670 		requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE);
    671 
    672 		err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe,
    673 		    USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf,
    674 		    &thislen);
    675 
    676 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
    677 		    "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
    678 		    device_xname(sc->sc_dev), err, (u_int)thislen, data));
    679 
    680 		if (err == 0) {
    681 			memcpy(data, sc->sc_in_buf, thislen);
    682 			DDUMP_PACKET(data, thislen);
    683 			len += thislen;
    684 			bytesleft -= thislen;
    685 			data += thislen;
    686 		}
    687 	} while (err == 0 && bytesleft && thislen == requested);
    688 
    689 	if (err)
    690 		return utoppy_usbd_status2errno(err);
    691 
    692 	h = sc->sc_in_data;
    693 
    694 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d "
    695 	    "bytes in total to %p\n", device_xname(sc->sc_dev), (u_int)len, h));
    696 	DDUMP_PACKET(h, len);
    697 
    698 	if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) {
    699 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad "
    700 		    " length (len %d, h_len %d)\n", device_xname(sc->sc_dev),
    701 		    (int)len, le16toh(h->h_len)));
    702 		return EIO;
    703 	}
    704 
    705 	len = h->h_len = le16toh(h->h_len);
    706 	h->h_crc = le16toh(h->h_crc);
    707 	*respp = h->h_cmd = le16toh(h->h_cmd);
    708 	h->h_cmd2 = le16toh(h->h_cmd2);
    709 
    710 	/*
    711 	 * To maximise data throughput when transferring files, acknowledge
    712 	 * data blocks as soon as we receive them. If we detect an error
    713 	 * later on, we can always cancel.
    714 	 */
    715 	if (*respp == UTOPPY_RESP_FILE_DATA) {
    716 		DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
    717 		    "ACKing file data\n", device_xname(sc->sc_dev)));
    718 
    719 		UTOPPY_OUT_INIT(sc);
    720 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
    721 		    UTOPPY_SHORT_TIMEOUT);
    722 		if (err) {
    723 			DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: "
    724 			    "utoppy_recv_packet: failed to ACK file data: %d\n",
    725 			    device_xname(sc->sc_dev), err));
    726 			return err;
    727 		}
    728 	}
    729 
    730 	/* The command word is part of the CRC */
    731 	crc = UTOPPY_CRC16(0,   h->h_cmd2 >> 8);
    732 	crc = UTOPPY_CRC16(crc, h->h_cmd2);
    733 	crc = UTOPPY_CRC16(crc, h->h_cmd >> 8);
    734 	crc = UTOPPY_CRC16(crc, h->h_cmd);
    735 
    736 	/*
    737 	 * Extract any payload, byte-swapping and calculating the CRC16
    738 	 * as we go.
    739 	 */
    740 	if (len > UTOPPY_HEADER_SIZE) {
    741 		data = h->h_data;
    742 		e = data + ((len & ~1) - UTOPPY_HEADER_SIZE);
    743 
    744 		while (data < e) {
    745 			t1 = data[0];
    746 			t2 = data[1];
    747 			crc = UTOPPY_CRC16(crc, t2);
    748 			crc = UTOPPY_CRC16(crc, t1);
    749 			*data++ = t2;
    750 			*data++ = t1;
    751 		}
    752 
    753 		if (len & 1) {
    754 			t1 = data[1];
    755 			crc = UTOPPY_CRC16(crc, t1);
    756 			*data = t1;
    757 		}
    758 	}
    759 
    760 	sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE;
    761 	sc->sc_in_offset = 0;
    762 
    763 	DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, "
    764 	    "crc 0x%04x, hdrcrc 0x%04x\n", device_xname(sc->sc_dev),
    765 	    (int)len, crc, h->h_crc));
    766 	DDUMP_PACKET(h, len);
    767 
    768 	return (crc == h->h_crc) ? 0 : EBADMSG;
    769 }
    770 
    771 static __inline void *
    772 utoppy_current_ptr(void *b)
    773 {
    774 	struct utoppy_header *h = b;
    775 
    776 	return &h->h_data[h->h_len];
    777 }
    778 
    779 static __inline void
    780 utoppy_advance_ptr(void *b, size_t len)
    781 {
    782 	struct utoppy_header *h = b;
    783 
    784 	h->h_len += len;
    785 }
    786 
    787 static __inline void
    788 utoppy_add_8(struct utoppy_softc *sc, uint8_t v)
    789 {
    790 	struct utoppy_header *h = sc->sc_out_data;
    791 	uint8_t *p;
    792 
    793 	p = utoppy_current_ptr(h);
    794 	*p = v;
    795 	utoppy_advance_ptr(h, sizeof(v));
    796 }
    797 
    798 static __inline void
    799 utoppy_add_16(struct utoppy_softc *sc, uint16_t v)
    800 {
    801 	struct utoppy_header *h = sc->sc_out_data;
    802 	uint8_t *p;
    803 
    804 	p = utoppy_current_ptr(h);
    805 	*p++ = (uint8_t)(v >> 8);
    806 	*p = (uint8_t)v;
    807 	utoppy_advance_ptr(h, sizeof(v));
    808 }
    809 
    810 static __inline void
    811 utoppy_add_32(struct utoppy_softc *sc, uint32_t v)
    812 {
    813 	struct utoppy_header *h = sc->sc_out_data;
    814 	uint8_t *p;
    815 
    816 	p = utoppy_current_ptr(h);
    817 	*p++ = (uint8_t)(v >> 24);
    818 	*p++ = (uint8_t)(v >> 16);
    819 	*p++ = (uint8_t)(v >> 8);
    820 	*p = (uint8_t)v;
    821 	utoppy_advance_ptr(h, sizeof(v));
    822 }
    823 
    824 static __inline void
    825 utoppy_add_64(struct utoppy_softc *sc, uint64_t v)
    826 {
    827 	struct utoppy_header *h = sc->sc_out_data;
    828 	uint8_t *p;
    829 
    830 	p = utoppy_current_ptr(h);
    831 	*p++ = (uint8_t)(v >> 56);
    832 	*p++ = (uint8_t)(v >> 48);
    833 	*p++ = (uint8_t)(v >> 40);
    834 	*p++ = (uint8_t)(v >> 32);
    835 	*p++ = (uint8_t)(v >> 24);
    836 	*p++ = (uint8_t)(v >> 16);
    837 	*p++ = (uint8_t)(v >> 8);
    838 	*p = (uint8_t)v;
    839 	utoppy_advance_ptr(h, sizeof(v));
    840 }
    841 
    842 static __inline void
    843 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len)
    844 {
    845 	struct utoppy_header *h = sc->sc_out_data;
    846 	char *p;
    847 
    848 	p = utoppy_current_ptr(h);
    849 	memset(p, 0, len);
    850 	strncpy(p, str, len);
    851 	utoppy_advance_ptr(h, len);
    852 }
    853 
    854 static int
    855 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen)
    856 {
    857 	struct utoppy_header *h = sc->sc_out_data;
    858 	uint8_t *p, *str, *s;
    859 	size_t len;
    860 	int err;
    861 
    862 	p = utoppy_current_ptr(h);
    863 
    864 	str = putlen ? (p + sizeof(uint16_t)) : p;
    865 
    866 	err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len);
    867 
    868 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n",
    869 	    err, (int)len));
    870 
    871 	if (err)
    872 		return err;
    873 
    874 	if (len < 2)
    875 		return EINVAL;
    876 
    877 	/*
    878 	 * copyinstr(9) has already copied the terminating NUL character,
    879 	 * but we append another one in case we have to pad the length
    880 	 * later on.
    881 	 */
    882 	str[len] = '\0';
    883 
    884 	/*
    885 	 * The Toppy uses backslash as the directory separator, so convert
    886 	 * all forward slashes.
    887 	 */
    888 	for (s = &str[len - 2]; s >= str; s--)
    889 		if (*s == '/')
    890 			*s = '\\';
    891 
    892 	if ((len + h->h_len) & 1)
    893 		len++;
    894 
    895 	if (putlen)
    896 		utoppy_add_16(sc, len);
    897 
    898 	utoppy_advance_ptr(h, len);
    899 
    900 	DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n",
    901 	    (u_int)len));
    902 
    903 	return 0;
    904 }
    905 
    906 static __inline int
    907 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp)
    908 {
    909 	uint8_t *p;
    910 
    911 	if (sc->sc_in_len < sizeof(*vp))
    912 		return 1;
    913 
    914 	p = UTOPPY_IN_DATA(sc);
    915 	*vp = *p;
    916 	sc->sc_in_offset += sizeof(*vp);
    917 	sc->sc_in_len -= sizeof(*vp);
    918 	return 0;
    919 }
    920 
    921 static __inline int
    922 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp)
    923 {
    924 	uint16_t v;
    925 	uint8_t *p;
    926 
    927 	if (sc->sc_in_len < sizeof(v))
    928 		return 1;
    929 
    930 	p = UTOPPY_IN_DATA(sc);
    931 	v = *p++;
    932 	v = (v << 8) | *p;
    933 	*vp = v;
    934 	sc->sc_in_offset += sizeof(v);
    935 	sc->sc_in_len -= sizeof(v);
    936 	return 0;
    937 }
    938 
    939 static __inline int
    940 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp)
    941 {
    942 	uint32_t v;
    943 	uint8_t *p;
    944 
    945 	if (sc->sc_in_len < sizeof(v))
    946 		return 1;
    947 
    948 	p = UTOPPY_IN_DATA(sc);
    949 	v = *p++;
    950 	v = (v << 8) | *p++;
    951 	v = (v << 8) | *p++;
    952 	v = (v << 8) | *p;
    953 	*vp = v;
    954 	sc->sc_in_offset += sizeof(v);
    955 	sc->sc_in_len -= sizeof(v);
    956 	return 0;
    957 }
    958 
    959 static __inline int
    960 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp)
    961 {
    962 	uint64_t v;
    963 	uint8_t *p;
    964 
    965 	if (sc->sc_in_len < sizeof(v))
    966 		return 1;
    967 
    968 	p = UTOPPY_IN_DATA(sc);
    969 	v = *p++;
    970 	v = (v << 8) | *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 	*vp = v;
    978 	sc->sc_in_offset += sizeof(v);
    979 	sc->sc_in_len -= sizeof(v);
    980 	return 0;
    981 }
    982 
    983 static __inline int
    984 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len)
    985 {
    986 	char *p;
    987 
    988 	if (sc->sc_in_len < len)
    989 		return 1;
    990 
    991 	memset(str, 0, len);
    992 	p = UTOPPY_IN_DATA(sc);
    993 	strncpy(str, p, len);
    994 	sc->sc_in_offset += len;
    995 	sc->sc_in_len -= len;
    996 	return 0;
    997 }
    998 
    999 static int
   1000 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout,
   1001     uint16_t *presp)
   1002 {
   1003 	int err;
   1004 
   1005 	err = utoppy_send_packet(sc, cmd, timeout);
   1006 	if (err)
   1007 		return err;
   1008 
   1009 	err = utoppy_recv_packet(sc, presp, timeout);
   1010 	if (err == EBADMSG) {
   1011 		UTOPPY_OUT_INIT(sc);
   1012 		utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout);
   1013 	}
   1014 
   1015 	return err;
   1016 }
   1017 
   1018 static int
   1019 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp)
   1020 {
   1021 	uint16_t mjd;
   1022 	uint8_t hour, minute, sec;
   1023 	uint32_t rv;
   1024 
   1025 	if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) ||
   1026 	    utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec))
   1027 		return 1;
   1028 
   1029 	if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){
   1030 		*tp = 0;
   1031 		return 0;
   1032 	}
   1033 
   1034 	rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd;
   1035 
   1036 	/* Calculate seconds since 1970 */
   1037 	rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24;
   1038 
   1039 	/* Add in the hours, minutes, and seconds */
   1040 	rv += (uint32_t)hour * 60 * 60;
   1041 	rv += (uint32_t)minute * 60;
   1042 	rv += sec;
   1043 	*tp = (time_t)rv;
   1044 
   1045 	return 0;
   1046 }
   1047 
   1048 static void
   1049 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t)
   1050 {
   1051 	u_int mjd, hour, minute;
   1052 
   1053 	mjd = t / (60 * 60 * 24);
   1054 	t -= mjd * 60 * 60 * 24;
   1055 
   1056 	hour = t / (60 * 60);
   1057 	t -= hour * 60 * 60;
   1058 
   1059 	minute = t / 60;
   1060 	t -= minute * 60;
   1061 
   1062 	utoppy_add_16(sc, mjd + UTOPPY_MJD_1970);
   1063 	utoppy_add_8(sc, hour);
   1064 	utoppy_add_8(sc, minute);
   1065 	utoppy_add_8(sc, t);
   1066 }
   1067 
   1068 static int
   1069 utoppy_turbo_mode(struct utoppy_softc *sc, int state)
   1070 {
   1071 	uint16_t r;
   1072 	int err;
   1073 
   1074 	UTOPPY_OUT_INIT(sc);
   1075 	utoppy_add_32(sc, state);
   1076 
   1077 	err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r);
   1078 	if (err)
   1079 		return err;
   1080 
   1081 	return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO;
   1082 }
   1083 
   1084 static int
   1085 utoppy_check_ready(struct utoppy_softc *sc)
   1086 {
   1087 	uint16_t r;
   1088 	int err;
   1089 
   1090 	UTOPPY_OUT_INIT(sc);
   1091 
   1092 	err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r);
   1093 	if (err)
   1094 		return err;
   1095 
   1096 	return (r == UTOPPY_RESP_SUCCESS) ? 0 : EIO;
   1097 }
   1098 
   1099 static int
   1100 utoppy_cancel(struct utoppy_softc *sc)
   1101 {
   1102 	uint16_t r;
   1103 	int err, i;
   1104 
   1105 	/*
   1106 	 * Issue the cancel command serveral times. the Toppy doesn't
   1107 	 * always respond to the first.
   1108 	 */
   1109 	for (i = 0; i < 3; i++) {
   1110 		UTOPPY_OUT_INIT(sc);
   1111 		err = utoppy_command(sc, UTOPPY_CMD_CANCEL,
   1112 		    UTOPPY_SHORT_TIMEOUT, &r);
   1113 		if (err == 0 && r == UTOPPY_RESP_SUCCESS)
   1114 			break;
   1115 		err = ETIMEDOUT;
   1116 	}
   1117 
   1118 	if (err)
   1119 		return err;
   1120 
   1121 	/*
   1122 	 * Make sure turbo mode is off, otherwise the Toppy will not
   1123 	 * respond to remote control input.
   1124 	 */
   1125 	(void) utoppy_turbo_mode(sc, 0);
   1126 
   1127 	sc->sc_state = UTOPPY_STATE_IDLE;
   1128 	return 0;
   1129 }
   1130 
   1131 static int
   1132 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us)
   1133 {
   1134 	uint32_t hsize, hfree;
   1135 	uint16_t r;
   1136 	int err;
   1137 
   1138 	UTOPPY_OUT_INIT(sc);
   1139 	err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r);
   1140 	if (err)
   1141 		return err;
   1142 
   1143 	if (r != UTOPPY_RESP_STATS_DATA)
   1144 		return EIO;
   1145 
   1146 	if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree))
   1147 		return EIO;
   1148 
   1149 	us->us_hdd_size = hsize;
   1150 	us->us_hdd_size *= 1024;
   1151 	us->us_hdd_free = hfree;
   1152 	us->us_hdd_free *= 1024;
   1153 
   1154 	return 0;
   1155 }
   1156 
   1157 static int
   1158 utoppy_readdir_next(struct utoppy_softc *sc)
   1159 {
   1160 	uint16_t resp;
   1161 	int err;
   1162 
   1163 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n",
   1164 	    device_xname(sc->sc_dev)));
   1165 
   1166 	/*
   1167 	 * Fetch the next READDIR response
   1168 	 */
   1169 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
   1170 	if (err) {
   1171 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1172 		    "utoppy_recv_packet() returned %d\n",
   1173 		    device_xname(sc->sc_dev), err));
   1174 		if (err == EBADMSG) {
   1175 			UTOPPY_OUT_INIT(sc);
   1176 			utoppy_send_packet(sc, UTOPPY_RESP_ERROR,
   1177 			    UTOPPY_LONG_TIMEOUT);
   1178 		}
   1179 		utoppy_cancel(sc);
   1180 		return err;
   1181 	}
   1182 
   1183 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1184 	    "utoppy_recv_packet() returned %d, len %ld\n",
   1185 	    device_xname(sc->sc_dev), err, (u_long)sc->sc_in_len));
   1186 
   1187 	switch (resp) {
   1188 	case UTOPPY_RESP_READDIR_DATA:
   1189 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1190 		    "UTOPPY_RESP_READDIR_DATA\n", device_xname(sc->sc_dev)));
   1191 
   1192 		UTOPPY_OUT_INIT(sc);
   1193 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
   1194 		    UTOPPY_LONG_TIMEOUT);
   1195 		if (err) {
   1196 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1197 			    "utoppy_send_packet(ACK) returned %d\n",
   1198 			    device_xname(sc->sc_dev), err));
   1199 			utoppy_cancel(sc);
   1200 			return err;
   1201 		}
   1202 		sc->sc_state = UTOPPY_STATE_READDIR;
   1203 		sc->sc_in_offset = 0;
   1204 		break;
   1205 
   1206 	case UTOPPY_RESP_READDIR_END:
   1207 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1208 		    "UTOPPY_RESP_READDIR_END\n", device_xname(sc->sc_dev)));
   1209 
   1210 		UTOPPY_OUT_INIT(sc);
   1211 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
   1212 		sc->sc_state = UTOPPY_STATE_IDLE;
   1213 		sc->sc_in_len = 0;
   1214 		break;
   1215 
   1216 	default:
   1217 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
   1218 		    "bad response: 0x%x\n", device_xname(sc->sc_dev), resp));
   1219 		sc->sc_state = UTOPPY_STATE_IDLE;
   1220 		sc->sc_in_len = 0;
   1221 		return EIO;
   1222 	}
   1223 
   1224 	return 0;
   1225 }
   1226 
   1227 static size_t
   1228 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud)
   1229 {
   1230 	uint8_t ftype;
   1231 
   1232 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left"
   1233 	    " %d\n", device_xname(sc->sc_dev), (int)sc->sc_in_len));
   1234 
   1235 	if (utoppy_timestamp_decode(sc, &ud->ud_mtime) ||
   1236 	    utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) ||
   1237 	    utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) ||
   1238 	    utoppy_get_32(sc, &ud->ud_attributes)) {
   1239 		DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no "
   1240 		    "more to decode\n", device_xname(sc->sc_dev)));
   1241 		return 0;
   1242 	}
   1243 
   1244 	switch (ftype) {
   1245 	case UTOPPY_FTYPE_DIR:
   1246 		ud->ud_type = UTOPPY_DIRENT_DIRECTORY;
   1247 		break;
   1248 	case UTOPPY_FTYPE_FILE:
   1249 		ud->ud_type = UTOPPY_DIRENT_FILE;
   1250 		break;
   1251 	default:
   1252 		ud->ud_type = UTOPPY_DIRENT_UNKNOWN;
   1253 		break;
   1254 	}
   1255 
   1256 	DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', "
   1257 	    "size %lld, time 0x%08lx, attr 0x%08x\n", device_xname(sc->sc_dev),
   1258 	    (ftype == UTOPPY_FTYPE_DIR) ? "DIR" :
   1259 	    ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path,
   1260 	    ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes));
   1261 
   1262 	return 1;
   1263 }
   1264 
   1265 static int
   1266 utoppy_readfile_next(struct utoppy_softc *sc)
   1267 {
   1268 	uint64_t off;
   1269 	uint16_t resp;
   1270 	int err;
   1271 
   1272 	err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
   1273 	if (err) {
   1274 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1275 		    "utoppy_recv_packet() returned %d\n",
   1276 		    device_xname(sc->sc_dev), err));
   1277 		utoppy_cancel(sc);
   1278 		return err;
   1279 	}
   1280 
   1281 	switch (resp) {
   1282 	case UTOPPY_RESP_FILE_HEADER:
   1283 		/* ACK it */
   1284 		UTOPPY_OUT_INIT(sc);
   1285 		err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
   1286 		    UTOPPY_LONG_TIMEOUT);
   1287 		if (err) {
   1288 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1289 			    "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
   1290 			    device_xname(sc->sc_dev), err));
   1291 			utoppy_cancel(sc);
   1292 			return err;
   1293 		}
   1294 
   1295 		sc->sc_in_len = 0;
   1296 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1297 		    "FILE_HEADER done\n", device_xname(sc->sc_dev)));
   1298 		break;
   1299 
   1300 	case UTOPPY_RESP_FILE_DATA:
   1301 		/* Already ACK'd */
   1302 		if (utoppy_get_64(sc, &off)) {
   1303 			DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1304 			    "UTOPPY_RESP_FILE_DATA did not provide offset\n",
   1305 			    device_xname(sc->sc_dev)));
   1306 			utoppy_cancel(sc);
   1307 			return EBADMSG;
   1308 		}
   1309 
   1310 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1311 		    "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
   1312 		    device_xname(sc->sc_dev), off, (u_long)sc->sc_in_len));
   1313 		break;
   1314 
   1315 	case UTOPPY_RESP_FILE_END:
   1316 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
   1317 		    "UTOPPY_RESP_FILE_END: sending ACK\n",
   1318 		    device_xname(sc->sc_dev)));
   1319 		UTOPPY_OUT_INIT(sc);
   1320 		utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
   1321 		/*FALLTHROUGH*/
   1322 
   1323 	case UTOPPY_RESP_SUCCESS:
   1324 		sc->sc_state = UTOPPY_STATE_IDLE;
   1325 		(void) utoppy_turbo_mode(sc, 0);
   1326 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all "
   1327 		    "done\n", device_xname(sc->sc_dev)));
   1328 		break;
   1329 
   1330 	case UTOPPY_RESP_ERROR:
   1331 	default:
   1332 		DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad "
   1333 		    "response code 0x%0x\n", device_xname(sc->sc_dev), resp));
   1334 		utoppy_cancel(sc);
   1335 		return EIO;
   1336 	}
   1337 
   1338 	return 0;
   1339 }
   1340 
   1341 int
   1342 utoppyopen(dev_t dev, int flag, int mode,
   1343     struct lwp *l)
   1344 {
   1345 	struct utoppy_softc *sc;
   1346 	int error = 0;
   1347 
   1348 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
   1349 	if (sc == NULL)
   1350 		return ENXIO;
   1351 
   1352 	if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
   1353 		return ENXIO;
   1354 
   1355 	if (sc->sc_state != UTOPPY_STATE_CLOSED) {
   1356 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n",
   1357 		    device_xname(sc->sc_dev)));
   1358 		return EBUSY;
   1359 	}
   1360 
   1361 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n",
   1362 	    device_xname(sc->sc_dev)));
   1363 
   1364 	sc->sc_refcnt++;
   1365 	sc->sc_state = UTOPPY_STATE_OPENING;
   1366 	sc->sc_turbo_mode = 0;
   1367 	sc->sc_out_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP);
   1368 	if (sc->sc_out_data == NULL) {
   1369 		error = ENOMEM;
   1370 		goto error;
   1371 	}
   1372 
   1373 	sc->sc_in_data = kmem_alloc(UTOPPY_BSIZE + 1, KM_SLEEP);
   1374 	if (sc->sc_in_data == NULL) {
   1375 		kmem_free(sc->sc_out_data, UTOPPY_BSIZE + 1);
   1376 		sc->sc_out_data = NULL;
   1377 		error = ENOMEM;
   1378 		goto error;
   1379 	}
   1380 
   1381 	if ((error = utoppy_cancel(sc)) != 0)
   1382 		goto error;
   1383 
   1384 	if ((error = utoppy_check_ready(sc)) != 0) {
   1385 		DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()"
   1386 		    " returned %d\n", device_xname(sc->sc_dev), error));
   1387 	}
   1388 
   1389  error:
   1390 	sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE;
   1391 
   1392 	DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state "
   1393 	    "'%s'\n", device_xname(sc->sc_dev), error,
   1394 	    utoppy_state_string(sc->sc_state)));
   1395 
   1396 	if (--sc->sc_refcnt < 0)
   1397 		usb_detach_wakeupold(sc->sc_dev);
   1398 
   1399 	return error;
   1400 }
   1401 
   1402 int
   1403 utoppyclose(dev_t dev, int flag, int mode,
   1404     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 open:"
   1417 		    " %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 %ld, "
   1564 	    "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 %ld,"
   1611 	    " wr_size %lld, wr_offset %lld, err %d\n", device_xname(sc->sc_dev),
   1612 	    (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset, err));
   1613 
   1614 	if (err == 0 && sc->sc_wr_size == 0) {
   1615 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending "
   1616 		    "FILE_END...\n", device_xname(sc->sc_dev)));
   1617 		UTOPPY_OUT_INIT(sc);
   1618 		err = utoppy_command(sc, UTOPPY_RESP_FILE_END,
   1619 		    UTOPPY_LONG_TIMEOUT, &resp);
   1620 		if (err) {
   1621 			DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
   1622 			    "utoppy_command(UTOPPY_RESP_FILE_END) returned "
   1623 			    "%d\n", device_xname(sc->sc_dev), err));
   1624 
   1625 			utoppy_cancel(sc);
   1626 		}
   1627 
   1628 		sc->sc_state = UTOPPY_STATE_IDLE;
   1629 		DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n",
   1630 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state)));
   1631 	}
   1632 
   1633 	if (--sc->sc_refcnt < 0)
   1634 		usb_detach_wakeupold(sc->sc_dev);
   1635 
   1636 	return err;
   1637 }
   1638 
   1639 int
   1640 utoppyioctl(dev_t dev, u_long cmd, void *data, int flag,
   1641     struct lwp *l)
   1642 {
   1643 	struct utoppy_softc *sc;
   1644 	struct utoppy_rename *ur;
   1645 	struct utoppy_readfile *urf;
   1646 	struct utoppy_writefile *uw;
   1647 	char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp;
   1648 	uint16_t resp;
   1649 	int err;
   1650 
   1651 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
   1652 
   1653 	if (sc->sc_dying)
   1654 		return EIO;
   1655 
   1656 	DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
   1657 	    device_xname(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state)));
   1658 
   1659 	if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) {
   1660 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n",
   1661 		    device_xname(sc->sc_dev)));
   1662 		return EBUSY;
   1663 	}
   1664 
   1665 	sc->sc_refcnt++;
   1666 
   1667 	switch (cmd) {
   1668 	case UTOPPYIOTURBO:
   1669 		err = 0;
   1670 		sc->sc_turbo_mode = *((int *)data) ? 1 : 0;
   1671 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: "
   1672 		    "%s\n", device_xname(sc->sc_dev), sc->sc_turbo_mode ? "On" :
   1673 		    "Off"));
   1674 		break;
   1675 
   1676 	case UTOPPYIOCANCEL:
   1677 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
   1678 		    device_xname(sc->sc_dev)));
   1679 		err = utoppy_cancel(sc);
   1680 		break;
   1681 
   1682 	case UTOPPYIOREBOOT:
   1683 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
   1684 		    device_xname(sc->sc_dev)));
   1685 		UTOPPY_OUT_INIT(sc);
   1686 		err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT,
   1687 		    &resp);
   1688 		if (err)
   1689 			break;
   1690 
   1691 		if (resp != UTOPPY_RESP_SUCCESS)
   1692 			err = EIO;
   1693 		break;
   1694 
   1695 	case UTOPPYIOSTATS:
   1696 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
   1697 		    device_xname(sc->sc_dev)));
   1698 		err = utoppy_stats(sc, (struct utoppy_stats *)data);
   1699 		break;
   1700 
   1701 	case UTOPPYIORENAME:
   1702 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n",
   1703 		    device_xname(sc->sc_dev)));
   1704 		ur = (struct utoppy_rename *)data;
   1705 		UTOPPY_OUT_INIT(sc);
   1706 
   1707 		if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0)
   1708 			break;
   1709 		if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0)
   1710 			break;
   1711 
   1712 		err = utoppy_command(sc, UTOPPY_CMD_RENAME, UTOPPY_LONG_TIMEOUT,
   1713 		    &resp);
   1714 		if (err)
   1715 			break;
   1716 
   1717 		if (resp != UTOPPY_RESP_SUCCESS)
   1718 			err = EIO;
   1719 		break;
   1720 
   1721 	case UTOPPYIOMKDIR:
   1722 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
   1723 		    device_xname(sc->sc_dev)));
   1724 		UTOPPY_OUT_INIT(sc);
   1725 		err = utoppy_add_path(sc, *((const char **)data), 1);
   1726 		if (err)
   1727 			break;
   1728 
   1729 		err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT,
   1730 		    &resp);
   1731 		if (err)
   1732 			break;
   1733 
   1734 		if (resp != UTOPPY_RESP_SUCCESS)
   1735 			err = EIO;
   1736 		break;
   1737 
   1738 	case UTOPPYIODELETE:
   1739 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n",
   1740 		    device_xname(sc->sc_dev)));
   1741 		UTOPPY_OUT_INIT(sc);
   1742 		err = utoppy_add_path(sc, *((const char **)data), 0);
   1743 		if (err)
   1744 			break;
   1745 
   1746 		err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT,
   1747 		    &resp);
   1748 		if (err)
   1749 			break;
   1750 
   1751 		if (resp != UTOPPY_RESP_SUCCESS)
   1752 			err = EIO;
   1753 		break;
   1754 
   1755 	case UTOPPYIOREADDIR:
   1756 		DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
   1757 		    device_xname(sc->sc_dev)));
   1758 		UTOPPY_OUT_INIT(sc);
   1759 		err = utoppy_add_path(sc, *((const char **)data), 0);
   1760 		if (err) {
   1761 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
   1762 			    "utoppy_add_path() returned %d\n",
   1763 			    device_xname(sc->sc_dev), err));
   1764 			break;
   1765 		}
   1766 
   1767 		err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR,
   1768 		    UTOPPY_LONG_TIMEOUT);
   1769 		if (err != 0) {
   1770 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
   1771 			    "UTOPPY_CMD_READDIR returned %d\n",
   1772 			    device_xname(sc->sc_dev), err));
   1773 			break;
   1774 		}
   1775 
   1776 		err = utoppy_readdir_next(sc);
   1777 		if (err) {
   1778 			DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
   1779 			    "utoppy_readdir_next() returned %d\n",
   1780 			    device_xname(sc->sc_dev), err));
   1781 		}
   1782 		break;
   1783 
   1784 	case UTOPPYIOREADFILE:
   1785 		urf = (struct utoppy_readfile *)data;
   1786 
   1787 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE "
   1788 		    "%s, offset %lld\n", device_xname(sc->sc_dev), urf->ur_path,
   1789 		    urf->ur_offset));
   1790 
   1791 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
   1792 			break;
   1793 
   1794 		UTOPPY_OUT_INIT(sc);
   1795 		utoppy_add_8(sc, UTOPPY_FILE_READ);
   1796 
   1797 		if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0)
   1798 			break;
   1799 
   1800 		utoppy_add_64(sc, urf->ur_offset);
   1801 
   1802 		sc->sc_state = UTOPPY_STATE_READFILE;
   1803 		sc->sc_in_offset = 0;
   1804 
   1805 		err = utoppy_send_packet(sc, UTOPPY_CMD_FILE,
   1806 		    UTOPPY_LONG_TIMEOUT);
   1807 		if (err == 0)
   1808 			err = utoppy_readfile_next(sc);
   1809 		break;
   1810 
   1811 	case UTOPPYIOWRITEFILE:
   1812 		uw = (struct utoppy_writefile *)data;
   1813 
   1814 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
   1815 		    "%s, size %lld, offset %lld\n", device_xname(sc->sc_dev),
   1816 		    uw->uw_path, uw->uw_size, uw->uw_offset));
   1817 
   1818 		if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
   1819 			break;
   1820 
   1821 		UTOPPY_OUT_INIT(sc);
   1822 		utoppy_add_8(sc, UTOPPY_FILE_WRITE);
   1823 		uwfp = utoppy_current_ptr(sc->sc_out_data);
   1824 
   1825 		if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) {
   1826 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path() "
   1827 			    "returned %d\n", device_xname(sc->sc_dev), err));
   1828 			break;
   1829 		}
   1830 
   1831 		strncpy(uwf, &uwfp[2], sizeof(uwf));
   1832 		utoppy_add_64(sc, uw->uw_offset);
   1833 
   1834 		err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT,
   1835 		    &resp);
   1836 		if (err) {
   1837 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
   1838 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
   1839 			    "%d\n", device_xname(sc->sc_dev), err));
   1840 			break;
   1841 		}
   1842 		if (resp != UTOPPY_RESP_SUCCESS) {
   1843 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
   1844 			    "utoppy_command(UTOPPY_CMD_FILE) returned "
   1845 			    "bad response 0x%x\n", device_xname(sc->sc_dev),
   1846 			    resp));
   1847 			err = EIO;
   1848 			break;
   1849 		}
   1850 
   1851 		UTOPPY_OUT_INIT(sc);
   1852 		utoppy_timestamp_encode(sc, uw->uw_mtime);
   1853 		utoppy_add_8(sc, UTOPPY_FTYPE_FILE);
   1854 		utoppy_add_64(sc, uw->uw_size);
   1855 		utoppy_add_string(sc, uwf, sizeof(uwf));
   1856 		utoppy_add_32(sc, 0);
   1857 
   1858 		err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER,
   1859 		    UTOPPY_LONG_TIMEOUT, &resp);
   1860 		if (err) {
   1861 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
   1862 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
   1863 			    "returned %d\n", device_xname(sc->sc_dev), err));
   1864 			break;
   1865 		}
   1866 		if (resp != UTOPPY_RESP_SUCCESS) {
   1867 			DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
   1868 			    "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
   1869 			    "returned bad response 0x%x\n",
   1870 			    device_xname(sc->sc_dev), resp));
   1871 			err = EIO;
   1872 			break;
   1873 		}
   1874 
   1875 		sc->sc_wr_offset = uw->uw_offset;
   1876 		sc->sc_wr_size = uw->uw_size;
   1877 		sc->sc_state = UTOPPY_STATE_WRITEFILE;
   1878 
   1879 		DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to "
   1880 		    "%s. wr_offset %lld, wr_size %lld\n",
   1881 		    device_xname(sc->sc_dev), utoppy_state_string(sc->sc_state),
   1882 		    sc->sc_wr_offset, sc->sc_wr_size));
   1883 		break;
   1884 
   1885 	default:
   1886 		DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n",
   1887 		    device_xname(sc->sc_dev)));
   1888 		err = ENODEV;
   1889 		break;
   1890 	}
   1891 
   1892 	DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
   1893 	    device_xname(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
   1894 
   1895 	if (err)
   1896 		utoppy_cancel(sc);
   1897 
   1898 	if (--sc->sc_refcnt < 0)
   1899 		usb_detach_wakeupold(sc->sc_dev);
   1900 
   1901 	return err;
   1902 }
   1903