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