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