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