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