utoppy.c revision 1.5 1 /* $NetBSD: utoppy.c,v 1.5 2006/04/11 23:08:08 scw 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.5 2006/04/11 23:08:08 scw 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;
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(0, h->h_cmd2 >> 8);
724 crc = UTOPPY_CRC16(crc, 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 goto done;
1373 }
1374
1375 sc->sc_out_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1376 if (sc->sc_out_data == NULL) {
1377 error = ENOMEM;
1378 goto error;
1379 }
1380
1381 sc->sc_in_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1382 if (sc->sc_in_data == NULL) {
1383 free(sc->sc_out_data, M_DEVBUF);
1384 sc->sc_out_data = NULL;
1385 error = ENOMEM;
1386 goto error;
1387 }
1388
1389 if ((error = utoppy_cancel(sc)) != 0)
1390 goto error;
1391
1392 if ((error = utoppy_check_ready(sc)) != 0) {
1393 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()"
1394 " returned %d\n", USBDEVNAME(sc->sc_dev), error));
1395 error:
1396 usbd_abort_pipe(sc->sc_out_pipe);
1397 usbd_close_pipe(sc->sc_out_pipe);
1398 sc->sc_out_pipe = NULL;
1399 usbd_abort_pipe(sc->sc_in_pipe);
1400 usbd_close_pipe(sc->sc_in_pipe);
1401 sc->sc_in_pipe = NULL;
1402 }
1403
1404 done:
1405 sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE;
1406
1407 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state "
1408 "'%s'\n", USBDEVNAME(sc->sc_dev), error,
1409 utoppy_state_string(sc->sc_state)));
1410
1411 if (--sc->sc_refcnt < 0)
1412 usb_detach_wakeup(USBDEV(sc->sc_dev));
1413
1414 return (error);
1415 }
1416
1417 int
1418 utoppyclose(dev_t dev, int flag, int mode, struct lwp *l)
1419 {
1420 struct utoppy_softc *sc;
1421 usbd_status err;
1422
1423 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1424
1425 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n",
1426 USBDEVNAME(sc->sc_dev)));
1427
1428 if (sc->sc_state < UTOPPY_STATE_IDLE) {
1429 /* We are being forced to close before the open completed. */
1430 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly open:"
1431 " %s\n", USBDEVNAME(sc->sc_dev),
1432 utoppy_state_string(sc->sc_state)));
1433 return (0);
1434 }
1435
1436 if (sc->sc_out_data)
1437 (void) utoppy_cancel(sc);
1438
1439 if (sc->sc_out_pipe != NULL) {
1440 if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
1441 printf("usbd_abort_pipe(OUT) returned %d\n", err);
1442 if ((err = usbd_close_pipe(sc->sc_out_pipe)) != 0)
1443 printf("usbd_close_pipe(OUT) returned %d\n", err);
1444 sc->sc_out_pipe = NULL;
1445 }
1446
1447 if (sc->sc_in_pipe != NULL) {
1448 if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
1449 printf("usbd_abort_pipe(IN) returned %d\n", err);
1450 if ((err = usbd_close_pipe(sc->sc_in_pipe)) != 0)
1451 printf("usbd_close_pipe(IN) returned %d\n", err);
1452 sc->sc_in_pipe = NULL;
1453 }
1454
1455 if (sc->sc_out_data) {
1456 free(sc->sc_out_data, M_DEVBUF);
1457 sc->sc_out_data = NULL;
1458 }
1459
1460 if (sc->sc_in_data) {
1461 free(sc->sc_in_data, M_DEVBUF);
1462 sc->sc_in_data = NULL;
1463 }
1464
1465 sc->sc_state = UTOPPY_STATE_CLOSED;
1466
1467 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n",
1468 USBDEVNAME(sc->sc_dev)));
1469
1470 return (0);
1471 }
1472
1473 int
1474 utoppyread(dev_t dev, struct uio *uio, int flags)
1475 {
1476 struct utoppy_softc *sc;
1477 struct utoppy_dirent ud;
1478 size_t len;
1479 int err;
1480
1481 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1482
1483 if (sc->sc_dying)
1484 return (EIO);
1485
1486 sc->sc_refcnt++;
1487
1488 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n",
1489 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1490
1491 switch (sc->sc_state) {
1492 case UTOPPY_STATE_READDIR:
1493 err = 0;
1494 while (err == 0 && uio->uio_resid >= sizeof(ud) &&
1495 sc->sc_state != UTOPPY_STATE_IDLE) {
1496 if (utoppy_readdir_decode(sc, &ud) == 0)
1497 err = utoppy_readdir_next(sc);
1498 else
1499 if ((err = uiomove(&ud, sizeof(ud), uio)) != 0)
1500 utoppy_cancel(sc);
1501 }
1502 break;
1503
1504 case UTOPPY_STATE_READFILE:
1505 err = 0;
1506 while (err == 0 && uio->uio_resid > 0 &&
1507 sc->sc_state != UTOPPY_STATE_IDLE) {
1508 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: "
1509 "resid %ld, bytes_left %ld\n",
1510 USBDEVNAME(sc->sc_dev), (u_long)uio->uio_resid,
1511 (u_long)sc->sc_in_len));
1512
1513 if (sc->sc_in_len == 0 &&
1514 (err = utoppy_readfile_next(sc)) != 0) {
1515 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: "
1516 "READFILE: utoppy_readfile_next returned "
1517 "%d\n", USBDEVNAME(sc->sc_dev), err));
1518 break;
1519 }
1520
1521 len = min(uio->uio_resid, sc->sc_in_len);
1522 if (len) {
1523 err = uiomove(UTOPPY_IN_DATA(sc), len, uio);
1524 if (err == 0) {
1525 sc->sc_in_offset += len;
1526 sc->sc_in_len -= len;
1527 }
1528 }
1529 }
1530 break;
1531
1532 case UTOPPY_STATE_IDLE:
1533 err = 0;
1534 break;
1535
1536 case UTOPPY_STATE_WRITEFILE:
1537 err = EBUSY;
1538 break;
1539
1540 default:
1541 err = EIO;
1542 break;
1543 }
1544
1545 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n",
1546 USBDEVNAME(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1547
1548 if (--sc->sc_refcnt < 0)
1549 usb_detach_wakeup(USBDEV(sc->sc_dev));
1550
1551 return (err);
1552 }
1553
1554 int
1555 utoppywrite(dev_t dev, struct uio *uio, int flags)
1556 {
1557 struct utoppy_softc *sc;
1558 uint16_t resp;
1559 size_t len;
1560 int err;
1561
1562 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1563
1564 if (sc->sc_dying)
1565 return (EIO);
1566
1567 switch(sc->sc_state) {
1568 case UTOPPY_STATE_WRITEFILE:
1569 break;
1570
1571 case UTOPPY_STATE_IDLE:
1572 return (0);
1573
1574 default:
1575 return (EIO);
1576 }
1577
1578 sc->sc_refcnt++;
1579 err = 0;
1580
1581 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid %ld, "
1582 "wr_size %lld, wr_offset %lld\n", USBDEVNAME(sc->sc_dev),
1583 (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset));
1584
1585 while (sc->sc_state == UTOPPY_STATE_WRITEFILE &&
1586 (len = min(uio->uio_resid, sc->sc_wr_size)) != 0) {
1587
1588 len = min(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE +
1589 sizeof(uint64_t) + 3));
1590
1591 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n",
1592 USBDEVNAME(sc->sc_dev), (u_long)len));
1593
1594 UTOPPY_OUT_INIT(sc);
1595 utoppy_add_64(sc, sc->sc_wr_offset);
1596
1597 err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio);
1598 if (err) {
1599 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove() "
1600 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1601 break;
1602 }
1603
1604 utoppy_advance_ptr(sc->sc_out_data, len);
1605
1606 err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA,
1607 UTOPPY_LONG_TIMEOUT, &resp);
1608 if (err) {
1609 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1610 "utoppy_command(UTOPPY_RESP_FILE_DATA) "
1611 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1612 break;
1613 }
1614 if (resp != UTOPPY_RESP_SUCCESS) {
1615 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1616 "utoppy_command(UTOPPY_RESP_FILE_DATA) returned "
1617 "bad response 0x%x\n", USBDEVNAME(sc->sc_dev),
1618 resp));
1619 utoppy_cancel(sc);
1620 err = EIO;
1621 break;
1622 }
1623
1624 sc->sc_wr_offset += len;
1625 sc->sc_wr_size -= len;
1626 }
1627
1628 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid %ld,"
1629 " wr_size %lld, wr_offset %lld, err %d\n", USBDEVNAME(sc->sc_dev),
1630 (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset, err));
1631
1632 if (err == 0 && sc->sc_wr_size == 0) {
1633 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending "
1634 "FILE_END...\n", USBDEVNAME(sc->sc_dev)));
1635 UTOPPY_OUT_INIT(sc);
1636 err = utoppy_command(sc, UTOPPY_RESP_FILE_END,
1637 UTOPPY_LONG_TIMEOUT, &resp);
1638 if (err) {
1639 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1640 "utoppy_command(UTOPPY_RESP_FILE_END) returned "
1641 "%d\n", USBDEVNAME(sc->sc_dev), err));
1642
1643 utoppy_cancel(sc);
1644 }
1645
1646 sc->sc_state = UTOPPY_STATE_IDLE;
1647 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n",
1648 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1649 }
1650
1651 if (--sc->sc_refcnt < 0)
1652 usb_detach_wakeup(USBDEV(sc->sc_dev));
1653
1654 return (err);
1655 }
1656
1657 int
1658 utoppyioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
1659 {
1660 struct utoppy_softc *sc;
1661 struct utoppy_rename *ur;
1662 struct utoppy_readfile *urf;
1663 struct utoppy_writefile *uw;
1664 char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp;
1665 uint16_t resp;
1666 int err;
1667
1668 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1669
1670 if (sc->sc_dying)
1671 return (EIO);
1672
1673 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1674 USBDEVNAME(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state)));
1675
1676 if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) {
1677 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n",
1678 USBDEVNAME(sc->sc_dev)));
1679 return (EBUSY);
1680 }
1681
1682 sc->sc_refcnt++;
1683
1684 switch (cmd) {
1685 case UTOPPYIOTURBO:
1686 err = 0;
1687 sc->sc_turbo_mode = *((int *)data) ? 1 : 0;
1688 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: "
1689 "%s\n", USBDEVNAME(sc->sc_dev), sc->sc_turbo_mode ? "On" :
1690 "Off"));
1691 break;
1692
1693 case UTOPPYIOCANCEL:
1694 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
1695 USBDEVNAME(sc->sc_dev)));
1696 err = utoppy_cancel(sc);
1697 break;
1698
1699 case UTOPPYIOREBOOT:
1700 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1701 USBDEVNAME(sc->sc_dev)));
1702 UTOPPY_OUT_INIT(sc);
1703 err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT,
1704 &resp);
1705 if (err)
1706 break;
1707
1708 if (resp != UTOPPY_RESP_SUCCESS)
1709 err = EIO;
1710 break;
1711
1712 case UTOPPYIOSTATS:
1713 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
1714 USBDEVNAME(sc->sc_dev)));
1715 err = utoppy_stats(sc, (struct utoppy_stats *)data);
1716 break;
1717
1718 case UTOPPYIORENAME:
1719 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n",
1720 USBDEVNAME(sc->sc_dev)));
1721 ur = (struct utoppy_rename *)data;
1722 UTOPPY_OUT_INIT(sc);
1723
1724 if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0)
1725 break;
1726 if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0)
1727 break;
1728
1729 err = utoppy_command(sc, UTOPPY_CMD_RENAME, UTOPPY_LONG_TIMEOUT,
1730 &resp);
1731 if (err)
1732 break;
1733
1734 if (resp != UTOPPY_RESP_SUCCESS)
1735 err = EIO;
1736 break;
1737
1738 case UTOPPYIOMKDIR:
1739 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
1740 USBDEVNAME(sc->sc_dev)));
1741 UTOPPY_OUT_INIT(sc);
1742 err = utoppy_add_path(sc, *((const char **)data), 1);
1743 if (err)
1744 break;
1745
1746 err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT,
1747 &resp);
1748 if (err)
1749 break;
1750
1751 if (resp != UTOPPY_RESP_SUCCESS)
1752 err = EIO;
1753 break;
1754
1755 case UTOPPYIODELETE:
1756 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n",
1757 USBDEVNAME(sc->sc_dev)));
1758 UTOPPY_OUT_INIT(sc);
1759 err = utoppy_add_path(sc, *((const char **)data), 0);
1760 if (err)
1761 break;
1762
1763 err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT,
1764 &resp);
1765 if (err)
1766 break;
1767
1768 if (resp != UTOPPY_RESP_SUCCESS)
1769 err = EIO;
1770 break;
1771
1772 case UTOPPYIOREADDIR:
1773 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
1774 USBDEVNAME(sc->sc_dev)));
1775 UTOPPY_OUT_INIT(sc);
1776 err = utoppy_add_path(sc, *((const char **)data), 0);
1777 if (err) {
1778 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1779 "utoppy_add_path() returned %d\n",
1780 USBDEVNAME(sc->sc_dev), err));
1781 break;
1782 }
1783
1784 err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR,
1785 UTOPPY_LONG_TIMEOUT);
1786 if (err != 0) {
1787 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1788 "UTOPPY_CMD_READDIR returned %d\n",
1789 USBDEVNAME(sc->sc_dev), err));
1790 break;
1791 }
1792
1793 err = utoppy_readdir_next(sc);
1794 if (err) {
1795 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1796 "utoppy_readdir_next() returned %d\n",
1797 USBDEVNAME(sc->sc_dev), err));
1798 }
1799 break;
1800
1801 case UTOPPYIOREADFILE:
1802 urf = (struct utoppy_readfile *)data;
1803
1804 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE "
1805 "%s, offset %lld\n", USBDEVNAME(sc->sc_dev), urf->ur_path,
1806 urf->ur_offset));
1807
1808 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1809 break;
1810
1811 UTOPPY_OUT_INIT(sc);
1812 utoppy_add_8(sc, UTOPPY_FILE_READ);
1813
1814 if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0)
1815 break;
1816
1817 utoppy_add_64(sc, urf->ur_offset);
1818
1819 sc->sc_state = UTOPPY_STATE_READFILE;
1820 sc->sc_in_offset = 0;
1821
1822 err = utoppy_send_packet(sc, UTOPPY_CMD_FILE,
1823 UTOPPY_LONG_TIMEOUT);
1824 if (err == 0)
1825 err = utoppy_readfile_next(sc);
1826 break;
1827
1828 case UTOPPYIOWRITEFILE:
1829 uw = (struct utoppy_writefile *)data;
1830
1831 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
1832 "%s, size %lld, offset %lld\n", USBDEVNAME(sc->sc_dev),
1833 uw->uw_path, uw->uw_size, uw->uw_offset));
1834
1835 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1836 break;
1837
1838 UTOPPY_OUT_INIT(sc);
1839 utoppy_add_8(sc, UTOPPY_FILE_WRITE);
1840 uwfp = utoppy_current_ptr(sc->sc_out_data);
1841
1842 if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) {
1843 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path() "
1844 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1845 break;
1846 }
1847
1848 strncpy(uwf, &uwfp[2], sizeof(uwf));
1849 utoppy_add_64(sc, uw->uw_offset);
1850
1851 err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT,
1852 &resp);
1853 if (err) {
1854 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1855 "utoppy_command(UTOPPY_CMD_FILE) returned "
1856 "%d\n", USBDEVNAME(sc->sc_dev), err));
1857 break;
1858 }
1859 if (resp != UTOPPY_RESP_SUCCESS) {
1860 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1861 "utoppy_command(UTOPPY_CMD_FILE) returned "
1862 "bad response 0x%x\n", USBDEVNAME(sc->sc_dev),
1863 resp));
1864 err = EIO;
1865 break;
1866 }
1867
1868 UTOPPY_OUT_INIT(sc);
1869 utoppy_timestamp_encode(sc, uw->uw_mtime);
1870 utoppy_add_8(sc, UTOPPY_FTYPE_FILE);
1871 utoppy_add_64(sc, uw->uw_size);
1872 utoppy_add_string(sc, uwf, sizeof(uwf));
1873 utoppy_add_32(sc, 0);
1874
1875 err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER,
1876 UTOPPY_LONG_TIMEOUT, &resp);
1877 if (err) {
1878 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1879 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1880 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1881 break;
1882 }
1883 if (resp != UTOPPY_RESP_SUCCESS) {
1884 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1885 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1886 "returned bad response 0x%x\n",
1887 USBDEVNAME(sc->sc_dev), resp));
1888 err = EIO;
1889 break;
1890 }
1891
1892 sc->sc_wr_offset = uw->uw_offset;
1893 sc->sc_wr_size = uw->uw_size;
1894 sc->sc_state = UTOPPY_STATE_WRITEFILE;
1895
1896 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to "
1897 "%s. wr_offset %lld, wr_size %lld\n",
1898 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state),
1899 sc->sc_wr_offset, sc->sc_wr_size));
1900 break;
1901
1902 default:
1903 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n",
1904 USBDEVNAME(sc->sc_dev)));
1905 err = ENODEV;
1906 break;
1907 }
1908
1909 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
1910 USBDEVNAME(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1911
1912 if (err)
1913 utoppy_cancel(sc);
1914
1915 if (--sc->sc_refcnt < 0)
1916 usb_detach_wakeup(USBDEV(sc->sc_dev));
1917
1918 return (err);
1919 }
1920