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