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