source: mainline/uspace/drv/bus/usb/usbmast/mast.c@ 1ecc5de

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1ecc5de was 026793d, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Increase message verbosity levels so that I/O is not normally logged. Works
around dead-lock when mounting a file system stored on USB mass storage device.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbmast
30 * @{
31 */
32/**
33 * @file
34 * Generic functions for USB mass storage (implementation).
35 */
36#include "mast.h"
37#include "cmds.h"
38#include <bool.h>
39#include <errno.h>
40#include <str_error.h>
41#include <usb/debug.h>
42#include <usb/dev/request.h>
43
44bool usb_mast_verbose = false;
45
46#define MASTLOG(format, ...) \
47 do { \
48 if (usb_mast_verbose) { \
49 usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
50 } \
51 } while (false)
52
53/** Send command via bulk-only transport.
54 *
55 * @param tag Command block wrapper tag (automatically compared
56 * with answer)
57 * @param lun LUN
58 * @param cmd Command block
59 * @param cmd_size Command block size in bytes
60 * @param ddir Direction in which data will be transferred
61 * @param dbuf Data send/receive buffer
62 * @param dbuf_size Size of the data buffer
63 * @param xferred_size Number of bytes actually transferred
64 *
65 * @return Error code
66 */
67static int usb_massstor_cmd(usb_device_t *dev, uint32_t tag, uint8_t lun,
68 const void *cmd, size_t cmd_size, usb_direction_t ddir, void *dbuf,
69 size_t dbuf_size, size_t *xferred_size)
70{
71 int rc;
72 size_t act_size;
73 usb_pipe_t *bulk_in_pipe = dev->pipes[BULK_IN_EP].pipe;
74 usb_pipe_t *bulk_out_pipe = dev->pipes[BULK_OUT_EP].pipe;
75
76 /* Prepare CBW - command block wrapper */
77 usb_massstor_cbw_t cbw;
78 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, lun, cmd_size,
79 cmd);
80
81 /* Send the CBW. */
82 rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
83 MASTLOG("CBW '%s' sent: %s.\n",
84 usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
85 str_error(rc));
86 if (rc != EOK) {
87 return rc;
88 }
89
90 if (ddir == USB_DIRECTION_IN) {
91 /* Recieve data from the device. */
92 rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
93 MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
94 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
95 str_error(rc));
96 } else {
97 /* Send data to the device. */
98 rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
99 MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
100 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
101 str_error(rc));
102 }
103
104 if (rc != EOK) {
105 /*
106 * XXX If the pipe is stalled, we should clear it
107 * and read CSW.
108 */
109 return rc;
110 }
111
112 /* Read CSW. */
113 usb_massstor_csw_t csw;
114 size_t csw_size;
115 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
116 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
117 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
118 str_error(rc));
119 if (rc != EOK) {
120 MASTLOG("rc != EOK\n");
121 return rc;
122 }
123
124 if (csw_size != sizeof(csw)) {
125 MASTLOG("csw_size != sizeof(csw)\n");
126 return ERANGE;
127 }
128
129 if (csw.dCSWTag != tag) {
130 MASTLOG("csw.dCSWTag != tag\n");
131 return EBADCHECKSUM;
132 }
133
134 /*
135 * Determine the actual return value from the CSW.
136 */
137 if (csw.dCSWStatus != 0) {
138 MASTLOG("csw.dCSWStatus != 0\n");
139 // FIXME: better error code
140 // FIXME: distinguish 0x01 and 0x02
141 return EXDEV;
142 }
143
144 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
145 if (residue > dbuf_size) {
146 MASTLOG("residue > dbuf_size\n");
147 return ERANGE;
148 }
149
150 /*
151 * When the device has less data to send than requested (or cannot
152 * receive moredata), it can either stall the pipe or send garbage
153 * (ignore data) and indicate that via the residue field in CSW.
154 * That means dbuf_size - residue is the authoritative size of data
155 * received (sent).
156 */
157
158 if (xferred_size != NULL)
159 *xferred_size = dbuf_size - residue;
160
161 return EOK;
162}
163
164/** Perform data-in command.
165 *
166 * @param tag Command block wrapper tag (automatically compared with
167 * answer)
168 * @param lun LUN
169 * @param cmd CDB (Command Descriptor)
170 * @param cmd_size CDB length in bytes
171 * @param dbuf Data receive buffer
172 * @param dbuf_size Data receive buffer size in bytes
173 * @param proc_size Number of bytes actually processed by device
174 *
175 * @return Error code
176 */
177int usb_massstor_data_in(usb_device_t *dev, uint32_t tag, uint8_t lun,
178 const void *cmd, size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
179{
180 return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_IN,
181 dbuf, dbuf_size, proc_size);
182}
183
184/** Perform data-out command.
185 *
186 * @param tag Command block wrapper tag (automatically compared with
187 * answer)
188 * @param lun LUN
189 * @param cmd CDB (Command Descriptor)
190 * @param cmd_size CDB length in bytes
191 * @param data Command data
192 * @param data_size Size of @a data in bytes
193 * @param proc_size Number of bytes actually processed by device
194 *
195 * @return Error code
196 */
197int usb_massstor_data_out(usb_device_t *dev, uint32_t tag, uint8_t lun,
198 const void *cmd, size_t cmd_size, const void *data, size_t data_size,
199 size_t *proc_size)
200{
201 return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_OUT,
202 (void *) data, data_size, proc_size);
203}
204
205/** Perform bulk-only mass storage reset.
206 *
207 * @param dev Device to be reseted.
208 * @return Error code.
209 */
210int usb_massstor_reset(usb_device_t *dev)
211{
212 return usb_control_request_set(&dev->ctrl_pipe,
213 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
214 0xFF, 0, dev->interface_no, NULL, 0);
215}
216
217/** Perform complete reset recovery of bulk-only mass storage.
218 *
219 * Notice that no error is reported because if this fails, the error
220 * would reappear on next transaction somehow.
221 *
222 * @param dev Device to be reseted.
223 */
224void usb_massstor_reset_recovery(usb_device_t *dev)
225{
226 /* We would ignore errors here because if this fails
227 * we are doomed anyway and any following transaction would fail.
228 */
229 usb_massstor_reset(dev);
230 usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_IN_EP].pipe);
231 usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_OUT_EP].pipe);
232}
233
234/** Get max LUN of a mass storage device.
235 *
236 * @see usb_masstor_get_lun_count
237 *
238 * @warning Error from this command does not necessarily indicate malfunction
239 * of the device. Device does not need to support this request.
240 * You shall rather use usb_masstor_get_lun_count.
241 *
242 * @param dev Mass storage device.
243 * @return Error code of maximum LUN (index, not count).
244 */
245int usb_massstor_get_max_lun(usb_device_t *dev)
246{
247 uint8_t max_lun;
248 size_t data_recv_len;
249 int rc = usb_control_request_get(&dev->ctrl_pipe,
250 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
251 0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
252 if (rc != EOK) {
253 return rc;
254 }
255 if (data_recv_len != 1) {
256 return EEMPTY;
257 }
258 return (int) max_lun;
259}
260
261/** Get number of LUNs supported by mass storage device.
262 *
263 * @warning This function hides any error during the request
264 * (typically that shall not be a problem).
265 *
266 * @param dev Mass storage device.
267 * @return Number of LUNs.
268 */
269size_t usb_masstor_get_lun_count(usb_device_t *dev)
270{
271 int max_lun = usb_massstor_get_max_lun(dev);
272 if (max_lun < 0) {
273 max_lun = 1;
274 } else {
275 max_lun++;
276 }
277
278 return (size_t) max_lun;
279}
280
281/**
282 * @}
283 */
Note: See TracBrowser for help on using the repository browser.