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