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