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