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