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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b6812a1 was c39e9fb, checked in by Jan Vesely <jano.vesely@…>, 13 years ago

usb, drivers: Use usb_device_* wrappers.

  • Property mode set to 100644
File size: 7.7 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 <stdbool.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 SCSI command
61 *
62 * @return Error code
63 */
64int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
65{
66 int rc;
67 int retval = EOK;
68 size_t act_size;
69 usb_pipe_t *bulk_in_pipe = &mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe;
70 usb_pipe_t *bulk_out_pipe = &mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe;
71 usb_direction_t ddir;
72 void *dbuf;
73 size_t dbuf_size;
74
75 if (cmd->data_out != NULL && cmd->data_in == NULL) {
76 ddir = USB_DIRECTION_OUT;
77 dbuf = (void *)cmd->data_out;
78 dbuf_size = cmd->data_out_size;
79 } else if (cmd->data_out == NULL && cmd->data_in != NULL) {
80 ddir = USB_DIRECTION_IN;
81 dbuf = cmd->data_in;
82 dbuf_size = cmd->data_in_size;
83 } else {
84 assert(false);
85 }
86
87 /* Prepare CBW - command block wrapper */
88 usb_massstor_cbw_t cbw;
89 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
90 cmd->cdb_size, cmd->cdb);
91
92 /* Send the CBW. */
93 MASTLOG("Sending CBW.\n");
94 rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
95 MASTLOG("CBW '%s' sent: %s.\n",
96 usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
97 str_error(rc));
98 if (rc != EOK)
99 return EIO;
100
101 MASTLOG("Transferring data.\n");
102 if (ddir == USB_DIRECTION_IN) {
103 /* Recieve data from the device. */
104 rc = usb_pipe_read(bulk_in_pipe, dbuf, dbuf_size, &act_size);
105 MASTLOG("Received %zu bytes (%s): %s.\n", act_size,
106 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
107 str_error(rc));
108 } else {
109 /* Send data to the device. */
110 rc = usb_pipe_write(bulk_out_pipe, dbuf, dbuf_size);
111 MASTLOG("Sent %zu bytes (%s): %s.\n", act_size,
112 usb_debug_str_buffer((uint8_t *) dbuf, act_size, 0),
113 str_error(rc));
114 }
115
116 if (rc == ESTALL) {
117 /* Clear stall condition and continue below to read CSW. */
118 if (ddir == USB_DIRECTION_IN) {
119 usb_pipe_clear_halt(
120 usb_device_get_default_pipe(mfun->mdev->usb_dev),
121 &mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
122 } else {
123 usb_pipe_clear_halt(
124 usb_device_get_default_pipe(mfun->mdev->usb_dev),
125 &mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
126 }
127 } else if (rc != EOK) {
128 return EIO;
129 }
130
131 /* Read CSW. */
132 usb_massstor_csw_t csw;
133 size_t csw_size;
134 MASTLOG("Reading CSW.\n");
135 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
136 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
137 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
138 str_error(rc));
139 if (rc != EOK) {
140 MASTLOG("rc != EOK\n");
141 return EIO;
142 }
143
144 if (csw_size != sizeof(csw)) {
145 MASTLOG("csw_size != sizeof(csw)\n");
146 return EIO;
147 }
148
149 if (csw.dCSWTag != tag) {
150 MASTLOG("csw.dCSWTag != tag\n");
151 return EIO;
152 }
153
154 /*
155 * Determine the actual return value from the CSW.
156 */
157 switch (csw.dCSWStatus) {
158 case cbs_passed:
159 cmd->status = CMDS_GOOD;
160 break;
161 case cbs_failed:
162 MASTLOG("Command failed\n");
163 cmd->status = CMDS_FAILED;
164 break;
165 case cbs_phase_error:
166 MASTLOG("Phase error\n");
167 retval = EIO;
168 break;
169 default:
170 retval = EIO;
171 break;
172 }
173
174 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
175 if (residue > dbuf_size) {
176 MASTLOG("residue > dbuf_size\n");
177 return EIO;
178 }
179
180 /*
181 * When the device has less data to send than requested (or cannot
182 * receive moredata), it can either stall the pipe or send garbage
183 * (ignore data) and indicate that via the residue field in CSW.
184 * That means dbuf_size - residue is the authoritative size of data
185 * received (sent).
186 */
187
188 if (ddir == USB_DIRECTION_IN)
189 cmd->rcvd_size = dbuf_size - residue;
190
191 return retval;
192}
193
194/** Perform bulk-only mass storage reset.
195 *
196 * @param mfun Mass storage function
197 * @return Error code
198 */
199int usb_massstor_reset(usbmast_dev_t *mdev)
200{
201 return usb_control_request_set(
202 usb_device_get_default_pipe(mdev->usb_dev),
203 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
204 0xFF, 0, mdev->usb_dev->interface_no, NULL, 0);
205}
206
207/** Perform complete reset recovery of bulk-only mass storage.
208 *
209 * Notice that no error is reported because if this fails, the error
210 * would reappear on next transaction somehow.
211 *
212 * @param mfun Mass storage function
213 */
214void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
215{
216 /* We would ignore errors here because if this fails
217 * we are doomed anyway and any following transaction would fail.
218 */
219 usb_massstor_reset(mdev);
220 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
221 &mdev->usb_dev->pipes[BULK_IN_EP].pipe);
222 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
223 &mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
224}
225
226/** Get max LUN of a mass storage device.
227 *
228 * @see usb_masstor_get_lun_count
229 *
230 * @warning Error from this command does not necessarily indicate malfunction
231 * of the device. Device does not need to support this request.
232 * You shall rather use usb_masstor_get_lun_count.
233 *
234 * @param mfun Mass storage function
235 * @return Error code of maximum LUN (index, not count)
236 */
237int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
238{
239 uint8_t max_lun;
240 size_t data_recv_len;
241 int rc = usb_control_request_get(
242 usb_device_get_default_pipe(mdev->usb_dev),
243 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
244 0xFE, 0, mdev->usb_dev->interface_no, &max_lun, 1, &data_recv_len);
245 if (rc != EOK) {
246 return rc;
247 }
248 if (data_recv_len != 1) {
249 return EEMPTY;
250 }
251 return (int) max_lun;
252}
253
254/** Get number of LUNs supported by mass storage device.
255 *
256 * @warning This function hides any error during the request
257 * (typically that shall not be a problem).
258 *
259 * @param mfun Mass storage function
260 * @return Number of LUNs
261 */
262size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
263{
264 int max_lun = usb_massstor_get_max_lun(mdev);
265 if (max_lun < 0) {
266 max_lun = 1;
267 } else {
268 max_lun++;
269 }
270
271 return (size_t) max_lun;
272}
273
274/**
275 * @}
276 */
Note: See TracBrowser for help on using the repository browser.