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