source: mainline/uspace/drv/bus/usb/usbmast/bo_trans.c@ 6a44ee4

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

Support multiple LUNs in mass storage driver.

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