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