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
RevLine 
[380e0364]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
[89d3f3c7]34 * USB mass storage bulk-only transport.
[380e0364]35 */
[3e6a98c5]36#include <stdbool.h>
[380e0364]37#include <errno.h>
38#include <str_error.h>
39#include <usb/debug.h>
[7d521e24]40#include <usb/dev/request.h>
[380e0364]41
[89d3f3c7]42#include "bo_trans.h"
43#include "cmdw.h"
[7190bbc]44#include "usbmast.h"
[89d3f3c7]45
[026793d]46bool usb_mast_verbose = false;
[380e0364]47
48#define MASTLOG(format, ...) \
49 do { \
50 if (usb_mast_verbose) { \
[026793d]51 usb_log_debug2("USB cl08: " format, ##__VA_ARGS__); \
[380e0364]52 } \
53 } while (false)
54
[38c9505]55/** Send command via bulk-only transport.
[380e0364]56 *
[7190bbc]57 * @param mfun Mass storage function
[38c9505]58 * @param tag Command block wrapper tag (automatically compared
59 * with answer)
[de3432b]60 * @param cmd SCSI command
[38c9505]61 *
62 * @return Error code
[380e0364]63 */
[de3432b]64int usb_massstor_cmd(usbmast_fun_t *mfun, uint32_t tag, scsi_cmd_t *cmd)
[380e0364]65{
66 int rc;
[45cae6b]67 int retval = EOK;
[380e0364]68 size_t act_size;
[b77931d]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;
[de3432b]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 }
[380e0364]86
87 /* Prepare CBW - command block wrapper */
88 usb_massstor_cbw_t cbw;
[e6b32a8]89 usb_massstor_cbw_prepare(&cbw, tag, dbuf_size, ddir, mfun->lun,
[de3432b]90 cmd->cdb_size, cmd->cdb);
[380e0364]91
[38c9505]92 /* Send the CBW. */
[45cae6b]93 MASTLOG("Sending CBW.\n");
[380e0364]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));
[45cae6b]98 if (rc != EOK)
99 return EIO;
[380e0364]100
[45cae6b]101 MASTLOG("Transferring data.\n");
[38c9505]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
[45cae6b]116 if (rc == ESTALL) {
117 /* Clear stall condition and continue below to read CSW. */
118 if (ddir == USB_DIRECTION_IN) {
[c39e9fb]119 usb_pipe_clear_halt(
120 usb_device_get_default_pipe(mfun->mdev->usb_dev),
[b77931d]121 &mfun->mdev->usb_dev->pipes[BULK_IN_EP].pipe);
[45cae6b]122 } else {
[c39e9fb]123 usb_pipe_clear_halt(
124 usb_device_get_default_pipe(mfun->mdev->usb_dev),
[b77931d]125 &mfun->mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
[45cae6b]126 }
127 } else if (rc != EOK) {
128 return EIO;
[380e0364]129 }
130
131 /* Read CSW. */
132 usb_massstor_csw_t csw;
133 size_t csw_size;
[45cae6b]134 MASTLOG("Reading CSW.\n");
[380e0364]135 rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
[38c9505]136 MASTLOG("CSW '%s' received (%zu bytes): %s.\n",
[380e0364]137 usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
138 str_error(rc));
139 if (rc != EOK) {
[f7a55f9]140 MASTLOG("rc != EOK\n");
[45cae6b]141 return EIO;
[380e0364]142 }
[f7a55f9]143
[380e0364]144 if (csw_size != sizeof(csw)) {
[f7a55f9]145 MASTLOG("csw_size != sizeof(csw)\n");
[45cae6b]146 return EIO;
[380e0364]147 }
148
149 if (csw.dCSWTag != tag) {
[f7a55f9]150 MASTLOG("csw.dCSWTag != tag\n");
[45cae6b]151 return EIO;
[380e0364]152 }
153
154 /*
155 * Determine the actual return value from the CSW.
156 */
[45cae6b]157 switch (csw.dCSWStatus) {
158 case cbs_passed:
[de3432b]159 cmd->status = CMDS_GOOD;
[45cae6b]160 break;
161 case cbs_failed:
162 MASTLOG("Command failed\n");
[de3432b]163 cmd->status = CMDS_FAILED;
[45cae6b]164 break;
165 case cbs_phase_error:
166 MASTLOG("Phase error\n");
167 retval = EIO;
168 break;
169 default:
170 retval = EIO;
171 break;
[380e0364]172 }
173
174 size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
[38c9505]175 if (residue > dbuf_size) {
176 MASTLOG("residue > dbuf_size\n");
[45cae6b]177 return EIO;
[380e0364]178 }
[f7a55f9]179
180 /*
[38c9505]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).
[f7a55f9]186 */
187
[de3432b]188 if (ddir == USB_DIRECTION_IN)
189 cmd->rcvd_size = dbuf_size - residue;
[380e0364]190
[45cae6b]191 return retval;
[380e0364]192}
193
[cf002dbf]194/** Perform bulk-only mass storage reset.
195 *
[7190bbc]196 * @param mfun Mass storage function
197 * @return Error code
[cf002dbf]198 */
[2aceec5]199int usb_massstor_reset(usbmast_dev_t *mdev)
[70c12d6]200{
[c39e9fb]201 return usb_control_request_set(
202 usb_device_get_default_pipe(mdev->usb_dev),
[70c12d6]203 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
[2aceec5]204 0xFF, 0, mdev->usb_dev->interface_no, NULL, 0);
[70c12d6]205}
206
[cf002dbf]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 *
[7190bbc]212 * @param mfun Mass storage function
[cf002dbf]213 */
[2aceec5]214void usb_massstor_reset_recovery(usbmast_dev_t *mdev)
[70c12d6]215{
216 /* We would ignore errors here because if this fails
217 * we are doomed anyway and any following transaction would fail.
218 */
[2aceec5]219 usb_massstor_reset(mdev);
[c39e9fb]220 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
[b77931d]221 &mdev->usb_dev->pipes[BULK_IN_EP].pipe);
[c39e9fb]222 usb_pipe_clear_halt(usb_device_get_default_pipe(mdev->usb_dev),
[b77931d]223 &mdev->usb_dev->pipes[BULK_OUT_EP].pipe);
[70c12d6]224}
225
[cf002dbf]226/** Get max LUN of a mass storage device.
[5f0fe4e9]227 *
228 * @see usb_masstor_get_lun_count
[cf002dbf]229 *
230 * @warning Error from this command does not necessarily indicate malfunction
231 * of the device. Device does not need to support this request.
[5f0fe4e9]232 * You shall rather use usb_masstor_get_lun_count.
[cf002dbf]233 *
[7190bbc]234 * @param mfun Mass storage function
235 * @return Error code of maximum LUN (index, not count)
[cf002dbf]236 */
[2aceec5]237int usb_massstor_get_max_lun(usbmast_dev_t *mdev)
[70c12d6]238{
239 uint8_t max_lun;
240 size_t data_recv_len;
[c39e9fb]241 int rc = usb_control_request_get(
242 usb_device_get_default_pipe(mdev->usb_dev),
[70c12d6]243 USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
[2aceec5]244 0xFE, 0, mdev->usb_dev->interface_no, &max_lun, 1, &data_recv_len);
[70c12d6]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
[5f0fe4e9]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 *
[7190bbc]259 * @param mfun Mass storage function
260 * @return Number of LUNs
[5f0fe4e9]261 */
[2aceec5]262size_t usb_masstor_get_lun_count(usbmast_dev_t *mdev)
[5f0fe4e9]263{
[2aceec5]264 int max_lun = usb_massstor_get_max_lun(mdev);
[5f0fe4e9]265 if (max_lun < 0) {
266 max_lun = 1;
267 } else {
268 max_lun++;
269 }
270
271 return (size_t) max_lun;
272}
273
[380e0364]274/**
275 * @}
276 */
Note: See TracBrowser for help on using the repository browser.