utoppy.c revision 1.7 1 /* $NetBSD: utoppy.c,v 1.7 2006/10/12 01:32:00 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.7 2006/10/12 01:32:00 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, D_OTHER,
189 };
190
191 #define UTOPPYUNIT(n) (minor(n))
192
193 USB_DECLARE_DRIVER(utoppy);
194
195 USB_MATCH(utoppy)
196 {
197 USB_MATCH_START(utoppy, uaa);
198
199 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,
515 usbd_private_handle priv __unused,
516 usbd_status status __unused)
517 {
518
519 wakeup(xfer);
520 }
521
522 static usbd_status
523 utoppy_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
524 u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size,
525 const char *lbl)
526 {
527 usbd_status err;
528 int s, error;
529
530 usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
531 utoppy_bulk_transfer_cb);
532 s = splusb();
533 err = usbd_transfer(xfer);
534 if (err != USBD_IN_PROGRESS) {
535 splx(s);
536 return (err);
537 }
538 error = tsleep((caddr_t)xfer, PZERO, lbl, 0);
539 splx(s);
540 if (error) {
541 usbd_abort_pipe(pipe);
542 return (USBD_INTERRUPTED);
543 }
544 usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
545 return (err);
546 }
547
548 static int
549 utoppy_send_packet(struct utoppy_softc *sc, uint16_t cmd, uint32_t timeout)
550 {
551 struct utoppy_header *h;
552 usbd_status err;
553 uint32_t len;
554 uint16_t dlen, crc;
555 uint8_t *data, *e, t1, t2;
556
557 h = sc->sc_out_data;
558
559 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: cmd 0x%04x, "
560 "len %d\n", USBDEVNAME(sc->sc_dev), (u_int)cmd, h->h_len));
561
562 dlen = h->h_len;
563 len = dlen + UTOPPY_HEADER_SIZE;
564
565 if (len & 1)
566 len++;
567 if ((len % 64) == 0)
568 len += 2;
569
570 if (len >= UTOPPY_BSIZE) {
571 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
572 "packet too big (%d)\n", USBDEVNAME(sc->sc_dev), (int)len));
573 return (EINVAL);
574 }
575
576 h->h_len = htole16(dlen + UTOPPY_HEADER_SIZE);
577 h->h_cmd2 = 0;
578 h->h_cmd = htole16(cmd);
579
580 /* The command word is part of the CRC */
581 crc = UTOPPY_CRC16(0, 0);
582 crc = UTOPPY_CRC16(crc, 0);
583 crc = UTOPPY_CRC16(crc, cmd >> 8);
584 crc = UTOPPY_CRC16(crc, cmd);
585
586 /*
587 * If there is data following the header, calculate the CRC and
588 * byte-swap as we go.
589 */
590 if (dlen) {
591 data = h->h_data;
592 e = data + (dlen & ~1);
593
594 do {
595 t1 = data[0];
596 t2 = data[1];
597 crc = UTOPPY_CRC16(crc, t1);
598 crc = UTOPPY_CRC16(crc, t2);
599 *data++ = t2;
600 *data++ = t1;
601 } while (data < e);
602
603 if (dlen & 1) {
604 t1 = data[0];
605 crc = UTOPPY_CRC16(crc, t1);
606 data[1] = t1;
607 }
608 }
609
610 h->h_crc = htole16(crc);
611 data = sc->sc_out_data;
612
613 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: total len "
614 "%d...\n", USBDEVNAME(sc->sc_dev), (int)len));
615 DDUMP_PACKET(data, len);
616
617 do {
618 uint32_t thislen;
619
620 thislen = min(len, UTOPPY_FRAG_SIZE);
621
622 memcpy(sc->sc_out_buf, data, thislen);
623
624 err = utoppy_bulk_transfer(sc->sc_out_xfer, sc->sc_out_pipe,
625 USBD_NO_COPY, timeout, sc->sc_out_buf, &thislen,
626 "utoppytx");
627
628 if (thislen != min(len, UTOPPY_FRAG_SIZE)) {
629 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: "
630 "utoppy_send_packet: sent %ld, err %d\n",
631 USBDEVNAME(sc->sc_dev), (u_long)thislen, err));
632 }
633
634 if (err == 0) {
635 len -= thislen;
636 data += thislen;
637 }
638 } while (err == 0 && len);
639
640 DPRINTF(UTOPPY_DBG_SEND_PACKET, ("%s: utoppy_send_packet: "
641 "usbd_bulk_transfer() returned %d.\n", USBDEVNAME(sc->sc_dev),err));
642
643 return (err ? utoppy_usbd_status2errno(err) : 0);
644 }
645
646 static int
647 utoppy_recv_packet(struct utoppy_softc *sc, uint16_t *respp, uint32_t timeout)
648 {
649 struct utoppy_header *h;
650 usbd_status err;
651 uint32_t len, thislen, requested, bytesleft;
652 uint16_t crc;
653 uint8_t *data, *e, t1, t2;
654
655 data = sc->sc_in_data;
656 len = 0;
657 bytesleft = UTOPPY_BSIZE;
658
659 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: ...\n",
660 USBDEVNAME(sc->sc_dev)));
661
662 do {
663 requested = thislen = min(bytesleft, UTOPPY_FRAG_SIZE);
664
665 err = utoppy_bulk_transfer(sc->sc_in_xfer, sc->sc_in_pipe,
666 USBD_NO_COPY | USBD_SHORT_XFER_OK, timeout, sc->sc_in_buf,
667 &thislen, "utoppyrx");
668
669 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
670 "usbd_bulk_transfer() returned %d, thislen %d, data %p\n",
671 USBDEVNAME(sc->sc_dev), err, (u_int)thislen, data));
672
673 if (err == 0) {
674 memcpy(data, sc->sc_in_buf, thislen);
675 DDUMP_PACKET(data, thislen);
676 len += thislen;
677 bytesleft -= thislen;
678 data += thislen;
679 }
680 } while (err == 0 && bytesleft && thislen == requested);
681
682 if (err)
683 return (utoppy_usbd_status2errno(err));
684
685 h = sc->sc_in_data;
686
687 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: received %d "
688 "bytes in total to %p\n", USBDEVNAME(sc->sc_dev), (u_int)len, h));
689 DDUMP_PACKET(h, len);
690
691 if (len < UTOPPY_HEADER_SIZE || len < (uint32_t)le16toh(h->h_len)) {
692 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: bad "
693 " length (len %d, h_len %d)\n", USBDEVNAME(sc->sc_dev),
694 (int)len, le16toh(h->h_len)));
695 return (EIO);
696 }
697
698 len = h->h_len = le16toh(h->h_len);
699 h->h_crc = le16toh(h->h_crc);
700 *respp = h->h_cmd = le16toh(h->h_cmd);
701 h->h_cmd2 = le16toh(h->h_cmd2);
702
703 /*
704 * To maximise data throughput when transferring files, acknowledge
705 * data blocks as soon as we receive them. If we detect an error
706 * later on, we can always cancel.
707 */
708 if (*respp == UTOPPY_RESP_FILE_DATA) {
709 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: "
710 "ACKing file data\n", USBDEVNAME(sc->sc_dev)));
711
712 UTOPPY_OUT_INIT(sc);
713 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
714 UTOPPY_SHORT_TIMEOUT);
715 if (err) {
716 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: "
717 "utoppy_recv_packet: failed to ACK file data: %d\n",
718 USBDEVNAME(sc->sc_dev), err));
719 return (err);
720 }
721 }
722
723 /* The command word is part of the CRC */
724 crc = UTOPPY_CRC16(0, h->h_cmd2 >> 8);
725 crc = UTOPPY_CRC16(crc, h->h_cmd2);
726 crc = UTOPPY_CRC16(crc, h->h_cmd >> 8);
727 crc = UTOPPY_CRC16(crc, h->h_cmd);
728
729 /*
730 * Extract any payload, byte-swapping and calculating the CRC16
731 * as we go.
732 */
733 if (len > UTOPPY_HEADER_SIZE) {
734 data = h->h_data;
735 e = data + ((len & ~1) - UTOPPY_HEADER_SIZE);
736
737 while (data < e) {
738 t1 = data[0];
739 t2 = data[1];
740 crc = UTOPPY_CRC16(crc, t2);
741 crc = UTOPPY_CRC16(crc, t1);
742 *data++ = t2;
743 *data++ = t1;
744 }
745
746 if (len & 1) {
747 t1 = data[1];
748 crc = UTOPPY_CRC16(crc, t1);
749 *data = t1;
750 }
751 }
752
753 sc->sc_in_len = (size_t) len - UTOPPY_HEADER_SIZE;
754 sc->sc_in_offset = 0;
755
756 DPRINTF(UTOPPY_DBG_RECV_PACKET, ("%s: utoppy_recv_packet: len %d, "
757 "crc 0x%04x, hdrcrc 0x%04x\n", USBDEVNAME(sc->sc_dev),
758 (int)len, crc, h->h_crc));
759 DDUMP_PACKET(h, len);
760
761 return ((crc == h->h_crc) ? 0 : EBADMSG);
762 }
763
764 static __inline void *
765 utoppy_current_ptr(void *b)
766 {
767 struct utoppy_header *h = b;
768
769 return (&h->h_data[h->h_len]);
770 }
771
772 static __inline void
773 utoppy_advance_ptr(void *b, size_t len)
774 {
775 struct utoppy_header *h = b;
776
777 h->h_len += len;
778 }
779
780 static __inline void
781 utoppy_add_8(struct utoppy_softc *sc, uint8_t v)
782 {
783 struct utoppy_header *h = sc->sc_out_data;
784 uint8_t *p;
785
786 p = utoppy_current_ptr(h);
787 *p = v;
788 utoppy_advance_ptr(h, sizeof(v));
789 }
790
791 static __inline void
792 utoppy_add_16(struct utoppy_softc *sc, uint16_t v)
793 {
794 struct utoppy_header *h = sc->sc_out_data;
795 uint8_t *p;
796
797 p = utoppy_current_ptr(h);
798 *p++ = (uint8_t)(v >> 8);
799 *p = (uint8_t)v;
800 utoppy_advance_ptr(h, sizeof(v));
801 }
802
803 static __inline void
804 utoppy_add_32(struct utoppy_softc *sc, uint32_t v)
805 {
806 struct utoppy_header *h = sc->sc_out_data;
807 uint8_t *p;
808
809 p = utoppy_current_ptr(h);
810 *p++ = (uint8_t)(v >> 24);
811 *p++ = (uint8_t)(v >> 16);
812 *p++ = (uint8_t)(v >> 8);
813 *p = (uint8_t)v;
814 utoppy_advance_ptr(h, sizeof(v));
815 }
816
817 static __inline void
818 utoppy_add_64(struct utoppy_softc *sc, uint64_t v)
819 {
820 struct utoppy_header *h = sc->sc_out_data;
821 uint8_t *p;
822
823 p = utoppy_current_ptr(h);
824 *p++ = (uint8_t)(v >> 56);
825 *p++ = (uint8_t)(v >> 48);
826 *p++ = (uint8_t)(v >> 40);
827 *p++ = (uint8_t)(v >> 32);
828 *p++ = (uint8_t)(v >> 24);
829 *p++ = (uint8_t)(v >> 16);
830 *p++ = (uint8_t)(v >> 8);
831 *p = (uint8_t)v;
832 utoppy_advance_ptr(h, sizeof(v));
833 }
834
835 static __inline void
836 utoppy_add_string(struct utoppy_softc *sc, const char *str, size_t len)
837 {
838 struct utoppy_header *h = sc->sc_out_data;
839 char *p;
840
841 p = utoppy_current_ptr(h);
842 memset(p, 0, len);
843 strncpy(p, str, len);
844 utoppy_advance_ptr(h, len);
845 }
846
847 static int
848 utoppy_add_path(struct utoppy_softc *sc, const char *path, int putlen)
849 {
850 struct utoppy_header *h = sc->sc_out_data;
851 uint8_t *p, *str, *s;
852 size_t len;
853 int err;
854
855 p = utoppy_current_ptr(h);
856
857 str = putlen ? (p + sizeof(uint16_t)) : p;
858
859 err = copyinstr(path, str, UTOPPY_MAX_FILENAME_LEN, &len);
860
861 DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: err %d, len %d\n",
862 err, (int)len));
863
864 if (err)
865 return (err);
866
867 if (len < 2)
868 return (EINVAL);
869
870 /*
871 * copyinstr(9) has already copied the terminating NUL character,
872 * but we append another one in case we have to pad the length
873 * later on.
874 */
875 str[len] = '\0';
876
877 /*
878 * The Toppy uses backslash as the directory separator, so convert
879 * all forward slashes.
880 */
881 for (s = &str[len - 2]; s >= str; s--)
882 if (*s == '/')
883 *s = '\\';
884
885 if ((len + h->h_len) & 1)
886 len++;
887
888 if (putlen)
889 utoppy_add_16(sc, len);
890
891 utoppy_advance_ptr(h, len);
892
893 DPRINTF(UTOPPY_DBG_ADDPATH, ("utoppy_add_path: final len %d\n",
894 (u_int)len));
895
896 return (0);
897 }
898
899 static __inline int
900 utoppy_get_8(struct utoppy_softc *sc, uint8_t *vp)
901 {
902 uint8_t *p;
903
904 if (sc->sc_in_len < sizeof(*vp))
905 return (1);
906
907 p = UTOPPY_IN_DATA(sc);
908 *vp = *p;
909 sc->sc_in_offset += sizeof(*vp);
910 sc->sc_in_len -= sizeof(*vp);
911 return (0);
912 }
913
914 static __inline int
915 utoppy_get_16(struct utoppy_softc *sc, uint16_t *vp)
916 {
917 uint16_t v;
918 uint8_t *p;
919
920 if (sc->sc_in_len < sizeof(v))
921 return (1);
922
923 p = UTOPPY_IN_DATA(sc);
924 v = *p++;
925 v = (v << 8) | *p;
926 *vp = v;
927 sc->sc_in_offset += sizeof(v);
928 sc->sc_in_len -= sizeof(v);
929 return (0);
930 }
931
932 static __inline int
933 utoppy_get_32(struct utoppy_softc *sc, uint32_t *vp)
934 {
935 uint32_t v;
936 uint8_t *p;
937
938 if (sc->sc_in_len < sizeof(v))
939 return (1);
940
941 p = UTOPPY_IN_DATA(sc);
942 v = *p++;
943 v = (v << 8) | *p++;
944 v = (v << 8) | *p++;
945 v = (v << 8) | *p;
946 *vp = v;
947 sc->sc_in_offset += sizeof(v);
948 sc->sc_in_len -= sizeof(v);
949 return (0);
950 }
951
952 static __inline int
953 utoppy_get_64(struct utoppy_softc *sc, uint64_t *vp)
954 {
955 uint64_t v;
956 uint8_t *p;
957
958 if (sc->sc_in_len < sizeof(v))
959 return (1);
960
961 p = UTOPPY_IN_DATA(sc);
962 v = *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 v = (v << 8) | *p;
970 *vp = v;
971 sc->sc_in_offset += sizeof(v);
972 sc->sc_in_len -= sizeof(v);
973 return (0);
974 }
975
976 static __inline int
977 utoppy_get_string(struct utoppy_softc *sc, char *str, size_t len)
978 {
979 char *p;
980
981 if (sc->sc_in_len < len)
982 return (1);
983
984 memset(str, 0, len);
985 p = UTOPPY_IN_DATA(sc);
986 strncpy(str, p, len);
987 sc->sc_in_offset += len;
988 sc->sc_in_len -= len;
989 return (0);
990 }
991
992 static int
993 utoppy_command(struct utoppy_softc *sc, uint16_t cmd, int timeout,
994 uint16_t *presp)
995 {
996 int err;
997
998 err = utoppy_send_packet(sc, cmd, timeout);
999 if (err)
1000 return (err);
1001
1002 err = utoppy_recv_packet(sc, presp, timeout);
1003 if (err == EBADMSG) {
1004 UTOPPY_OUT_INIT(sc);
1005 utoppy_send_packet(sc, UTOPPY_RESP_ERROR, timeout);
1006 }
1007
1008 return (err);
1009 }
1010
1011 static int
1012 utoppy_timestamp_decode(struct utoppy_softc *sc, time_t *tp)
1013 {
1014 uint16_t mjd;
1015 uint8_t hour, minute, sec;
1016 uint32_t rv;
1017
1018 if (utoppy_get_16(sc, &mjd) || utoppy_get_8(sc, &hour) ||
1019 utoppy_get_8(sc, &minute) || utoppy_get_8(sc, &sec))
1020 return (1);
1021
1022 if (mjd == 0xffffu && hour == 0xffu && minute == 0xffu && sec == 0xffu){
1023 *tp = 0;
1024 return (0);
1025 }
1026
1027 rv = (mjd < UTOPPY_MJD_1970) ? UTOPPY_MJD_1970 : (uint32_t) mjd;
1028
1029 /* Calculate seconds since 1970 */
1030 rv = (rv - UTOPPY_MJD_1970) * 60 * 60 * 24;
1031
1032 /* Add in the hours, minutes, and seconds */
1033 rv += (uint32_t)hour * 60 * 60;
1034 rv += (uint32_t)minute * 60;
1035 rv += sec;
1036 *tp = (time_t)rv;
1037
1038 return (0);
1039 }
1040
1041 static void
1042 utoppy_timestamp_encode(struct utoppy_softc *sc, time_t t)
1043 {
1044 u_int mjd, hour, minute;
1045
1046 mjd = t / (60 * 60 * 24);
1047 t -= mjd * 60 * 60 * 24;
1048
1049 hour = t / (60 * 60);
1050 t -= hour * 60 * 60;
1051
1052 minute = t / 60;
1053 t -= minute * 60;
1054
1055 utoppy_add_16(sc, mjd + UTOPPY_MJD_1970);
1056 utoppy_add_8(sc, hour);
1057 utoppy_add_8(sc, minute);
1058 utoppy_add_8(sc, t);
1059 }
1060
1061 static int
1062 utoppy_turbo_mode(struct utoppy_softc *sc, int state)
1063 {
1064 uint16_t r;
1065 int err;
1066
1067 UTOPPY_OUT_INIT(sc);
1068 utoppy_add_32(sc, state);
1069
1070 err = utoppy_command(sc, UTOPPY_CMD_TURBO, UTOPPY_SHORT_TIMEOUT, &r);
1071 if (err)
1072 return (err);
1073
1074 return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1075 }
1076
1077 static int
1078 utoppy_check_ready(struct utoppy_softc *sc)
1079 {
1080 uint16_t r;
1081 int err;
1082
1083 UTOPPY_OUT_INIT(sc);
1084
1085 err = utoppy_command(sc, UTOPPY_CMD_READY, UTOPPY_LONG_TIMEOUT, &r);
1086 if (err)
1087 return (err);
1088
1089 return ((r == UTOPPY_RESP_SUCCESS) ? 0 : EIO);
1090 }
1091
1092 static int
1093 utoppy_cancel(struct utoppy_softc *sc)
1094 {
1095 uint16_t r;
1096 int err, i;
1097
1098 /*
1099 * Issue the cancel command serveral times. the Toppy doesn't
1100 * always respond to the first.
1101 */
1102 for (i = 0; i < 3; i++) {
1103 UTOPPY_OUT_INIT(sc);
1104 err = utoppy_command(sc, UTOPPY_CMD_CANCEL,
1105 UTOPPY_SHORT_TIMEOUT, &r);
1106 if (err == 0 && r == UTOPPY_RESP_SUCCESS)
1107 break;
1108 err = ETIMEDOUT;
1109 }
1110
1111 if (err)
1112 return (err);
1113
1114 /*
1115 * Make sure turbo mode is off, otherwise the Toppy will not
1116 * respond to remote control input.
1117 */
1118 (void) utoppy_turbo_mode(sc, 0);
1119
1120 sc->sc_state = UTOPPY_STATE_IDLE;
1121 return (0);
1122 }
1123
1124 static int
1125 utoppy_stats(struct utoppy_softc *sc, struct utoppy_stats *us)
1126 {
1127 uint32_t hsize, hfree;
1128 uint16_t r;
1129 int err;
1130
1131 UTOPPY_OUT_INIT(sc);
1132 err = utoppy_command(sc, UTOPPY_CMD_STATS, UTOPPY_LONG_TIMEOUT, &r);
1133 if (err)
1134 return (err);
1135
1136 if (r != UTOPPY_RESP_STATS_DATA)
1137 return (EIO);
1138
1139 if (utoppy_get_32(sc, &hsize) || utoppy_get_32(sc, &hfree))
1140 return (EIO);
1141
1142 us->us_hdd_size = hsize;
1143 us->us_hdd_size *= 1024;
1144 us->us_hdd_free = hfree;
1145 us->us_hdd_free *= 1024;
1146
1147 return (0);
1148 }
1149
1150 static int
1151 utoppy_readdir_next(struct utoppy_softc *sc)
1152 {
1153 uint16_t resp;
1154 int err;
1155
1156 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: running...\n",
1157 USBDEVNAME(sc->sc_dev)));
1158
1159 /*
1160 * Fetch the next READDIR response
1161 */
1162 err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1163 if (err) {
1164 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1165 "utoppy_recv_packet() returned %d\n",
1166 USBDEVNAME(sc->sc_dev), err));
1167 if (err == EBADMSG) {
1168 UTOPPY_OUT_INIT(sc);
1169 utoppy_send_packet(sc, UTOPPY_RESP_ERROR,
1170 UTOPPY_LONG_TIMEOUT);
1171 }
1172 utoppy_cancel(sc);
1173 return (err);
1174 }
1175
1176 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1177 "utoppy_recv_packet() returned %d, len %ld\n",
1178 USBDEVNAME(sc->sc_dev), err, (u_long)sc->sc_in_len));
1179
1180 switch (resp) {
1181 case UTOPPY_RESP_READDIR_DATA:
1182 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1183 "UTOPPY_RESP_READDIR_DATA\n", USBDEVNAME(sc->sc_dev)));
1184
1185 UTOPPY_OUT_INIT(sc);
1186 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1187 UTOPPY_LONG_TIMEOUT);
1188 if (err) {
1189 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1190 "utoppy_send_packet(ACK) returned %d\n",
1191 USBDEVNAME(sc->sc_dev), err));
1192 utoppy_cancel(sc);
1193 return (err);
1194 }
1195 sc->sc_state = UTOPPY_STATE_READDIR;
1196 sc->sc_in_offset = 0;
1197 break;
1198
1199 case UTOPPY_RESP_READDIR_END:
1200 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1201 "UTOPPY_RESP_READDIR_END\n", USBDEVNAME(sc->sc_dev)));
1202
1203 UTOPPY_OUT_INIT(sc);
1204 utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1205 sc->sc_state = UTOPPY_STATE_IDLE;
1206 sc->sc_in_len = 0;
1207 break;
1208
1209 default:
1210 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_next: "
1211 "bad response: 0x%x\n", USBDEVNAME(sc->sc_dev), resp));
1212 sc->sc_state = UTOPPY_STATE_IDLE;
1213 sc->sc_in_len = 0;
1214 return (EIO);
1215 }
1216
1217 return (0);
1218 }
1219
1220 static size_t
1221 utoppy_readdir_decode(struct utoppy_softc *sc, struct utoppy_dirent *ud)
1222 {
1223 uint8_t ftype;
1224
1225 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: bytes left"
1226 " %d\n", USBDEVNAME(sc->sc_dev), (int)sc->sc_in_len));
1227
1228 if (utoppy_timestamp_decode(sc, &ud->ud_mtime) ||
1229 utoppy_get_8(sc, &ftype) || utoppy_get_64(sc, &ud->ud_size) ||
1230 utoppy_get_string(sc, ud->ud_path, UTOPPY_MAX_FILENAME_LEN + 1) ||
1231 utoppy_get_32(sc, &ud->ud_attributes)) {
1232 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: no "
1233 "more to decode\n", USBDEVNAME(sc->sc_dev)));
1234 return (0);
1235 }
1236
1237 switch (ftype) {
1238 case UTOPPY_FTYPE_DIR:
1239 ud->ud_type = UTOPPY_DIRENT_DIRECTORY;
1240 break;
1241 case UTOPPY_FTYPE_FILE:
1242 ud->ud_type = UTOPPY_DIRENT_FILE;
1243 break;
1244 default:
1245 ud->ud_type = UTOPPY_DIRENT_UNKNOWN;
1246 break;
1247 }
1248
1249 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppy_readdir_decode: %s '%s', "
1250 "size %lld, time 0x%08lx, attr 0x%08x\n", USBDEVNAME(sc->sc_dev),
1251 (ftype == UTOPPY_FTYPE_DIR) ? "DIR" :
1252 ((ftype == UTOPPY_FTYPE_FILE) ? "FILE" : "UNKNOWN"), ud->ud_path,
1253 ud->ud_size, (u_long)ud->ud_mtime, ud->ud_attributes));
1254
1255 return (1);
1256 }
1257
1258 static int
1259 utoppy_readfile_next(struct utoppy_softc *sc)
1260 {
1261 uint64_t off;
1262 uint16_t resp;
1263 int err;
1264
1265 err = utoppy_recv_packet(sc, &resp, UTOPPY_LONG_TIMEOUT);
1266 if (err) {
1267 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1268 "utoppy_recv_packet() returned %d\n",
1269 USBDEVNAME(sc->sc_dev), err));
1270 utoppy_cancel(sc);
1271 return (err);
1272 }
1273
1274 switch (resp) {
1275 case UTOPPY_RESP_FILE_HEADER:
1276 /* ACK it */
1277 UTOPPY_OUT_INIT(sc);
1278 err = utoppy_send_packet(sc, UTOPPY_CMD_ACK,
1279 UTOPPY_LONG_TIMEOUT);
1280 if (err) {
1281 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1282 "utoppy_send_packet(UTOPPY_CMD_ACK) returned %d\n",
1283 USBDEVNAME(sc->sc_dev), err));
1284 utoppy_cancel(sc);
1285 return (err);
1286 }
1287
1288 sc->sc_in_len = 0;
1289 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1290 "FILE_HEADER done\n", USBDEVNAME(sc->sc_dev)));
1291 break;
1292
1293 case UTOPPY_RESP_FILE_DATA:
1294 /* Already ACK'd */
1295 if (utoppy_get_64(sc, &off)) {
1296 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1297 "UTOPPY_RESP_FILE_DATA did not provide offset\n",
1298 USBDEVNAME(sc->sc_dev)));
1299 utoppy_cancel(sc);
1300 return (EBADMSG);
1301 }
1302
1303 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1304 "UTOPPY_RESP_FILE_DATA: offset %lld, bytes left %ld\n",
1305 USBDEVNAME(sc->sc_dev), off, (u_long)sc->sc_in_len));
1306 break;
1307
1308 case UTOPPY_RESP_FILE_END:
1309 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: "
1310 "UTOPPY_RESP_FILE_END: sending ACK\n",
1311 USBDEVNAME(sc->sc_dev)));
1312 UTOPPY_OUT_INIT(sc);
1313 utoppy_send_packet(sc, UTOPPY_CMD_ACK, UTOPPY_SHORT_TIMEOUT);
1314 /*FALLTHROUGH*/
1315
1316 case UTOPPY_RESP_SUCCESS:
1317 sc->sc_state = UTOPPY_STATE_IDLE;
1318 (void) utoppy_turbo_mode(sc, 0);
1319 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: all "
1320 "done\n", USBDEVNAME(sc->sc_dev)));
1321 break;
1322
1323 case UTOPPY_RESP_ERROR:
1324 default:
1325 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppy_readfile_next: bad "
1326 "response code 0x%0x\n", USBDEVNAME(sc->sc_dev), resp));
1327 utoppy_cancel(sc);
1328 return (EIO);
1329 }
1330
1331 return (0);
1332 }
1333
1334 int
1335 utoppyopen(dev_t dev, int flag __unused, int mode __unused,
1336 struct lwp *l __unused)
1337 {
1338 struct utoppy_softc *sc;
1339 int error = 0;
1340
1341 USB_GET_SC_OPEN(utoppy, UTOPPYUNIT(dev), sc);
1342
1343 if (sc == NULL || sc->sc_iface == NULL || sc->sc_dying)
1344 return (ENXIO);
1345
1346 if (sc->sc_state != UTOPPY_STATE_CLOSED) {
1347 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: already open\n",
1348 USBDEVNAME(sc->sc_dev)));
1349 return (EBUSY);
1350 }
1351
1352 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: opening...\n",
1353 USBDEVNAME(sc->sc_dev)));
1354
1355 sc->sc_refcnt++;
1356 sc->sc_state = UTOPPY_STATE_OPENING;
1357 sc->sc_turbo_mode = 0;
1358 sc->sc_out_pipe = NULL;
1359 sc->sc_in_pipe = NULL;
1360
1361 if (usbd_open_pipe(sc->sc_iface, sc->sc_out, 0, &sc->sc_out_pipe)) {
1362 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(OUT) "
1363 "failed\n", USBDEVNAME(sc->sc_dev)));
1364 error = EIO;
1365 goto done;
1366 }
1367
1368 if (usbd_open_pipe(sc->sc_iface, sc->sc_in, 0, &sc->sc_in_pipe)) {
1369 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: usbd_open_pipe(IN) "
1370 "failed\n", USBDEVNAME(sc->sc_dev)));
1371 error = EIO;
1372 usbd_close_pipe(sc->sc_out_pipe);
1373 sc->sc_out_pipe = NULL;
1374 goto done;
1375 }
1376
1377 sc->sc_out_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1378 if (sc->sc_out_data == NULL) {
1379 error = ENOMEM;
1380 goto error;
1381 }
1382
1383 sc->sc_in_data = malloc(UTOPPY_BSIZE + 1, M_DEVBUF, M_WAITOK);
1384 if (sc->sc_in_data == NULL) {
1385 free(sc->sc_out_data, M_DEVBUF);
1386 sc->sc_out_data = NULL;
1387 error = ENOMEM;
1388 goto error;
1389 }
1390
1391 if ((error = utoppy_cancel(sc)) != 0)
1392 goto error;
1393
1394 if ((error = utoppy_check_ready(sc)) != 0) {
1395 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: utoppy_check_ready()"
1396 " returned %d\n", USBDEVNAME(sc->sc_dev), error));
1397 error:
1398 usbd_abort_pipe(sc->sc_out_pipe);
1399 usbd_close_pipe(sc->sc_out_pipe);
1400 sc->sc_out_pipe = NULL;
1401 usbd_abort_pipe(sc->sc_in_pipe);
1402 usbd_close_pipe(sc->sc_in_pipe);
1403 sc->sc_in_pipe = NULL;
1404 }
1405
1406 done:
1407 sc->sc_state = error ? UTOPPY_STATE_CLOSED : UTOPPY_STATE_IDLE;
1408
1409 DPRINTF(UTOPPY_DBG_OPEN, ("%s: utoppyopen: done. error %d, new state "
1410 "'%s'\n", USBDEVNAME(sc->sc_dev), error,
1411 utoppy_state_string(sc->sc_state)));
1412
1413 if (--sc->sc_refcnt < 0)
1414 usb_detach_wakeup(USBDEV(sc->sc_dev));
1415
1416 return (error);
1417 }
1418
1419 int
1420 utoppyclose(dev_t dev, int flag __unused, int mode __unused,
1421 struct lwp *l __unused)
1422 {
1423 struct utoppy_softc *sc;
1424 usbd_status err;
1425
1426 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1427
1428 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: closing...\n",
1429 USBDEVNAME(sc->sc_dev)));
1430
1431 if (sc->sc_state < UTOPPY_STATE_IDLE) {
1432 /* We are being forced to close before the open completed. */
1433 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: not properly open:"
1434 " %s\n", USBDEVNAME(sc->sc_dev),
1435 utoppy_state_string(sc->sc_state)));
1436 return (0);
1437 }
1438
1439 if (sc->sc_out_data)
1440 (void) utoppy_cancel(sc);
1441
1442 if (sc->sc_out_pipe != NULL) {
1443 if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
1444 printf("usbd_abort_pipe(OUT) returned %d\n", err);
1445 if ((err = usbd_close_pipe(sc->sc_out_pipe)) != 0)
1446 printf("usbd_close_pipe(OUT) returned %d\n", err);
1447 sc->sc_out_pipe = NULL;
1448 }
1449
1450 if (sc->sc_in_pipe != NULL) {
1451 if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
1452 printf("usbd_abort_pipe(IN) returned %d\n", err);
1453 if ((err = usbd_close_pipe(sc->sc_in_pipe)) != 0)
1454 printf("usbd_close_pipe(IN) returned %d\n", err);
1455 sc->sc_in_pipe = NULL;
1456 }
1457
1458 if (sc->sc_out_data) {
1459 free(sc->sc_out_data, M_DEVBUF);
1460 sc->sc_out_data = NULL;
1461 }
1462
1463 if (sc->sc_in_data) {
1464 free(sc->sc_in_data, M_DEVBUF);
1465 sc->sc_in_data = NULL;
1466 }
1467
1468 sc->sc_state = UTOPPY_STATE_CLOSED;
1469
1470 DPRINTF(UTOPPY_DBG_CLOSE, ("%s: utoppyclose: done.\n",
1471 USBDEVNAME(sc->sc_dev)));
1472
1473 return (0);
1474 }
1475
1476 int
1477 utoppyread(dev_t dev, struct uio *uio, int flags __unused)
1478 {
1479 struct utoppy_softc *sc;
1480 struct utoppy_dirent ud;
1481 size_t len;
1482 int err;
1483
1484 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1485
1486 if (sc->sc_dying)
1487 return (EIO);
1488
1489 sc->sc_refcnt++;
1490
1491 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: reading: state '%s'\n",
1492 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1493
1494 switch (sc->sc_state) {
1495 case UTOPPY_STATE_READDIR:
1496 err = 0;
1497 while (err == 0 && uio->uio_resid >= sizeof(ud) &&
1498 sc->sc_state != UTOPPY_STATE_IDLE) {
1499 if (utoppy_readdir_decode(sc, &ud) == 0)
1500 err = utoppy_readdir_next(sc);
1501 else
1502 if ((err = uiomove(&ud, sizeof(ud), uio)) != 0)
1503 utoppy_cancel(sc);
1504 }
1505 break;
1506
1507 case UTOPPY_STATE_READFILE:
1508 err = 0;
1509 while (err == 0 && uio->uio_resid > 0 &&
1510 sc->sc_state != UTOPPY_STATE_IDLE) {
1511 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: READFILE: "
1512 "resid %ld, bytes_left %ld\n",
1513 USBDEVNAME(sc->sc_dev), (u_long)uio->uio_resid,
1514 (u_long)sc->sc_in_len));
1515
1516 if (sc->sc_in_len == 0 &&
1517 (err = utoppy_readfile_next(sc)) != 0) {
1518 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: "
1519 "READFILE: utoppy_readfile_next returned "
1520 "%d\n", USBDEVNAME(sc->sc_dev), err));
1521 break;
1522 }
1523
1524 len = min(uio->uio_resid, sc->sc_in_len);
1525 if (len) {
1526 err = uiomove(UTOPPY_IN_DATA(sc), len, uio);
1527 if (err == 0) {
1528 sc->sc_in_offset += len;
1529 sc->sc_in_len -= len;
1530 }
1531 }
1532 }
1533 break;
1534
1535 case UTOPPY_STATE_IDLE:
1536 err = 0;
1537 break;
1538
1539 case UTOPPY_STATE_WRITEFILE:
1540 err = EBUSY;
1541 break;
1542
1543 default:
1544 err = EIO;
1545 break;
1546 }
1547
1548 DPRINTF(UTOPPY_DBG_READ, ("%s: utoppyread: done. err %d, state '%s'\n",
1549 USBDEVNAME(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1550
1551 if (--sc->sc_refcnt < 0)
1552 usb_detach_wakeup(USBDEV(sc->sc_dev));
1553
1554 return (err);
1555 }
1556
1557 int
1558 utoppywrite(dev_t dev, struct uio *uio, int flags __unused)
1559 {
1560 struct utoppy_softc *sc;
1561 uint16_t resp;
1562 size_t len;
1563 int err;
1564
1565 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1566
1567 if (sc->sc_dying)
1568 return (EIO);
1569
1570 switch(sc->sc_state) {
1571 case UTOPPY_STATE_WRITEFILE:
1572 break;
1573
1574 case UTOPPY_STATE_IDLE:
1575 return (0);
1576
1577 default:
1578 return (EIO);
1579 }
1580
1581 sc->sc_refcnt++;
1582 err = 0;
1583
1584 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: PRE-WRITEFILE: resid %ld, "
1585 "wr_size %lld, wr_offset %lld\n", USBDEVNAME(sc->sc_dev),
1586 (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset));
1587
1588 while (sc->sc_state == UTOPPY_STATE_WRITEFILE &&
1589 (len = min(uio->uio_resid, sc->sc_wr_size)) != 0) {
1590
1591 len = min(len, UTOPPY_BSIZE - (UTOPPY_HEADER_SIZE +
1592 sizeof(uint64_t) + 3));
1593
1594 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove(%ld)\n",
1595 USBDEVNAME(sc->sc_dev), (u_long)len));
1596
1597 UTOPPY_OUT_INIT(sc);
1598 utoppy_add_64(sc, sc->sc_wr_offset);
1599
1600 err = uiomove(utoppy_current_ptr(sc->sc_out_data), len, uio);
1601 if (err) {
1602 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: uiomove() "
1603 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1604 break;
1605 }
1606
1607 utoppy_advance_ptr(sc->sc_out_data, len);
1608
1609 err = utoppy_command(sc, UTOPPY_RESP_FILE_DATA,
1610 UTOPPY_LONG_TIMEOUT, &resp);
1611 if (err) {
1612 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1613 "utoppy_command(UTOPPY_RESP_FILE_DATA) "
1614 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1615 break;
1616 }
1617 if (resp != UTOPPY_RESP_SUCCESS) {
1618 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1619 "utoppy_command(UTOPPY_RESP_FILE_DATA) returned "
1620 "bad response 0x%x\n", USBDEVNAME(sc->sc_dev),
1621 resp));
1622 utoppy_cancel(sc);
1623 err = EIO;
1624 break;
1625 }
1626
1627 sc->sc_wr_offset += len;
1628 sc->sc_wr_size -= len;
1629 }
1630
1631 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: POST-WRITEFILE: resid %ld,"
1632 " wr_size %lld, wr_offset %lld, err %d\n", USBDEVNAME(sc->sc_dev),
1633 (u_long)uio->uio_resid, sc->sc_wr_size, sc->sc_wr_offset, err));
1634
1635 if (err == 0 && sc->sc_wr_size == 0) {
1636 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: sending "
1637 "FILE_END...\n", USBDEVNAME(sc->sc_dev)));
1638 UTOPPY_OUT_INIT(sc);
1639 err = utoppy_command(sc, UTOPPY_RESP_FILE_END,
1640 UTOPPY_LONG_TIMEOUT, &resp);
1641 if (err) {
1642 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: "
1643 "utoppy_command(UTOPPY_RESP_FILE_END) returned "
1644 "%d\n", USBDEVNAME(sc->sc_dev), err));
1645
1646 utoppy_cancel(sc);
1647 }
1648
1649 sc->sc_state = UTOPPY_STATE_IDLE;
1650 DPRINTF(UTOPPY_DBG_WRITE, ("%s: utoppywrite: state %s\n",
1651 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state)));
1652 }
1653
1654 if (--sc->sc_refcnt < 0)
1655 usb_detach_wakeup(USBDEV(sc->sc_dev));
1656
1657 return (err);
1658 }
1659
1660 int
1661 utoppyioctl(dev_t dev, u_long cmd, caddr_t data, int flag __unused,
1662 struct lwp *l __unused)
1663 {
1664 struct utoppy_softc *sc;
1665 struct utoppy_rename *ur;
1666 struct utoppy_readfile *urf;
1667 struct utoppy_writefile *uw;
1668 char uwf[UTOPPY_MAX_FILENAME_LEN + 1], *uwfp;
1669 uint16_t resp;
1670 int err;
1671
1672 USB_GET_SC(utoppy, UTOPPYUNIT(dev), sc);
1673
1674 if (sc->sc_dying)
1675 return (EIO);
1676
1677 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: cmd 0x%08lx, state '%s'\n",
1678 USBDEVNAME(sc->sc_dev), cmd, utoppy_state_string(sc->sc_state)));
1679
1680 if (sc->sc_state != UTOPPY_STATE_IDLE && cmd != UTOPPYIOCANCEL) {
1681 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: still busy.\n",
1682 USBDEVNAME(sc->sc_dev)));
1683 return (EBUSY);
1684 }
1685
1686 sc->sc_refcnt++;
1687
1688 switch (cmd) {
1689 case UTOPPYIOTURBO:
1690 err = 0;
1691 sc->sc_turbo_mode = *((int *)data) ? 1 : 0;
1692 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOTURBO: "
1693 "%s\n", USBDEVNAME(sc->sc_dev), sc->sc_turbo_mode ? "On" :
1694 "Off"));
1695 break;
1696
1697 case UTOPPYIOCANCEL:
1698 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOCANCEL\n",
1699 USBDEVNAME(sc->sc_dev)));
1700 err = utoppy_cancel(sc);
1701 break;
1702
1703 case UTOPPYIOREBOOT:
1704 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREBOOT\n",
1705 USBDEVNAME(sc->sc_dev)));
1706 UTOPPY_OUT_INIT(sc);
1707 err = utoppy_command(sc, UTOPPY_CMD_RESET, UTOPPY_LONG_TIMEOUT,
1708 &resp);
1709 if (err)
1710 break;
1711
1712 if (resp != UTOPPY_RESP_SUCCESS)
1713 err = EIO;
1714 break;
1715
1716 case UTOPPYIOSTATS:
1717 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOSTATS\n",
1718 USBDEVNAME(sc->sc_dev)));
1719 err = utoppy_stats(sc, (struct utoppy_stats *)data);
1720 break;
1721
1722 case UTOPPYIORENAME:
1723 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIORENAME\n",
1724 USBDEVNAME(sc->sc_dev)));
1725 ur = (struct utoppy_rename *)data;
1726 UTOPPY_OUT_INIT(sc);
1727
1728 if ((err = utoppy_add_path(sc, ur->ur_old_path, 1)) != 0)
1729 break;
1730 if ((err = utoppy_add_path(sc, ur->ur_new_path, 1)) != 0)
1731 break;
1732
1733 err = utoppy_command(sc, UTOPPY_CMD_RENAME, UTOPPY_LONG_TIMEOUT,
1734 &resp);
1735 if (err)
1736 break;
1737
1738 if (resp != UTOPPY_RESP_SUCCESS)
1739 err = EIO;
1740 break;
1741
1742 case UTOPPYIOMKDIR:
1743 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOMKDIR\n",
1744 USBDEVNAME(sc->sc_dev)));
1745 UTOPPY_OUT_INIT(sc);
1746 err = utoppy_add_path(sc, *((const char **)data), 1);
1747 if (err)
1748 break;
1749
1750 err = utoppy_command(sc, UTOPPY_CMD_MKDIR, UTOPPY_LONG_TIMEOUT,
1751 &resp);
1752 if (err)
1753 break;
1754
1755 if (resp != UTOPPY_RESP_SUCCESS)
1756 err = EIO;
1757 break;
1758
1759 case UTOPPYIODELETE:
1760 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIODELETE\n",
1761 USBDEVNAME(sc->sc_dev)));
1762 UTOPPY_OUT_INIT(sc);
1763 err = utoppy_add_path(sc, *((const char **)data), 0);
1764 if (err)
1765 break;
1766
1767 err = utoppy_command(sc, UTOPPY_CMD_DELETE, UTOPPY_LONG_TIMEOUT,
1768 &resp);
1769 if (err)
1770 break;
1771
1772 if (resp != UTOPPY_RESP_SUCCESS)
1773 err = EIO;
1774 break;
1775
1776 case UTOPPYIOREADDIR:
1777 DPRINTF(UTOPPY_DBG_IOCTL, ("%s: utoppyioctl: UTOPPYIOREADDIR\n",
1778 USBDEVNAME(sc->sc_dev)));
1779 UTOPPY_OUT_INIT(sc);
1780 err = utoppy_add_path(sc, *((const char **)data), 0);
1781 if (err) {
1782 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1783 "utoppy_add_path() returned %d\n",
1784 USBDEVNAME(sc->sc_dev), err));
1785 break;
1786 }
1787
1788 err = utoppy_send_packet(sc, UTOPPY_CMD_READDIR,
1789 UTOPPY_LONG_TIMEOUT);
1790 if (err != 0) {
1791 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1792 "UTOPPY_CMD_READDIR returned %d\n",
1793 USBDEVNAME(sc->sc_dev), err));
1794 break;
1795 }
1796
1797 err = utoppy_readdir_next(sc);
1798 if (err) {
1799 DPRINTF(UTOPPY_DBG_READDIR, ("%s: utoppyioctl: "
1800 "utoppy_readdir_next() returned %d\n",
1801 USBDEVNAME(sc->sc_dev), err));
1802 }
1803 break;
1804
1805 case UTOPPYIOREADFILE:
1806 urf = (struct utoppy_readfile *)data;
1807
1808 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOREADFILE "
1809 "%s, offset %lld\n", USBDEVNAME(sc->sc_dev), urf->ur_path,
1810 urf->ur_offset));
1811
1812 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1813 break;
1814
1815 UTOPPY_OUT_INIT(sc);
1816 utoppy_add_8(sc, UTOPPY_FILE_READ);
1817
1818 if ((err = utoppy_add_path(sc, urf->ur_path, 1)) != 0)
1819 break;
1820
1821 utoppy_add_64(sc, urf->ur_offset);
1822
1823 sc->sc_state = UTOPPY_STATE_READFILE;
1824 sc->sc_in_offset = 0;
1825
1826 err = utoppy_send_packet(sc, UTOPPY_CMD_FILE,
1827 UTOPPY_LONG_TIMEOUT);
1828 if (err == 0)
1829 err = utoppy_readfile_next(sc);
1830 break;
1831
1832 case UTOPPYIOWRITEFILE:
1833 uw = (struct utoppy_writefile *)data;
1834
1835 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: UTOPPYIOWRITEFILE "
1836 "%s, size %lld, offset %lld\n", USBDEVNAME(sc->sc_dev),
1837 uw->uw_path, uw->uw_size, uw->uw_offset));
1838
1839 if ((err = utoppy_turbo_mode(sc, sc->sc_turbo_mode)) != 0)
1840 break;
1841
1842 UTOPPY_OUT_INIT(sc);
1843 utoppy_add_8(sc, UTOPPY_FILE_WRITE);
1844 uwfp = utoppy_current_ptr(sc->sc_out_data);
1845
1846 if ((err = utoppy_add_path(sc, uw->uw_path, 1)) != 0) {
1847 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: add_path() "
1848 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1849 break;
1850 }
1851
1852 strncpy(uwf, &uwfp[2], sizeof(uwf));
1853 utoppy_add_64(sc, uw->uw_offset);
1854
1855 err = utoppy_command(sc, UTOPPY_CMD_FILE, UTOPPY_LONG_TIMEOUT,
1856 &resp);
1857 if (err) {
1858 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1859 "utoppy_command(UTOPPY_CMD_FILE) returned "
1860 "%d\n", USBDEVNAME(sc->sc_dev), err));
1861 break;
1862 }
1863 if (resp != UTOPPY_RESP_SUCCESS) {
1864 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1865 "utoppy_command(UTOPPY_CMD_FILE) returned "
1866 "bad response 0x%x\n", USBDEVNAME(sc->sc_dev),
1867 resp));
1868 err = EIO;
1869 break;
1870 }
1871
1872 UTOPPY_OUT_INIT(sc);
1873 utoppy_timestamp_encode(sc, uw->uw_mtime);
1874 utoppy_add_8(sc, UTOPPY_FTYPE_FILE);
1875 utoppy_add_64(sc, uw->uw_size);
1876 utoppy_add_string(sc, uwf, sizeof(uwf));
1877 utoppy_add_32(sc, 0);
1878
1879 err = utoppy_command(sc, UTOPPY_RESP_FILE_HEADER,
1880 UTOPPY_LONG_TIMEOUT, &resp);
1881 if (err) {
1882 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1883 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1884 "returned %d\n", USBDEVNAME(sc->sc_dev), err));
1885 break;
1886 }
1887 if (resp != UTOPPY_RESP_SUCCESS) {
1888 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: "
1889 "utoppy_command(UTOPPY_RESP_FILE_HEADER) "
1890 "returned bad response 0x%x\n",
1891 USBDEVNAME(sc->sc_dev), resp));
1892 err = EIO;
1893 break;
1894 }
1895
1896 sc->sc_wr_offset = uw->uw_offset;
1897 sc->sc_wr_size = uw->uw_size;
1898 sc->sc_state = UTOPPY_STATE_WRITEFILE;
1899
1900 DPRINTF(UTOPPY_DBG_WRITE,("%s: utoppyioctl: Changing state to "
1901 "%s. wr_offset %lld, wr_size %lld\n",
1902 USBDEVNAME(sc->sc_dev), utoppy_state_string(sc->sc_state),
1903 sc->sc_wr_offset, sc->sc_wr_size));
1904 break;
1905
1906 default:
1907 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: Invalid cmd\n",
1908 USBDEVNAME(sc->sc_dev)));
1909 err = ENODEV;
1910 break;
1911 }
1912
1913 DPRINTF(UTOPPY_DBG_IOCTL,("%s: utoppyioctl: done. err %d, state '%s'\n",
1914 USBDEVNAME(sc->sc_dev), err, utoppy_state_string(sc->sc_state)));
1915
1916 if (err)
1917 utoppy_cancel(sc);
1918
1919 if (--sc->sc_refcnt < 0)
1920 usb_detach_wakeup(USBDEV(sc->sc_dev));
1921
1922 return (err);
1923 }
1924