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