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