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