1 /* $NetBSD: utoppy.c,v 1.13 2009/09/23 19:07:19 plunky Exp $ */
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.13 2009/09/23 19:07:19 plunky Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/fcntl.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/ioctl.h>
45 #include <sys/vnode.h>
47 #include <dev/usb/usb.h>
48 #include <dev/usb/usbdi.h>
49 #include <dev/usb/usbdi_util.h>
50 #include <dev/usb/usbdevs.h>
51 #include <dev/usb/usb_quirks.h>
52 #include <dev/usb/utoppy.h>
56 #define UTOPPY_DBG_OPEN 0x0001
57 #define UTOPPY_DBG_CLOSE 0x0002
58 #define UTOPPY_DBG_READ 0x0004
59 #define UTOPPY_DBG_WRITE 0x0008
60 #define UTOPPY_DBG_IOCTL 0x0010
61 #define UTOPPY_DBG_SEND_PACKET 0x0020
62 #define UTOPPY_DBG_RECV_PACKET 0x0040
63 #define UTOPPY_DBG_ADDPATH 0x0080
64 #define UTOPPY_DBG_READDIR 0x0100
65 #define UTOPPY_DBG_DUMP 0x0200
66 #define DPRINTF(l, m) \
68 if (utoppy_debug & l) \
70 } while (/*CONSTCOND*/0)
71 static int utoppy_debug
= 0;
72 static void utoppy_dump_packet(const void *, size_t);
73 #define DDUMP_PACKET(p, l) \
75 if (utoppy_debug & UTOPPY_DBG_DUMP) \
76 utoppy_dump_packet((p), (l)); \
77 } while (/*CONSTCOND*/0)
79 #define DPRINTF(l, m) /* nothing */
80 #define DDUMP_PACKET(p, l) /* nothing */
84 #define UTOPPY_CONFIG_NO 1
85 #define UTOPPY_NUMENDPOINTS 2
87 #define UTOPPY_BSIZE 0xffff
88 #define UTOPPY_FRAG_SIZE 0x1000
89 #define UTOPPY_HEADER_SIZE 8
90 #define UTOPPY_SHORT_TIMEOUT (500) /* 0.5 seconds */
91 #define UTOPPY_LONG_TIMEOUT (10 * 1000) /* 10 seconds */
93 /* Protocol Commands and Responses */
94 #define UTOPPY_RESP_ERROR 0x0001
95 #define UTOPPY_CMD_ACK 0x0002
96 #define UTOPPY_RESP_SUCCESS UTOPPY_CMD_ACK
97 #define UTOPPY_CMD_CANCEL 0x0003
98 #define UTOPPY_CMD_READY 0x0100
99 #define UTOPPY_CMD_RESET 0x0101
100 #define UTOPPY_CMD_TURBO 0x0102
101 #define UTOPPY_CMD_STATS 0x1000
102 #define UTOPPY_RESP_STATS_DATA 0x1001
103 #define UTOPPY_CMD_READDIR 0x1002
104 #define UTOPPY_RESP_READDIR_DATA 0x1003
105 #define UTOPPY_RESP_READDIR_END 0x1004
106 #define UTOPPY_CMD_DELETE 0x1005
107 #define UTOPPY_CMD_RENAME 0x1006
108 #define UTOPPY_CMD_MKDIR 0x1007
109 #define UTOPPY_CMD_FILE 0x1008
110 #define UTOPPY_FILE_WRITE 0
111 #define UTOPPY_FILE_READ 1
112 #define UTOPPY_RESP_FILE_HEADER 0x1009
113 #define UTOPPY_RESP_FILE_DATA 0x100a
114 #define UTOPPY_RESP_FILE_END 0x100b
118 UTOPPY_STATE_OPENING
,
120 UTOPPY_STATE_READDIR
,
121 UTOPPY_STATE_READFILE
,
122 UTOPPY_STATE_WRITEFILE
125 struct utoppy_softc
{
126 USBBASEDEVICE sc_dev
;
127 usbd_device_handle sc_udev
; /* device */
128 usbd_interface_handle sc_iface
; /* interface */
132 enum utoppy_state sc_state
;
136 usbd_pipe_handle sc_out_pipe
; /* bulk out pipe */
137 usbd_xfer_handle sc_out_xfer
;
140 uint64_t sc_wr_offset
;
144 usbd_pipe_handle sc_in_pipe
; /* bulk in pipe */
145 usbd_xfer_handle sc_in_xfer
;
152 struct utoppy_header
{
159 #define UTOPPY_OUT_INIT(sc) \
161 struct utoppy_header *_h = sc->sc_out_data; \
163 } while (/*CONSTCOND*/0)
165 #define UTOPPY_MJD_1970 40587u /* MJD value for Jan 1 00:00:00 1970 */
167 #define UTOPPY_FTYPE_DIR 1
168 #define UTOPPY_FTYPE_FILE 2
170 #define UTOPPY_IN_DATA(sc) \
171 ((void*)&(((uint8_t*)(sc)->sc_in_data)[(sc)->sc_in_offset+UTOPPY_HEADER_SIZE]))
173 dev_type_open(utoppyopen
);
174 dev_type_close(utoppyclose
);
175 dev_type_read(utoppyread
);
176 dev_type_write(utoppywrite
);
177 dev_type_ioctl(utoppyioctl
);
179 const struct cdevsw utoppy_cdevsw
= {
180 utoppyopen
, utoppyclose
, utoppyread
, utoppywrite
, utoppyioctl
,
181 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_OTHER
,
184 #define UTOPPYUNIT(n) (minor(n))
186 USB_DECLARE_DRIVER(utoppy
);
190 USB_MATCH_START(utoppy
, uaa
);
192 if (uaa
->vendor
== USB_VENDOR_TOPFIELD
&&
193 uaa
->product
== USB_PRODUCT_TOPFIELD_TF5000PVR
)
194 return (UMATCH_VENDOR_PRODUCT
);
196 return (UMATCH_NONE
);
201 USB_ATTACH_START(utoppy
, sc
, uaa
);
202 usbd_device_handle dev
= uaa
->device
;
203 usbd_interface_handle iface
;
204 usb_endpoint_descriptor_t
*ed
;
214 devinfop
= usbd_devinfo_alloc(dev
, 0);
215 aprint_normal_dev(self
, "%s\n", devinfop
);
216 usbd_devinfo_free(devinfop
);
222 if (usbd_set_config_index(dev
, 0, 1)
223 || usbd_device2interface_handle(dev
, 0, &iface
)) {
224 aprint_error_dev(self
, "Configuration failed\n");
225 USB_ATTACH_ERROR_RETURN
;
229 (void) usbd_endpoint_count(iface
, &epcount
);
230 if (epcount
!= UTOPPY_NUMENDPOINTS
) {
231 aprint_error_dev(self
, "Expected %d endpoints, got %d\n",
232 UTOPPY_NUMENDPOINTS
, epcount
);
233 USB_ATTACH_ERROR_RETURN
;
239 for (i
= 0; i
< epcount
; i
++) {
240 ed
= usbd_interface2endpoint_descriptor(iface
, i
);
242 aprint_error_dev(self
, "couldn't get ep %d\n", i
);
243 USB_ATTACH_ERROR_RETURN
;
246 if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_IN
&&
247 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
248 sc
->sc_in
= ed
->bEndpointAddress
;
249 } else if (UE_GET_DIR(ed
->bEndpointAddress
) == UE_DIR_OUT
&&
250 UE_GET_XFERTYPE(ed
->bmAttributes
) == UE_BULK
) {
251 sc
->sc_out
= ed
->bEndpointAddress
;
255 if (sc
->sc_out
== -1 || sc
->sc_in
== -1) {
256 aprint_error_dev(self
,
257 "could not find bulk in/out endpoints\n");
259 USB_ATTACH_ERROR_RETURN
;
262 sc
->sc_iface
= iface
;
265 sc
->sc_out_xfer
= usbd_alloc_xfer(sc
->sc_udev
);
266 if (sc
->sc_out_xfer
== NULL
) {
267 aprint_error_dev(self
, "could not allocate bulk out xfer\n");
271 sc
->sc_out_buf
= usbd_alloc_buffer(sc
->sc_out_xfer
, UTOPPY_FRAG_SIZE
);
272 if (sc
->sc_out_buf
== NULL
) {
273 aprint_error_dev(self
, "could not allocate bulk out buffer\n");
277 sc
->sc_in_xfer
= usbd_alloc_xfer(sc
->sc_udev
);
278 if (sc
->sc_in_xfer
== NULL
) {
279 aprint_error_dev(self
, "could not allocate bulk in xfer\n");
283 sc
->sc_in_buf
= usbd_alloc_buffer(sc
->sc_in_xfer
, UTOPPY_FRAG_SIZE
);
284 if (sc
->sc_in_buf
== NULL
) {
285 aprint_error_dev(self
, "could not allocate bulk in buffer\n");
289 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
,
292 USB_ATTACH_SUCCESS_RETURN
;
294 fail2
: usbd_free_xfer(sc
->sc_in_xfer
);
295 sc
->sc_in_xfer
= NULL
;
297 fail1
: usbd_free_xfer(sc
->sc_out_xfer
);
298 sc
->sc_out_xfer
= NULL
;
300 fail0
: sc
->sc_dying
= 1;
301 USB_ATTACH_ERROR_RETURN
;
305 utoppy_activate(device_ptr_t self
, enum devact act
)
307 struct utoppy_softc
*sc
= device_private(self
);
310 case DVACT_DEACTIVATE
:
320 USB_DETACH_START(utoppy
, sc
);
325 if (sc
->sc_out_pipe
!= NULL
)
326 usbd_abort_pipe(sc
->sc_out_pipe
);
327 if (sc
->sc_in_pipe
!= NULL
)
328 usbd_abort_pipe(sc
->sc_in_pipe
);
330 if (sc
->sc_in_xfer
!= NULL
)
331 usbd_free_xfer(sc
->sc_in_xfer
);
332 if (sc
->sc_out_xfer
!= NULL
)
333 usbd_free_xfer(sc
->sc_out_xfer
);
336 if (--sc
->sc_refcnt
>= 0)
337 usb_detach_wait(USBDEV(sc
->sc_dev
));
340 /* locate the major number */
341 maj
= cdevsw_lookup_major(&utoppy_cdevsw
);
343 /* Nuke the vnodes for any open instances (calls close). */
345 vdevgone(maj
, mn
, mn
, VCHR
);
347 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
,
353 static const uint16_t utoppy_crc16_lookup
[] = {
354 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
355 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
356 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
357 0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
358 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
359 0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
360 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
361 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
362 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
363 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
364 0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
365 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
366 0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
367 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
368 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
369 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
370 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
371 0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
372 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
373 0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
374 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
375 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
376 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
377 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
378 0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
379 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
380 0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
381 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
382 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
383 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
384 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
385 0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
388 #define UTOPPY_CRC16(ccrc,b) \
389 (utoppy_crc16_lookup[((ccrc) ^ (b)) & 0xffu] ^ ((ccrc) >> 8))
391 static const int utoppy_usbdstatus_lookup
[] = {
392 0, /* USBD_NORMAL_COMPLETION */
393 EINPROGRESS
, /* USBD_IN_PROGRESS */
394 EALREADY
, /* USBD_PENDING_REQUESTS */
395 EAGAIN
, /* USBD_NOT_STARTED */
396 EINVAL
, /* USBD_INVAL */
397 ENOMEM
, /* USBD_NOMEM */
398 ECONNRESET
, /* USBD_CANCELLED */
399 EFAULT
, /* USBD_BAD_ADDRESS */
400 EBUSY
, /* USBD_IN_USE */
401 EADDRNOTAVAIL
, /* USBD_NO_ADDR */
402 ENETDOWN
, /* USBD_SET_ADDR_FAILED */
403 EIO
, /* USBD_NO_POWER */
404 EMLINK
, /* USBD_TOO_DEEP */
405 EIO
, /* USBD_IOERROR */
406 ENXIO
, /* USBD_NOT_CONFIGURED */
407 ETIMEDOUT
, /* USBD_TIMEOUT */
408 EBADMSG
, /* USBD_SHORT_XFER */
409 EHOSTDOWN
, /* USBD_STALLED */
410 EINTR
/* USBD_INTERRUPTED */
414 utoppy_usbd_status2errno(usbd_status err
)
417 if (err
>= USBD_ERROR_MAX
)
419 return (utoppy_usbdstatus_lookup
[err
]);
424 utoppy_state_string(enum utoppy_state state
)
429 case UTOPPY_STATE_CLOSED
:
432 case UTOPPY_STATE_OPENING
:
435 case UTOPPY_STATE_IDLE
:
438 case UTOPPY_STATE_READDIR
:
439 str
= "READ DIRECTORY";
441 case UTOPPY_STATE_READFILE
:
444 case UTOPPY_STATE_WRITEFILE
:
456 utoppy_dump_packet(const void *b
, size_t len
)
458 const uint8_t *buf
= b
, *l
;
469 for (i
= 0, l
= buf
; i
< len
; i
++) {
470 printf("%02x ", *buf
++);
472 if ((i
% 16) == 15) {
473 for (j
= 0; j
< 16; j
++) {
475 if (c
< ' ' || c
> 0x7e)
484 printf("%02x: ", (u_int
)i
+ 1);
488 while ((i
++ % 16) != 0)
494 if (c
< ' ' || c
> 0x7e)
505 * Very much like usbd_bulk_transfer(), except don't catch signals
508 utoppy_bulk_transfer_cb(usbd_xfer_handle xfer
,
509 usbd_private_handle priv
,
517 utoppy_bulk_transfer(usbd_xfer_handle xfer
, usbd_pipe_handle pipe
,
518 u_int16_t flags
, u_int32_t timeout
, void *buf
, u_int32_t
*size
,
524 usbd_setup_xfer(xfer
, pipe
, 0, buf
, *size
, flags
, timeout
,
525 utoppy_bulk_transfer_cb
);
527 err
= usbd_transfer(xfer
);
528 if (err
!= USBD_IN_PROGRESS
) {
532 error
= tsleep((void *)xfer
, PZERO
, lbl
, 0);
535 usbd_abort_pipe(pipe
);
536 return (USBD_INTERRUPTED
);
538 usbd_get_xfer_status(xfer
, NULL
, NULL
, size
, &err
);
543 utoppy_send_packet(struct utoppy_softc
*sc
, uint16_t cmd
, uint32_t timeout
)
545 struct utoppy_header
*h
;
549 uint8_t *data
, *e
, t1
, t2
;
553 DPRINTF(UTOPPY_DBG_SEND_PACKET
, ("%s: utoppy_send_packet: cmd 0x%04x, "
554 "len %d\n", USBDEVNAME(sc
->sc_dev
), (u_int
)cmd
, h
->h_len
));
557 len
= dlen
+ UTOPPY_HEADER_SIZE
;
564 if (len
>= UTOPPY_BSIZE
) {
565 DPRINTF(UTOPPY_DBG_SEND_PACKET
, ("%s: utoppy_send_packet: "
566 "packet too big (%d)\n", USBDEVNAME(sc
->sc_dev
), (int)len
));
570 h
->h_len
= htole16(dlen
+ UTOPPY_HEADER_SIZE
);
572 h
->h_cmd
= htole16(cmd
);
574 /* The command word is part of the CRC */
575 crc
= UTOPPY_CRC16(0, 0);
576 crc
= UTOPPY_CRC16(crc
, 0);
577 crc
= UTOPPY_CRC16(crc
, cmd
>> 8);
578 crc
= UTOPPY_CRC16(crc
, cmd
);
581 * If there is data following the header, calculate the CRC and
582 * byte-swap as we go.
586 e
= data
+ (dlen
& ~1);
591 crc
= UTOPPY_CRC16(crc
, t1
);
592 crc
= UTOPPY_CRC16(crc
, t2
);
599 crc
= UTOPPY_CRC16(crc
, t1
);
604 h
->h_crc
= htole16(crc
);
605 data
= sc
->sc_out_data
;
607 DPRINTF(UTOPPY_DBG_SEND_PACKET
, ("%s: utoppy_send_packet: total len "
608 "%d...\n", USBDEVNAME(sc
->sc_dev
), (int)len
));
609 DDUMP_PACKET(data
, len
);
614 thislen
= min(len
, UTOPPY_FRAG_SIZE
);
616 memcpy(sc
->sc_out_buf
, data
, thislen
);
618 err
= utoppy_bulk_transfer(sc
->sc_out_xfer
, sc
->sc_out_pipe
,
619 USBD_NO_COPY
, timeout
, sc
->sc_out_buf
, &thislen
,
622 if (thislen
!= min(len
, UTOPPY_FRAG_SIZE
)) {
623 DPRINTF(UTOPPY_DBG_SEND_PACKET
, ("%s: "
624 "utoppy_send_packet: sent %ld, err %d\n",
625 USBDEVNAME(sc
->sc_dev
), (u_long
)thislen
, err
));
632 } while (err
== 0 && len
);
634 DPRINTF(UTOPPY_DBG_SEND_PACKET
, ("%s: utoppy_send_packet: "
635 "usbd_bulk_transfer() returned %d.\n", USBDEVNAME(sc
->sc_dev
),err
));
637 return (err
? utoppy_usbd_status2errno(err
) : 0);
641 utoppy_recv_packet(struct utoppy_softc
*sc
, uint16_t *respp
, uint32_t timeout
)
643 struct utoppy_header
*h
;
645 uint32_t len
, thislen
, requested
, bytesleft
;
647 uint8_t *data
, *e
, t1
, t2
;
649 data
= sc
->sc_in_data
;
651 bytesleft
= UTOPPY_BSIZE
;
653 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: ...\n",
654 USBDEVNAME(sc
->sc_dev
)));
657 requested
= thislen
= min(bytesleft
, UTOPPY_FRAG_SIZE
);
659 err
= utoppy_bulk_transfer(sc
->sc_in_xfer
, sc
->sc_in_pipe
,
660 USBD_NO_COPY
| USBD_SHORT_XFER_OK
, timeout
, sc
->sc_in_buf
,
661 &thislen
, "utoppyrx");
663 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: "
664 "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
665 USBDEVNAME(sc
->sc_dev
), err
, (u_int
)thislen
, data
));
668 memcpy(data
, sc
->sc_in_buf
, thislen
);
669 DDUMP_PACKET(data
, thislen
);
671 bytesleft
-= thislen
;
674 } while (err
== 0 && bytesleft
&& thislen
== requested
);
677 return (utoppy_usbd_status2errno(err
));
681 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: received %d "
682 "bytes in total to %p\n", USBDEVNAME(sc
->sc_dev
), (u_int
)len
, h
));
683 DDUMP_PACKET(h
, len
);
685 if (len
< UTOPPY_HEADER_SIZE
|| len
< (uint32_t)le16toh(h
->h_len
)) {
686 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: bad "
687 " length (len %d, h_len %d)\n", USBDEVNAME(sc
->sc_dev
),
688 (int)len
, le16toh(h
->h_len
)));
692 len
= h
->h_len
= le16toh(h
->h_len
);
693 h
->h_crc
= le16toh(h
->h_crc
);
694 *respp
= h
->h_cmd
= le16toh(h
->h_cmd
);
695 h
->h_cmd2
= le16toh(h
->h_cmd2
);
698 * To maximise data throughput when transferring files, acknowledge
699 * data blocks as soon as we receive them. If we detect an error
700 * later on, we can always cancel.
702 if (*respp
== UTOPPY_RESP_FILE_DATA
) {
703 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: "
704 "ACKing file data\n", USBDEVNAME(sc
->sc_dev
)));
707 err
= utoppy_send_packet(sc
, UTOPPY_CMD_ACK
,
708 UTOPPY_SHORT_TIMEOUT
);
710 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: "
711 "utoppy_recv_packet: failed to ACK file data: %d\n",
712 USBDEVNAME(sc
->sc_dev
), err
));
717 /* The command word is part of the CRC */
718 crc
= UTOPPY_CRC16(0, h
->h_cmd2
>> 8);
719 crc
= UTOPPY_CRC16(crc
, h
->h_cmd2
);
720 crc
= UTOPPY_CRC16(crc
, h
->h_cmd
>> 8);
721 crc
= UTOPPY_CRC16(crc
, h
->h_cmd
);
724 * Extract any payload, byte-swapping and calculating the CRC16
727 if (len
> UTOPPY_HEADER_SIZE
) {
729 e
= data
+ ((len
& ~1) - UTOPPY_HEADER_SIZE
);
734 crc
= UTOPPY_CRC16(crc
, t2
);
735 crc
= UTOPPY_CRC16(crc
, t1
);
742 crc
= UTOPPY_CRC16(crc
, t1
);
747 sc
->sc_in_len
= (size_t) len
- UTOPPY_HEADER_SIZE
;
748 sc
->sc_in_offset
= 0;
750 DPRINTF(UTOPPY_DBG_RECV_PACKET
, ("%s: utoppy_recv_packet: len %d, "
751 "crc 0x%04x, hdrcrc 0x%04x\n", USBDEVNAME(sc
->sc_dev
),
752 (int)len
, crc
, h
->h_crc
));
753 DDUMP_PACKET(h
, len
);
755 return ((crc
== h
->h_crc
) ? 0 : EBADMSG
);
758 static __inline
void *
759 utoppy_current_ptr(void *b
)
761 struct utoppy_header
*h
= b
;
763 return (&h
->h_data
[h
->h_len
]);
767 utoppy_advance_ptr(void *b
, size_t len
)
769 struct utoppy_header
*h
= b
;
775 utoppy_add_8(struct utoppy_softc
*sc
, uint8_t v
)
777 struct utoppy_header
*h
= sc
->sc_out_data
;
780 p
= utoppy_current_ptr(h
);
782 utoppy_advance_ptr(h
, sizeof(v
));
786 utoppy_add_16(struct utoppy_softc
*sc
, uint16_t v
)
788 struct utoppy_header
*h
= sc
->sc_out_data
;
791 p
= utoppy_current_ptr(h
);
792 *p
++ = (uint8_t)(v
>> 8);
794 utoppy_advance_ptr(h
, sizeof(v
));
798 utoppy_add_32(struct utoppy_softc
*sc
, uint32_t v
)
800 struct utoppy_header
*h
= sc
->sc_out_data
;
803 p
= utoppy_current_ptr(h
);
804 *p
++ = (uint8_t)(v
>> 24);
805 *p
++ = (uint8_t)(v
>> 16);
806 *p
++ = (uint8_t)(v
>> 8);
808 utoppy_advance_ptr(h
, sizeof(v
));
812 utoppy_add_64(struct utoppy_softc
*sc
, uint64_t v
)
814 struct utoppy_header
*h
= sc
->sc_out_data
;
817 p
= utoppy_current_ptr(h
);
818 *p
++ = (uint8_t)(v
>> 56);
819 *p
++ = (uint8_t)(v
>> 48);
820 *p
++ = (uint8_t)(v
>> 40);
821 *p
++ = (uint8_t)(v
>> 32);
822 *p
++ = (uint8_t)(v
>> 24);
823 *p
++ = (uint8_t)(v
>> 16);
824 *p
++ = (uint8_t)(v
>> 8);
826 utoppy_advance_ptr(h
, sizeof(v
));
830 utoppy_add_string(struct utoppy_softc
*sc
, const char *str
, size_t len
)
832 struct utoppy_header
*h
= sc
->sc_out_data
;
835 p
= utoppy_current_ptr(h
);
837 strncpy(p
, str
, len
);
838 utoppy_advance_ptr(h
, len
);
842 utoppy_add_path(struct utoppy_softc
*sc
, const char *path
, int putlen
)
844 struct utoppy_header
*h
= sc
->sc_out_data
;
845 uint8_t *p
, *str
, *s
;
849 p
= utoppy_current_ptr(h
);
851 str
= putlen
? (p
+ sizeof(uint16_t)) : p
;
853 err
= copyinstr(path
, str
, UTOPPY_MAX_FILENAME_LEN
, &len
);
855 DPRINTF(UTOPPY_DBG_ADDPATH
, ("utoppy_add_path: err %d, len %d\n",
865 * copyinstr(9) has already copied the terminating NUL character,
866 * but we append another one in case we have to pad the length
872 * The Toppy uses backslash as the directory separator, so convert
873 * all forward slashes.
875 for (s
= &str
[len
- 2]; s
>= str
; s
--)
879 if ((len
+ h
->h_len
) & 1)
883 utoppy_add_16(sc
, len
);
885 utoppy_advance_ptr(h
, len
);
887 DPRINTF(UTOPPY_DBG_ADDPATH
, ("utoppy_add_path: final len %d\n",
894 utoppy_get_8(struct utoppy_softc
*sc
, uint8_t *vp
)
898 if (sc
->sc_in_len
< sizeof(*vp
))
901 p
= UTOPPY_IN_DATA(sc
);
903 sc
->sc_in_offset
+= sizeof(*vp
);
904 sc
->sc_in_len
-= sizeof(*vp
);
909 utoppy_get_16(struct utoppy_softc
*sc
, uint16_t *vp
)
914 if (sc
->sc_in_len
< sizeof(v
))
917 p
= UTOPPY_IN_DATA(sc
);
921 sc
->sc_in_offset
+= sizeof(v
);
922 sc
->sc_in_len
-= sizeof(v
);
927 utoppy_get_32(struct utoppy_softc
*sc
, uint32_t *vp
)
932 if (sc
->sc_in_len
< sizeof(v
))
935 p
= UTOPPY_IN_DATA(sc
);
941 sc
->sc_in_offset
+= sizeof(v
);
942 sc
->sc_in_len
-= sizeof(v
);
947 utoppy_get_64(struct utoppy_softc
*sc
, uint64_t *vp
)
952 if (sc
->sc_in_len
< sizeof(v
))
955 p
= UTOPPY_IN_DATA(sc
);
965 sc
->sc_in_offset
+= sizeof(v
);
966 sc
->sc_in_len
-= sizeof(v
);
971 utoppy_get_string(struct utoppy_softc
*sc
, char *str
, size_t len
)
975 if (sc
->sc_in_len
< len
)
979 p
= UTOPPY_IN_DATA(sc
);
980 strncpy(str
, p
, len
);
981 sc
->sc_in_offset
+= len
;
982 sc
->sc_in_len
-= len
;
987 utoppy_command(struct utoppy_softc
*sc
, uint16_t cmd
, int timeout
,
992 err
= utoppy_send_packet(sc
, cmd
, timeout
);
996 err
= utoppy_recv_packet(sc
, presp
, timeout
);
997 if (err
== EBADMSG
) {
999 utoppy_send_packet(sc
, UTOPPY_RESP_ERROR
, timeout
);
1006 utoppy_timestamp_decode(struct utoppy_softc
*sc
, time_t *tp
)
1009 uint8_t hour
, minute
, sec
;
1012 if (utoppy_get_16(sc
, &mjd
) || utoppy_get_8(sc
, &hour
) ||
1013 utoppy_get_8(sc
, &minute
) || utoppy_get_8(sc
, &sec
))
1016 if (mjd
== 0xffffu
&& hour
== 0xffu
&& minute
== 0xffu
&& sec
== 0xffu
){
1021 rv
= (mjd
< UTOPPY_MJD_1970
) ? UTOPPY_MJD_1970
: (uint32_t) mjd
;
1023 /* Calculate seconds since 1970 */
1024 rv
= (rv
- UTOPPY_MJD_1970
) * 60 * 60 * 24;
1026 /* Add in the hours, minutes, and seconds */
1027 rv
+= (uint32_t)hour
* 60 * 60;
1028 rv
+= (uint32_t)minute
* 60;
1036 utoppy_timestamp_encode(struct utoppy_softc
*sc
, time_t t
)
1038 u_int mjd
, hour
, minute
;
1040 mjd
= t
/ (60 * 60 * 24);
1041 t
-= mjd
* 60 * 60 * 24;
1043 hour
= t
/ (60 * 60);
1044 t
-= hour
* 60 * 60;
1049 utoppy_add_16(sc
, mjd
+ UTOPPY_MJD_1970
);
1050 utoppy_add_8(sc
, hour
);
1051 utoppy_add_8(sc
, minute
);
1052 utoppy_add_8(sc
, t
);
1056 utoppy_turbo_mode(struct utoppy_softc
*sc
, int state
)
1061 UTOPPY_OUT_INIT(sc
);
1062 utoppy_add_32(sc
, state
);
1064 err
= utoppy_command(sc
, UTOPPY_CMD_TURBO
, UTOPPY_SHORT_TIMEOUT
, &r
);
1068 return ((r
== UTOPPY_RESP_SUCCESS
) ? 0 : EIO
);
1072 utoppy_check_ready(struct utoppy_softc
*sc
)
1077 UTOPPY_OUT_INIT(sc
);
1079 err
= utoppy_command(sc
, UTOPPY_CMD_READY
, UTOPPY_LONG_TIMEOUT
, &r
);
1083 return ((r
== UTOPPY_RESP_SUCCESS
) ? 0 : EIO
);
1087 utoppy_cancel(struct utoppy_softc
*sc
)
1093 * Issue the cancel command serveral times. the Toppy doesn't
1094 * always respond to the first.
1096 for (i
= 0; i
< 3; i
++) {
1097 UTOPPY_OUT_INIT(sc
);
1098 err
= utoppy_command(sc
, UTOPPY_CMD_CANCEL
,
1099 UTOPPY_SHORT_TIMEOUT
, &r
);
1100 if (err
== 0 && r
== UTOPPY_RESP_SUCCESS
)
1109 * Make sure turbo mode is off, otherwise the Toppy will not
1110 * respond to remote control input.
1112 (void) utoppy_turbo_mode(sc
, 0);
1114 sc
->sc_state
= UTOPPY_STATE_IDLE
;
1119 utoppy_stats(struct utoppy_softc
*sc
, struct utoppy_stats
*us
)
1121 uint32_t hsize
, hfree
;
1125 UTOPPY_OUT_INIT(sc
);
1126 err
= utoppy_command(sc
, UTOPPY_CMD_STATS
, UTOPPY_LONG_TIMEOUT
, &r
);
1130 if (r
!= UTOPPY_RESP_STATS_DATA
)
1133 if (utoppy_get_32(sc
, &hsize
) || utoppy_get_32(sc
, &hfree
))
1136 us
->us_hdd_size
= hsize
;
1137 us
->us_hdd_size
*= 1024;
1138 us
->us_hdd_free
= hfree
;
1139 us
->us_hdd_free
*= 1024;
1145 utoppy_readdir_next(struct utoppy_softc
*sc
)
1150 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: running...\n",
1151 USBDEVNAME(sc
->sc_dev
)));
1154 * Fetch the next READDIR response
1156 err
= utoppy_recv_packet(sc
, &resp
, UTOPPY_LONG_TIMEOUT
);
1158 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1159 "utoppy_recv_packet() returned %d\n",
1160 USBDEVNAME(sc
->sc_dev
), err
));
1161 if (err
== EBADMSG
) {
1162 UTOPPY_OUT_INIT(sc
);
1163 utoppy_send_packet(sc
, UTOPPY_RESP_ERROR
,
1164 UTOPPY_LONG_TIMEOUT
);
1170 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1171 "utoppy_recv_packet() returned %d, len %ld\n",
1172 USBDEVNAME(sc
->sc_dev
), err
, (u_long
)sc
->sc_in_len
));
1175 case UTOPPY_RESP_READDIR_DATA
:
1176 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1177 "UTOPPY_RESP_READDIR_DATA\n", USBDEVNAME(sc
->sc_dev
)));
1179 UTOPPY_OUT_INIT(sc
);
1180 err
= utoppy_send_packet(sc
, UTOPPY_CMD_ACK
,
1181 UTOPPY_LONG_TIMEOUT
);
1183 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1184 "utoppy_send_packet(ACK) returned %d\n",
1185 USBDEVNAME(sc
->sc_dev
), err
));
1189 sc
->sc_state
= UTOPPY_STATE_READDIR
;
1190 sc
->sc_in_offset
= 0;
1193 case UTOPPY_RESP_READDIR_END
:
1194 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1195 "UTOPPY_RESP_READDIR_END\n", USBDEVNAME(sc
->sc_dev
)));
1197 UTOPPY_OUT_INIT(sc
);
1198 utoppy_send_packet(sc
, UTOPPY_CMD_ACK
, UTOPPY_SHORT_TIMEOUT
);
1199 sc
->sc_state
= UTOPPY_STATE_IDLE
;
1204 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_next: "
1205 "bad response: 0x%x\n", USBDEVNAME(sc
->sc_dev
), resp
));
1206 sc
->sc_state
= UTOPPY_STATE_IDLE
;
1215 utoppy_readdir_decode(struct utoppy_softc
*sc
, struct utoppy_dirent
*ud
)
1219 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_decode: bytes left"
1220 " %d\n", USBDEVNAME(sc
->sc_dev
), (int)sc
->sc_in_len
));
1222 if (utoppy_timestamp_decode(sc
, &ud
->ud_mtime
) ||
1223 utoppy_get_8(sc
, &ftype
) || utoppy_get_64(sc
, &ud
->ud_size
) ||
1224 utoppy_get_string(sc
, ud
->ud_path
, UTOPPY_MAX_FILENAME_LEN
+ 1) ||
1225 utoppy_get_32(sc
, &ud
->ud_attributes
)) {
1226 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_decode: no "
1227 "more to decode\n", USBDEVNAME(sc
->sc_dev
)));
1232 case UTOPPY_FTYPE_DIR
:
1233 ud
->ud_type
= UTOPPY_DIRENT_DIRECTORY
;
1235 case UTOPPY_FTYPE_FILE
:
1236 ud
->ud_type
= UTOPPY_DIRENT_FILE
;
1239 ud
->ud_type
= UTOPPY_DIRENT_UNKNOWN
;
1243 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppy_readdir_decode: %s '%s', "
1244 "size %lld, time 0x%08lx, attr 0x%08x\n", USBDEVNAME(sc
->sc_dev
),
1245 (ftype
== UTOPPY_FTYPE_DIR
) ? "DIR" :
1246 ((ftype
== UTOPPY_FTYPE_FILE
) ? "FILE" : "UNKNOWN"), ud
->ud_path
,
1247 ud
->ud_size
, (u_long
)ud
->ud_mtime
, ud
->ud_attributes
));
1253 utoppy_readfile_next(struct utoppy_softc
*sc
)
1259 err
= utoppy_recv_packet(sc
, &resp
, UTOPPY_LONG_TIMEOUT
);
1261 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1262 "utoppy_recv_packet() returned %d\n",
1263 USBDEVNAME(sc
->sc_dev
), err
));
1269 case UTOPPY_RESP_FILE_HEADER
:
1271 UTOPPY_OUT_INIT(sc
);
1272 err
= utoppy_send_packet(sc
, UTOPPY_CMD_ACK
,
1273 UTOPPY_LONG_TIMEOUT
);
1275 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1276 "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
1277 USBDEVNAME(sc
->sc_dev
), err
));
1283 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1284 "FILE_HEADER done\n", USBDEVNAME(sc
->sc_dev
)));
1287 case UTOPPY_RESP_FILE_DATA
:
1289 if (utoppy_get_64(sc
, &off
)) {
1290 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1291 "UTOPPY_RESP_FILE_DATA did not provide offset\n",
1292 USBDEVNAME(sc
->sc_dev
)));
1297 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1298 "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
1299 USBDEVNAME(sc
->sc_dev
), off
, (u_long
)sc
->sc_in_len
));
1302 case UTOPPY_RESP_FILE_END
:
1303 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: "
1304 "UTOPPY_RESP_FILE_END: sending ACK\n",
1305 USBDEVNAME(sc
->sc_dev
)));
1306 UTOPPY_OUT_INIT(sc
);
1307 utoppy_send_packet(sc
, UTOPPY_CMD_ACK
, UTOPPY_SHORT_TIMEOUT
);
1310 case UTOPPY_RESP_SUCCESS
:
1311 sc
->sc_state
= UTOPPY_STATE_IDLE
;
1312 (void) utoppy_turbo_mode(sc
, 0);
1313 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: all "
1314 "done\n", USBDEVNAME(sc
->sc_dev
)));
1317 case UTOPPY_RESP_ERROR
:
1319 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppy_readfile_next: bad "
1320 "response code 0x%0x\n", USBDEVNAME(sc
->sc_dev
), resp
));
1329 utoppyopen(dev_t dev
, int flag
, int mode
,
1332 struct utoppy_softc
*sc
;
1335 USB_GET_SC_OPEN(utoppy
, UTOPPYUNIT(dev
), sc
);
1337 if (sc
== NULL
|| sc
->sc_iface
== NULL
|| sc
->sc_dying
)
1340 if (sc
->sc_state
!= UTOPPY_STATE_CLOSED
) {
1341 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: already open\n",
1342 USBDEVNAME(sc
->sc_dev
)));
1346 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: opening...\n",
1347 USBDEVNAME(sc
->sc_dev
)));
1350 sc
->sc_state
= UTOPPY_STATE_OPENING
;
1351 sc
->sc_turbo_mode
= 0;
1352 sc
->sc_out_pipe
= NULL
;
1353 sc
->sc_in_pipe
= NULL
;
1355 if (usbd_open_pipe(sc
->sc_iface
, sc
->sc_out
, 0, &sc
->sc_out_pipe
)) {
1356 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: usbd_open_pipe(OUT) "
1357 "failed\n", USBDEVNAME(sc
->sc_dev
)));
1362 if (usbd_open_pipe(sc
->sc_iface
, sc
->sc_in
, 0, &sc
->sc_in_pipe
)) {
1363 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: usbd_open_pipe(IN) "
1364 "failed\n", USBDEVNAME(sc
->sc_dev
)));
1366 usbd_close_pipe(sc
->sc_out_pipe
);
1367 sc
->sc_out_pipe
= NULL
;
1371 sc
->sc_out_data
= malloc(UTOPPY_BSIZE
+ 1, M_DEVBUF
, M_WAITOK
);
1372 if (sc
->sc_out_data
== NULL
) {
1377 sc
->sc_in_data
= malloc(UTOPPY_BSIZE
+ 1, M_DEVBUF
, M_WAITOK
);
1378 if (sc
->sc_in_data
== NULL
) {
1379 free(sc
->sc_out_data
, M_DEVBUF
);
1380 sc
->sc_out_data
= NULL
;
1385 if ((error
= utoppy_cancel(sc
)) != 0)
1388 if ((error
= utoppy_check_ready(sc
)) != 0) {
1389 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: utoppy_check_ready()"
1390 " returned %d\n", USBDEVNAME(sc
->sc_dev
), error
));
1392 usbd_abort_pipe(sc
->sc_out_pipe
);
1393 usbd_close_pipe(sc
->sc_out_pipe
);
1394 sc
->sc_out_pipe
= NULL
;
1395 usbd_abort_pipe(sc
->sc_in_pipe
);
1396 usbd_close_pipe(sc
->sc_in_pipe
);
1397 sc
->sc_in_pipe
= NULL
;
1401 sc
->sc_state
= error
? UTOPPY_STATE_CLOSED
: UTOPPY_STATE_IDLE
;
1403 DPRINTF(UTOPPY_DBG_OPEN
, ("%s: utoppyopen: done. error %d, new state "
1404 "'%s'\n", USBDEVNAME(sc
->sc_dev
), error
,
1405 utoppy_state_string(sc
->sc_state
)));
1407 if (--sc
->sc_refcnt
< 0)
1408 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
1414 utoppyclose(dev_t dev
, int flag
, int mode
,
1417 struct utoppy_softc
*sc
;
1420 USB_GET_SC(utoppy
, UTOPPYUNIT(dev
), sc
);
1422 DPRINTF(UTOPPY_DBG_CLOSE
, ("%s: utoppyclose: closing...\n",
1423 USBDEVNAME(sc
->sc_dev
)));
1425 if (sc
->sc_state
< UTOPPY_STATE_IDLE
) {
1426 /* We are being forced to close before the open completed. */
1427 DPRINTF(UTOPPY_DBG_CLOSE
, ("%s: utoppyclose: not properly open:"
1428 " %s\n", USBDEVNAME(sc
->sc_dev
),
1429 utoppy_state_string(sc
->sc_state
)));
1433 if (sc
->sc_out_data
)
1434 (void) utoppy_cancel(sc
);
1436 if (sc
->sc_out_pipe
!= NULL
) {
1437 if ((err
= usbd_abort_pipe(sc
->sc_out_pipe
)) != 0)
1438 printf("usbd_abort_pipe(OUT) returned %d\n", err
);
1439 if ((err
= usbd_close_pipe(sc
->sc_out_pipe
)) != 0)
1440 printf("usbd_close_pipe(OUT) returned %d\n", err
);
1441 sc
->sc_out_pipe
= NULL
;
1444 if (sc
->sc_in_pipe
!= NULL
) {
1445 if ((err
= usbd_abort_pipe(sc
->sc_in_pipe
)) != 0)
1446 printf("usbd_abort_pipe(IN) returned %d\n", err
);
1447 if ((err
= usbd_close_pipe(sc
->sc_in_pipe
)) != 0)
1448 printf("usbd_close_pipe(IN) returned %d\n", err
);
1449 sc
->sc_in_pipe
= NULL
;
1452 if (sc
->sc_out_data
) {
1453 free(sc
->sc_out_data
, M_DEVBUF
);
1454 sc
->sc_out_data
= NULL
;
1457 if (sc
->sc_in_data
) {
1458 free(sc
->sc_in_data
, M_DEVBUF
);
1459 sc
->sc_in_data
= NULL
;
1462 sc
->sc_state
= UTOPPY_STATE_CLOSED
;
1464 DPRINTF(UTOPPY_DBG_CLOSE
, ("%s: utoppyclose: done.\n",
1465 USBDEVNAME(sc
->sc_dev
)));
1471 utoppyread(dev_t dev
, struct uio
*uio
, int flags
)
1473 struct utoppy_softc
*sc
;
1474 struct utoppy_dirent ud
;
1478 USB_GET_SC(utoppy
, UTOPPYUNIT(dev
), sc
);
1485 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppyread: reading: state '%s'\n",
1486 USBDEVNAME(sc
->sc_dev
), utoppy_state_string(sc
->sc_state
)));
1488 switch (sc
->sc_state
) {
1489 case UTOPPY_STATE_READDIR
:
1491 while (err
== 0 && uio
->uio_resid
>= sizeof(ud
) &&
1492 sc
->sc_state
!= UTOPPY_STATE_IDLE
) {
1493 if (utoppy_readdir_decode(sc
, &ud
) == 0)
1494 err
= utoppy_readdir_next(sc
);
1496 if ((err
= uiomove(&ud
, sizeof(ud
), uio
)) != 0)
1501 case UTOPPY_STATE_READFILE
:
1503 while (err
== 0 && uio
->uio_resid
> 0 &&
1504 sc
->sc_state
!= UTOPPY_STATE_IDLE
) {
1505 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppyread: READFILE: "
1506 "resid %ld, bytes_left %ld\n",
1507 USBDEVNAME(sc
->sc_dev
), (u_long
)uio
->uio_resid
,
1508 (u_long
)sc
->sc_in_len
));
1510 if (sc
->sc_in_len
== 0 &&
1511 (err
= utoppy_readfile_next(sc
)) != 0) {
1512 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppyread: "
1513 "READFILE: utoppy_readfile_next returned "
1514 "%d\n", USBDEVNAME(sc
->sc_dev
), err
));
1518 len
= min(uio
->uio_resid
, sc
->sc_in_len
);
1520 err
= uiomove(UTOPPY_IN_DATA(sc
), len
, uio
);
1522 sc
->sc_in_offset
+= len
;
1523 sc
->sc_in_len
-= len
;
1529 case UTOPPY_STATE_IDLE
:
1533 case UTOPPY_STATE_WRITEFILE
:
1542 DPRINTF(UTOPPY_DBG_READ
, ("%s: utoppyread: done. err %d, state '%s'\n",
1543 USBDEVNAME(sc
->sc_dev
), err
, utoppy_state_string(sc
->sc_state
)));
1545 if (--sc
->sc_refcnt
< 0)
1546 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
1552 utoppywrite(dev_t dev
, struct uio
*uio
, int flags
)
1554 struct utoppy_softc
*sc
;
1559 USB_GET_SC(utoppy
, UTOPPYUNIT(dev
), sc
);
1564 switch(sc
->sc_state
) {
1565 case UTOPPY_STATE_WRITEFILE
:
1568 case UTOPPY_STATE_IDLE
:
1578 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: PRE-WRITEFILE: resid %ld, "
1579 "wr_size %lld, wr_offset %lld\n", USBDEVNAME(sc
->sc_dev
),
1580 (u_long
)uio
->uio_resid
, sc
->sc_wr_size
, sc
->sc_wr_offset
));
1582 while (sc
->sc_state
== UTOPPY_STATE_WRITEFILE
&&
1583 (len
= min(uio
->uio_resid
, sc
->sc_wr_size
)) != 0) {
1585 len
= min(len
, UTOPPY_BSIZE
- (UTOPPY_HEADER_SIZE
+
1586 sizeof(uint64_t) + 3));
1588 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: uiomove(%ld)\n",
1589 USBDEVNAME(sc
->sc_dev
), (u_long
)len
));
1591 UTOPPY_OUT_INIT(sc
);
1592 utoppy_add_64(sc
, sc
->sc_wr_offset
);
1594 err
= uiomove(utoppy_current_ptr(sc
->sc_out_data
), len
, uio
);
1596 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: uiomove() "
1597 "returned %d\n", USBDEVNAME(sc
->sc_dev
), err
));
1601 utoppy_advance_ptr(sc
->sc_out_data
, len
);
1603 err
= utoppy_command(sc
, UTOPPY_RESP_FILE_DATA
,
1604 UTOPPY_LONG_TIMEOUT
, &resp
);
1606 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: "
1607 "utoppy_command(UTOPPY_RESP_FILE_DATA) "
1608 "returned %d\n", USBDEVNAME(sc
->sc_dev
), err
));
1611 if (resp
!= UTOPPY_RESP_SUCCESS
) {
1612 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: "
1613 "utoppy_command(UTOPPY_RESP_FILE_DATA) returned "
1614 "bad response 0x%x\n", USBDEVNAME(sc
->sc_dev
),
1621 sc
->sc_wr_offset
+= len
;
1622 sc
->sc_wr_size
-= len
;
1625 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: POST-WRITEFILE: resid %ld,"
1626 " wr_size %lld, wr_offset %lld, err %d\n", USBDEVNAME(sc
->sc_dev
),
1627 (u_long
)uio
->uio_resid
, sc
->sc_wr_size
, sc
->sc_wr_offset
, err
));
1629 if (err
== 0 && sc
->sc_wr_size
== 0) {
1630 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: sending "
1631 "FILE_END...\n", USBDEVNAME(sc
->sc_dev
)));
1632 UTOPPY_OUT_INIT(sc
);
1633 err
= utoppy_command(sc
, UTOPPY_RESP_FILE_END
,
1634 UTOPPY_LONG_TIMEOUT
, &resp
);
1636 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: "
1637 "utoppy_command(UTOPPY_RESP_FILE_END) returned "
1638 "%d\n", USBDEVNAME(sc
->sc_dev
), err
));
1643 sc
->sc_state
= UTOPPY_STATE_IDLE
;
1644 DPRINTF(UTOPPY_DBG_WRITE
, ("%s: utoppywrite: state %s\n",
1645 USBDEVNAME(sc
->sc_dev
), utoppy_state_string(sc
->sc_state
)));
1648 if (--sc
->sc_refcnt
< 0)
1649 usb_detach_wakeup(USBDEV(sc
->sc_dev
));
1655 utoppyioctl(dev_t dev
, u_long cmd
, void *data
, int flag
,
1658 struct utoppy_softc
*sc
;
1659 struct utoppy_rename
*ur
;
1660 struct utoppy_readfile
*urf
;
1661 struct utoppy_writefile
*uw
;
1662 char uwf
[UTOPPY_MAX_FILENAME_LEN
+ 1], *uwfp
;
1666 USB_GET_SC(utoppy
, UTOPPYUNIT(dev
), sc
);
1671 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1672 USBDEVNAME(sc
->sc_dev
), cmd
, utoppy_state_string(sc
->sc_state
)));
1674 if (sc
->sc_state
!= UTOPPY_STATE_IDLE
&& cmd
!= UTOPPYIOCANCEL
) {
1675 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: still busy.\n",
1676 USBDEVNAME(sc
->sc_dev
)));
1685 sc
->sc_turbo_mode
= *((int *)data
) ? 1 : 0;
1686 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOTURBO: "
1687 "%s\n", USBDEVNAME(sc
->sc_dev
), sc
->sc_turbo_mode
? "On" :
1691 case UTOPPYIOCANCEL
:
1692 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
1693 USBDEVNAME(sc
->sc_dev
)));
1694 err
= utoppy_cancel(sc
);
1697 case UTOPPYIOREBOOT
:
1698 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1699 USBDEVNAME(sc
->sc_dev
)));
1700 UTOPPY_OUT_INIT(sc
);
1701 err
= utoppy_command(sc
, UTOPPY_CMD_RESET
, UTOPPY_LONG_TIMEOUT
,
1706 if (resp
!= UTOPPY_RESP_SUCCESS
)
1711 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
1712 USBDEVNAME(sc
->sc_dev
)));
1713 err
= utoppy_stats(sc
, (struct utoppy_stats
*)data
);
1716 case UTOPPYIORENAME
:
1717 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIORENAME\n",
1718 USBDEVNAME(sc
->sc_dev
)));
1719 ur
= (struct utoppy_rename
*)data
;
1720 UTOPPY_OUT_INIT(sc
);
1722 if ((err
= utoppy_add_path(sc
, ur
->ur_old_path
, 1)) != 0)
1724 if ((err
= utoppy_add_path(sc
, ur
->ur_new_path
, 1)) != 0)
1727 err
= utoppy_command(sc
, UTOPPY_CMD_RENAME
, UTOPPY_LONG_TIMEOUT
,
1732 if (resp
!= UTOPPY_RESP_SUCCESS
)
1737 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
1738 USBDEVNAME(sc
->sc_dev
)));
1739 UTOPPY_OUT_INIT(sc
);
1740 err
= utoppy_add_path(sc
, *((const char **)data
), 1);
1744 err
= utoppy_command(sc
, UTOPPY_CMD_MKDIR
, UTOPPY_LONG_TIMEOUT
,
1749 if (resp
!= UTOPPY_RESP_SUCCESS
)
1753 case UTOPPYIODELETE
:
1754 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIODELETE\n",
1755 USBDEVNAME(sc
->sc_dev
)));
1756 UTOPPY_OUT_INIT(sc
);
1757 err
= utoppy_add_path(sc
, *((const char **)data
), 0);
1761 err
= utoppy_command(sc
, UTOPPY_CMD_DELETE
, UTOPPY_LONG_TIMEOUT
,
1766 if (resp
!= UTOPPY_RESP_SUCCESS
)
1770 case UTOPPYIOREADDIR
:
1771 DPRINTF(UTOPPY_DBG_IOCTL
, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
1772 USBDEVNAME(sc
->sc_dev
)));
1773 UTOPPY_OUT_INIT(sc
);
1774 err
= utoppy_add_path(sc
, *((const char **)data
), 0);
1776 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppyioctl: "
1777 "utoppy_add_path() returned %d\n",
1778 USBDEVNAME(sc
->sc_dev
), err
));
1782 err
= utoppy_send_packet(sc
, UTOPPY_CMD_READDIR
,
1783 UTOPPY_LONG_TIMEOUT
);
1785 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppyioctl: "
1786 "UTOPPY_CMD_READDIR returned %d\n",
1787 USBDEVNAME(sc
->sc_dev
), err
));
1791 err
= utoppy_readdir_next(sc
);
1793 DPRINTF(UTOPPY_DBG_READDIR
, ("%s: utoppyioctl: "
1794 "utoppy_readdir_next() returned %d\n",
1795 USBDEVNAME(sc
->sc_dev
), err
));
1799 case UTOPPYIOREADFILE
:
1800 urf
= (struct utoppy_readfile
*)data
;
1802 DPRINTF(UTOPPY_DBG_IOCTL
,("%s: utoppyioctl: UTOPPYIOREADFILE "
1803 "%s, offset %lld\n", USBDEVNAME(sc
->sc_dev
), urf
->ur_path
,
1806 if ((err
= utoppy_turbo_mode(sc
, sc
->sc_turbo_mode
)) != 0)
1809 UTOPPY_OUT_INIT(sc
);
1810 utoppy_add_8(sc
, UTOPPY_FILE_READ
);
1812 if ((err
= utoppy_add_path(sc
, urf
->ur_path
, 1)) != 0)
1815 utoppy_add_64(sc
, urf
->ur_offset
);
1817 sc
->sc_state
= UTOPPY_STATE_READFILE
;
1818 sc
->sc_in_offset
= 0;
1820 err
= utoppy_send_packet(sc
, UTOPPY_CMD_FILE
,
1821 UTOPPY_LONG_TIMEOUT
);
1823 err
= utoppy_readfile_next(sc
);
1826 case UTOPPYIOWRITEFILE
:
1827 uw
= (struct utoppy_writefile
*)data
;
1829 DPRINTF(UTOPPY_DBG_IOCTL
,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
1830 "%s, size %lld, offset %lld\n", USBDEVNAME(sc
->sc_dev
),
1831 uw
->uw_path
, uw
->uw_size
, uw
->uw_offset
));
1833 if ((err
= utoppy_turbo_mode(sc
, sc
->sc_turbo_mode
)) != 0)
1836 UTOPPY_OUT_INIT(sc
);
1837 utoppy_add_8(sc
, UTOPPY_FILE_WRITE
);
1838 uwfp
= utoppy_current_ptr(sc
->sc_out_data
);
1840 if ((err
= utoppy_add_path(sc
, uw
->uw_path
, 1)) != 0) {
1841 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: add_path() "
1842 "returned %d\n", USBDEVNAME(sc
->sc_dev
), err
));
1846 strncpy(uwf
, &uwfp
[2], sizeof(uwf
));
1847 utoppy_add_64(sc
, uw
->uw_offset
);
1849 err
= utoppy_command(sc
, UTOPPY_CMD_FILE
, UTOPPY_LONG_TIMEOUT
,
1852 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: "
1853 "utoppy_command(UTOPPY_CMD_FILE) returned "
1854 "%d\n", USBDEVNAME(sc
->sc_dev
), err
));
1857 if (resp
!= UTOPPY_RESP_SUCCESS
) {
1858 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: "
1859 "utoppy_command(UTOPPY_CMD_FILE) returned "
1860 "bad response 0x%x\n", USBDEVNAME(sc
->sc_dev
),
1866 UTOPPY_OUT_INIT(sc
);
1867 utoppy_timestamp_encode(sc
, uw
->uw_mtime
);
1868 utoppy_add_8(sc
, UTOPPY_FTYPE_FILE
);
1869 utoppy_add_64(sc
, uw
->uw_size
);
1870 utoppy_add_string(sc
, uwf
, sizeof(uwf
));
1871 utoppy_add_32(sc
, 0);
1873 err
= utoppy_command(sc
, UTOPPY_RESP_FILE_HEADER
,
1874 UTOPPY_LONG_TIMEOUT
, &resp
);
1876 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: "
1877 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1878 "returned %d\n", USBDEVNAME(sc
->sc_dev
), err
));
1881 if (resp
!= UTOPPY_RESP_SUCCESS
) {
1882 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: "
1883 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1884 "returned bad response 0x%x\n",
1885 USBDEVNAME(sc
->sc_dev
), resp
));
1890 sc
->sc_wr_offset
= uw
->uw_offset
;
1891 sc
->sc_wr_size
= uw
->uw_size
;
1892 sc
->sc_state
= UTOPPY_STATE_WRITEFILE
;
1894 DPRINTF(UTOPPY_DBG_WRITE
,("%s: utoppyioctl: Changing state to "
1895 "%s. wr_offset %lld, wr_size %lld\n",
1896 USBDEVNAME(sc
->sc_dev
), utoppy_state_string(sc
->sc_state
),
1897 sc
->sc_wr_offset
, sc
->sc_wr_size
));
1901 DPRINTF(UTOPPY_DBG_IOCTL
,("%s: utoppyioctl: Invalid cmd\n",
1902 USBDEVNAME(sc
->sc_dev
)));
1907 DPRINTF(UTOPPY_DBG_IOCTL
,("%s: utoppyioctl: done. err %d, state '%s'\n",
1908 USBDEVNAME(sc
->sc_dev
), err
, utoppy_state_string(sc
->sc_state
)));
1913 if (--sc
->sc_refcnt
< 0)
1914 usb_detach_wakeup(USBDEV(sc
->sc_dev
));