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