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