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