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