source: mainline/uspace/drv/bus/usb/usbmast/bo_trans.c@ 89d3f3c7

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

Rename mass storage sources to be more fitting.

  • 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 * USB mass storage bulk-only transport.
35 */
36#include <bool.h>
37#include <errno.h>
38#include <str_error.h>
39#include <usb/debug.h>
40#include <usb/dev/request.h>
41
42#include "bo_trans.h"
43#include "cmdw.h"
44
45bool usb_mast_verbose = false;
46
47#define MASTLOG(format, ...) \
48 do { \
49 if (usb_mast_verbose) { \
50 usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
51 } \
52 } while (false)
53
54/** Send command via bulk-only transport.
55 *
56 * @param tag Command block wrapper tag (automatically compared
57 * with answer)
58 * @param lun LUN
59 * @param cmd Command block
60 * @param cmd_size Command block size in bytes
61 * @param ddir Direction in which data will be transferred
62 * @param dbuf Data send/receive buffer
63 * @param dbuf_size Size of the data buffer
64 * @param xferred_size Number of bytes actually transferred
65 *
66 * @return Error code
67 */
68static int usb_massstor_cmd(usb_device_t *dev, uint32_t tag, uint8_t lun,
69 const void *cmd, size_t cmd_size, usb_direction_t ddir, void *dbuf,
70 size_t dbuf_size, size_t *xferred_size)
71{
72 int rc;
73 size_t act_size;
74 usb_pipe_t *bulk_in_pipe = dev->pipes[BULK_IN_EP].pipe;
75 usb_pipe_t *bulk_out_pipe = dev->pipes[BULK_OUT_EP].pipe;
76
77 /* Prepare CBW - command block wrapper */
78 usb_massstor_cbw_t cbw;
79 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, lun, cmd_size,
80 cmd);
81
82 /* Send the CBW. */
83 rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
84 MASTLOG("CBW '%s' sent: %s.\n",
85 usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
86 str_error(rc));
87 if (rc != EOK) {
88 return rc;
89 }
90
91 if (ddir == USB_DIRECTION_IN) {
92 /* Recieve data from the device. */
93 rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
94 MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
95 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
96 str_error(rc));
97 } else {
98 /* Send data to the device. */
99 rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
100 MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
101 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
102 str_error(rc));
103 }
104
105 if (rc != EOK) {
106 /*
107 * XXX If the pipe is stalled, we should clear it
108 * and read CSW.
109 */
110 return rc;
111 }
112
113 /* Read CSW. */
114 usb_massstor_csw_t csw;
115 size_t csw_size;
116 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
117 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
118 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
119 str_error(rc));
120 if (rc != EOK) {
121 MASTLOG("rc != EOK\n");
122 return rc;
123 }
124
125 if (csw_size != sizeof(csw)) {
126 MASTLOG("csw_size != sizeof(csw)\n");
127 return ERANGE;
128 }
129
130 if (csw.dCSWTag != tag) {
131 MASTLOG("csw.dCSWTag != tag\n");
132 return EBADCHECKSUM;
133 }
134
135 /*
136 * Determine the actual return value from the CSW.
137 */
138 if (csw.dCSWStatus != 0) {
139 MASTLOG("csw.dCSWStatus != 0\n");
140 // FIXME: better error code
141 // FIXME: distinguish 0x01 and 0x02
142 return EXDEV;
143 }
144
145 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
146 if (residue > dbuf_size) {
147 MASTLOG("residue > dbuf_size\n");
148 return ERANGE;
149 }
150
151 /*
152 * When the device has less data to send than requested (or cannot
153 * receive moredata), it can either stall the pipe or send garbage
154 * (ignore data) and indicate that via the residue field in CSW.
155 * That means dbuf_size - residue is the authoritative size of data
156 * received (sent).
157 */
158
159 if (xferred_size != NULL)
160 *xferred_size = dbuf_size - residue;
161
162 return EOK;
163}
164
165/** Perform data-in command.
166 *
167 * @param tag Command block wrapper tag (automatically compared with
168 * answer)
169 * @param lun LUN
170 * @param cmd CDB (Command Descriptor)
171 * @param cmd_size CDB length in bytes
172 * @param dbuf Data receive buffer
173 * @param dbuf_size Data receive buffer size in bytes
174 * @param proc_size Number of bytes actually processed by device
175 *
176 * @return Error code
177 */
178int usb_massstor_data_in(usb_device_t *dev, uint32_t tag, uint8_t lun,
179 const void *cmd, size_t cmd_size, void *dbuf, size_t dbuf_size, size_t *proc_size)
180{
181 return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_IN,
182 dbuf, dbuf_size, proc_size);
183}
184
185/** Perform data-out command.
186 *
187 * @param tag Command block wrapper tag (automatically compared with
188 * answer)
189 * @param lun LUN
190 * @param cmd CDB (Command Descriptor)
191 * @param cmd_size CDB length in bytes
192 * @param data Command data
193 * @param data_size Size of @a data in bytes
194 * @param proc_size Number of bytes actually processed by device
195 *
196 * @return Error code
197 */
198int usb_massstor_data_out(usb_device_t *dev, uint32_t tag, uint8_t lun,
199 const void *cmd, size_t cmd_size, const void *data, size_t data_size,
200 size_t *proc_size)
201{
202 return usb_massstor_cmd(dev, tag, lun, cmd, cmd_size, USB_DIRECTION_OUT,
203 (void *) data, data_size, proc_size);
204}
205
206/** Perform bulk-only mass storage reset.
207 *
208 * @param dev Device to be reseted.
209 * @return Error code.
210 */
211int usb_massstor_reset(usb_device_t *dev)
212{
213 return usb_control_request_set(&dev->ctrl_pipe,
214 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
215 0xFF, 0, dev->interface_no, NULL, 0);
216}
217
218/** Perform complete reset recovery of bulk-only mass storage.
219 *
220 * Notice that no error is reported because if this fails, the error
221 * would reappear on next transaction somehow.
222 *
223 * @param dev Device to be reseted.
224 */
225void usb_massstor_reset_recovery(usb_device_t *dev)
226{
227 /* We would ignore errors here because if this fails
228 * we are doomed anyway and any following transaction would fail.
229 */
230 usb_massstor_reset(dev);
231 usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_IN_EP].pipe);
232 usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[BULK_OUT_EP].pipe);
233}
234
235/** Get max LUN of a mass storage device.
236 *
237 * @see usb_masstor_get_lun_count
238 *
239 * @warning Error from this command does not necessarily indicate malfunction
240 * of the device. Device does not need to support this request.
241 * You shall rather use usb_masstor_get_lun_count.
242 *
243 * @param dev Mass storage device.
244 * @return Error code of maximum LUN (index, not count).
245 */
246int usb_massstor_get_max_lun(usb_device_t *dev)
247{
248 uint8_t max_lun;
249 size_t data_recv_len;
250 int rc = usb_control_request_get(&dev->ctrl_pipe,
251 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
252 0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
253 if (rc != EOK) {
254 return rc;
255 }
256 if (data_recv_len != 1) {
257 return EEMPTY;
258 }
259 return (int) max_lun;
260}
261
262/** Get number of LUNs supported by mass storage device.
263 *
264 * @warning This function hides any error during the request
265 * (typically that shall not be a problem).
266 *
267 * @param dev Mass storage device.
268 * @return Number of LUNs.
269 */
270size_t usb_masstor_get_lun_count(usb_device_t *dev)
271{
272 int max_lun = usb_massstor_get_max_lun(dev);
273 if (max_lun < 0) {
274 max_lun = 1;
275 } else {
276 max_lun++;
277 }
278
279 return (size_t) max_lun;
280}
281
282/**
283 * @}
284 */
Note: See TracBrowser for help on using the repository browser.