mast.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Vojtech Horky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00036 #include "mast.h"
00037 #include "cmds.h"
00038 #include <bool.h>
00039 #include <errno.h>
00040 #include <str_error.h>
00041 #include <usb/debug.h>
00042 #include <usb/dev/request.h>
00043 
00044 bool usb_mast_verbose = true;
00045 
00046 #define MASTLOG(format, ...) \
00047         do { \
00048                 if (usb_mast_verbose) { \
00049                         usb_log_debug("USB cl08: " format, ##__VA_ARGS__); \
00050                 } \
00051         } while (false)
00052 
00066 int usb_massstor_data_in(usb_device_t *dev,
00067     size_t bulk_in_pipe_index, size_t bulk_out_pipe_index,
00068     uint32_t tag, uint8_t lun, void *cmd, size_t cmd_size,
00069     void *in_buffer, size_t in_buffer_size, size_t *received_size)
00070 {
00071         int rc;
00072         size_t act_size;
00073         usb_pipe_t *bulk_in_pipe = dev->pipes[bulk_in_pipe_index].pipe;
00074         usb_pipe_t *bulk_out_pipe = dev->pipes[bulk_out_pipe_index].pipe;
00075 
00076         /* Prepare CBW - command block wrapper */
00077         usb_massstor_cbw_t cbw;
00078         usb_massstor_cbw_prepare(&cbw, tag, in_buffer_size,
00079             USB_DIRECTION_IN, lun, cmd_size, cmd);
00080 
00081         /* First, send the CBW. */
00082         rc = usb_pipe_write(bulk_out_pipe, &cbw, sizeof(cbw));
00083         MASTLOG("CBW '%s' sent: %s.\n",
00084             usb_debug_str_buffer((uint8_t *) &cbw, sizeof(cbw), 0),
00085             str_error(rc));
00086         if (rc != EOK) {
00087                 return rc;
00088         }
00089 
00090         /* Try to retrieve the data from the device. */
00091         act_size = 0;
00092         rc = usb_pipe_read(bulk_in_pipe, in_buffer, in_buffer_size, &act_size);
00093         MASTLOG("Received %zuB (%s): %s.\n", act_size,
00094             usb_debug_str_buffer((uint8_t *) in_buffer, act_size, 0),
00095             str_error(rc));
00096         if (rc != EOK) {
00097                 return rc;
00098         }
00099 
00100         /* Read CSW. */
00101         usb_massstor_csw_t csw;
00102         size_t csw_size;
00103         rc = usb_pipe_read(bulk_in_pipe, &csw, sizeof(csw), &csw_size);
00104         MASTLOG("CSW '%s' received (%zuB): %s.\n",
00105             usb_debug_str_buffer((uint8_t *) &csw, csw_size, 0), csw_size,
00106             str_error(rc));
00107         if (rc != EOK) {
00108                 return rc;
00109         }
00110         if (csw_size != sizeof(csw)) {
00111                 return ERANGE;
00112         }
00113 
00114         if (csw.dCSWTag != tag) {
00115                 return EBADCHECKSUM;
00116         }
00117 
00118         /*
00119          * Determine the actual return value from the CSW.
00120          */
00121         if (csw.dCSWStatus != 0) {
00122                 // FIXME: better error code
00123                 // FIXME: distinguish 0x01 and 0x02
00124                 return EXDEV;
00125         }
00126 
00127         size_t residue = (size_t) uint32_usb2host(csw.dCSWDataResidue);
00128         if (residue > in_buffer_size) {
00129                 return ERANGE;
00130         }
00131         if (act_size != in_buffer_size - residue) {
00132                 return ERANGE;
00133         }
00134         if (received_size != NULL) {
00135                 *received_size = in_buffer_size - residue;
00136         }
00137 
00138         return EOK;
00139 }
00140 
00146 int usb_massstor_reset(usb_device_t *dev)
00147 {
00148         return usb_control_request_set(&dev->ctrl_pipe,
00149             USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
00150             0xFF, 0, dev->interface_no, NULL, 0);
00151 }
00152 
00162 void usb_massstor_reset_recovery(usb_device_t *dev,
00163     size_t bulk_in_idx, size_t bulk_out_idx)
00164 {
00165         /* We would ignore errors here because if this fails
00166          * we are doomed anyway and any following transaction would fail.
00167          */
00168         usb_massstor_reset(dev);
00169         usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_in_idx].pipe);
00170         usb_pipe_clear_halt(&dev->ctrl_pipe, dev->pipes[bulk_out_idx].pipe);
00171 }
00172 
00184 int usb_massstor_get_max_lun(usb_device_t *dev)
00185 {
00186         uint8_t max_lun;
00187         size_t data_recv_len;
00188         int rc = usb_control_request_get(&dev->ctrl_pipe,
00189             USB_REQUEST_TYPE_CLASS, USB_REQUEST_RECIPIENT_INTERFACE,
00190             0xFE, 0, dev->interface_no, &max_lun, 1, &data_recv_len);
00191         if (rc != EOK) {
00192                 return rc;
00193         }
00194         if (data_recv_len != 1) {
00195                 return EEMPTY;
00196         }
00197         return (int) max_lun;
00198 }
00199 
00208 size_t usb_masstor_get_lun_count(usb_device_t *dev)
00209 {
00210         int max_lun = usb_massstor_get_max_lun(dev);
00211         if (max_lun < 0) {
00212                 max_lun = 1;
00213         } else {
00214                 max_lun++;
00215         }
00216 
00217         return (size_t) max_lun;
00218 }
00219 

Generated on Thu Jun 2 07:45:44 2011 for HelenOS/USB by  doxygen 1.4.7