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