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