Changeset f51f193 in mainline for uspace/drv/bus/usb/usbmast/main.c


Ignore:
Timestamp:
2011-07-12T03:00:14Z (13 years ago)
Author:
Petr Koupy <petr.koupy@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
6817eba
Parents:
eca52a8 (diff), 026793d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/usbmast/main.c

    reca52a8 rf51f193  
    11/*
    22 * Copyright (c) 2011 Vojtech Horky
     3 * Copyright (c) 2011 Jiri Svoboda
    34 * All rights reserved.
    45 *
     
    3435 * Main routines of USB mass storage driver.
    3536 */
     37#include <as.h>
     38#include <async.h>
     39#include <ipc/bd.h>
     40#include <macros.h>
    3641#include <usb/dev/driver.h>
    3742#include <usb/debug.h>
     
    4146#include <str_error.h>
    4247#include "cmds.h"
    43 #include "scsi.h"
    4448#include "mast.h"
     49#include "scsi_ms.h"
    4550
    4651#define NAME "usbmast"
    47 
    48 #define BULK_IN_EP 0
    49 #define BULK_OUT_EP 1
    5052
    5153#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
     
    7577};
    7678
     79/** Mass storage function.
     80 *
     81 * Serves as soft state for function/LUN.
     82 */
     83typedef struct {
     84        /** DDF function */
     85        ddf_fun_t *ddf_fun;
     86        /** Total number of blocks. */
     87        uint64_t nblocks;
     88        /** Block size in bytes. */
     89        size_t block_size;
     90        /** USB device function belongs to */
     91        usb_device_t *usb_dev;
     92} usbmast_fun_t;
     93
     94static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
     95    void *arg);
     96
    7797/** Callback when new device is attached and recognized as a mass storage.
    7898 *
     
    83103{
    84104        int rc;
    85         const char *fun_name = "ctl";
    86 
    87         ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
    88             fun_name);
    89         if (ctl_fun == NULL) {
    90                 usb_log_error("Failed to create control function.\n");
    91                 return ENOMEM;
    92         }
    93         rc = ddf_fun_bind(ctl_fun);
    94         if (rc != EOK) {
    95                 usb_log_error("Failed to bind control function: %s.\n",
    96                     str_error(rc));
    97                 return rc;
    98         }
    99 
    100         usb_log_info("Pretending to control mass storage `%s'.\n",
     105        const char *fun_name = "a";
     106        ddf_fun_t *fun = NULL;
     107        usbmast_fun_t *msfun = NULL;
     108
     109        /* Allocate softstate */
     110        msfun = calloc(1, sizeof(usbmast_fun_t));
     111        if (msfun == NULL) {
     112                usb_log_error("Failed allocating softstate.\n");
     113                rc = ENOMEM;
     114                goto error;
     115        }
     116
     117        fun = ddf_fun_create(dev->ddf_dev, fun_exposed, fun_name);
     118        if (fun == NULL) {
     119                usb_log_error("Failed to create DDF function %s.\n", fun_name);
     120                rc = ENOMEM;
     121                goto error;
     122        }
     123
     124        /* Set up a connection handler. */
     125        fun->conn_handler = usbmast_bd_connection;
     126        fun->driver_data = msfun;
     127
     128        usb_log_info("Initializing mass storage `%s'.\n",
    101129            dev->ddf_dev->name);
    102130        usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
     
    107135            (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
    108136
     137        usb_log_debug("Get LUN count...\n");
    109138        size_t lun_count = usb_masstor_get_lun_count(dev);
    110139
    111         usb_massstor_inquiry_result_t inquiry;
    112         rc = usb_massstor_inquiry(dev, BULK_IN_EP, BULK_OUT_EP, &inquiry);
     140        /* XXX Handle more than one LUN properly. */
     141        if (lun_count > 1) {
     142                usb_log_warning ("Mass storage has %zu LUNs. Ignoring all "
     143                    "but first.\n", lun_count);
     144        }
     145
     146        usb_log_debug("Inquire...\n");
     147        usbmast_inquiry_data_t inquiry;
     148        rc = usbmast_inquiry(dev, &inquiry);
    113149        if (rc != EOK) {
    114                 usb_log_warning("Failed to inquiry device `%s': %s.\n",
     150                usb_log_warning("Failed to inquire device `%s': %s.\n",
    115151                    dev->ddf_dev->name, str_error(rc));
    116                 return EOK;
     152                rc = EIO;
     153                goto error;
    117154        }
    118155
    119156        usb_log_info("Mass storage `%s': " \
    120             "`%s' by `%s' is %s (%s), %zu LUN(s).\n",
     157            "%s by %s rev. %s is %s (%s), %zu LUN(s).\n",
    121158            dev->ddf_dev->name,
    122             inquiry.product_and_revision, inquiry.vendor_id,
    123             usb_str_masstor_scsi_peripheral_device_type(inquiry.peripheral_device_type),
     159            inquiry.product,
     160            inquiry.vendor,
     161            inquiry.revision,
     162            usbmast_scsi_dev_type_str(inquiry.device_type),
    124163            inquiry.removable ? "removable" : "non-removable",
    125164            lun_count);
    126165
     166        uint32_t nblocks, block_size;
     167
     168        rc = usbmast_read_capacity(dev, &nblocks, &block_size);
     169        if (rc != EOK) {
     170                usb_log_warning("Failed to read capacity, device `%s': %s.\n",
     171                    dev->ddf_dev->name, str_error(rc));
     172                rc = EIO;
     173                goto error;
     174        }
     175
     176        usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
     177            "block_size=%" PRIu32 "\n", nblocks, block_size);
     178
     179        msfun->nblocks = nblocks;
     180        msfun->block_size = block_size;
     181        msfun->usb_dev = dev;
     182
     183        rc = ddf_fun_bind(fun);
     184        if (rc != EOK) {
     185                usb_log_error("Failed to bind DDF function %s: %s.\n",
     186                    fun_name, str_error(rc));
     187                goto error;
     188        }
     189
    127190        return EOK;
     191
     192        /* Error cleanup */
     193error:
     194        if (fun != NULL)
     195                ddf_fun_destroy(fun);
     196        if (msfun != NULL)
     197                free(msfun);
     198        return rc;
     199}
     200
     201/** Blockdev client connection handler. */
     202static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
     203    void *arg)
     204{
     205        usbmast_fun_t *msfun;
     206        void *comm_buf = NULL;
     207        size_t comm_size;
     208        ipc_callid_t callid;
     209        ipc_call_t call;
     210        unsigned int flags;
     211        sysarg_t method;
     212        uint64_t ba;
     213        size_t cnt;
     214        int retval;
     215
     216        async_answer_0(iid, EOK);
     217
     218        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
     219                async_answer_0(callid, EHANGUP);
     220                return;
     221        }
     222
     223        comm_buf = as_get_mappable_page(comm_size);
     224        if (comm_buf == NULL) {
     225                async_answer_0(callid, EHANGUP);
     226                return;
     227        }
     228
     229        (void) async_share_out_finalize(callid, comm_buf);
     230
     231        msfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
     232
     233        while (true) {
     234                callid = async_get_call(&call);
     235                method = IPC_GET_IMETHOD(call);
     236
     237                if (!method) {
     238                        /* The other side hung up. */
     239                        async_answer_0(callid, EOK);
     240                        return;
     241                }
     242
     243                switch (method) {
     244                case BD_GET_BLOCK_SIZE:
     245                        async_answer_1(callid, EOK, msfun->block_size);
     246                        break;
     247                case BD_GET_NUM_BLOCKS:
     248                        async_answer_2(callid, EOK, LOWER32(msfun->nblocks),
     249                            UPPER32(msfun->nblocks));
     250                        break;
     251                case BD_READ_BLOCKS:
     252                        ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     253                        cnt = IPC_GET_ARG3(call);
     254                        retval = usbmast_read(msfun->usb_dev, ba, cnt,
     255                            msfun->block_size, comm_buf);
     256                        async_answer_0(callid, retval);
     257                        break;
     258                case BD_WRITE_BLOCKS:
     259                        ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     260                        cnt = IPC_GET_ARG3(call);
     261                        retval = usbmast_write(msfun->usb_dev, ba, cnt,
     262                            msfun->block_size, comm_buf);
     263                        async_answer_0(callid, retval);
     264                        break;
     265                default:
     266                        async_answer_0(callid, EINVAL);
     267                }
     268        }
    128269}
    129270
Note: See TracChangeset for help on using the changeset viewer.