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