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


Ignore:
Timestamp:
2011-08-07T11:21:44Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
cc574511
Parents:
15f3c3f (diff), e8067c0 (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

    r15f3c3f r86ffa27f  
    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>
     
    4045#include <errno.h>
    4146#include <str_error.h>
    42 #include "cmds.h"
    43 #include "scsi.h"
    44 #include "mast.h"
     47#include "cmdw.h"
     48#include "bo_trans.h"
     49#include "scsi_ms.h"
     50#include "usbmast.h"
    4551
    4652#define NAME "usbmast"
    47 
    48 #define BULK_IN_EP 0
    49 #define BULK_OUT_EP 1
    5053
    5154#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
     
    7578};
    7679
     80static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
     81static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
     82    void *arg);
     83
    7784/** Callback when new device is attached and recognized as a mass storage.
    7885 *
     
    8390{
    8491        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",
     92        usbmast_dev_t *mdev = NULL;
     93        unsigned i;
     94
     95        /* Allocate softstate */
     96        mdev = calloc(1, sizeof(usbmast_dev_t));
     97        if (mdev == NULL) {
     98                usb_log_error("Failed allocating softstate.\n");
     99                rc = ENOMEM;
     100                goto error;
     101        }
     102
     103        mdev->ddf_dev = dev->ddf_dev;
     104        mdev->usb_dev = dev;
     105
     106        usb_log_info("Initializing mass storage `%s'.\n",
    101107            dev->ddf_dev->name);
    102108        usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
     
    107113            (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
    108114
    109         size_t lun_count = usb_masstor_get_lun_count(dev);
    110 
    111         usb_massstor_inquiry_result_t inquiry;
    112         rc = usb_massstor_inquiry(dev, BULK_IN_EP, BULK_OUT_EP, &inquiry);
     115        usb_log_debug("Get LUN count...\n");
     116        mdev->luns = usb_masstor_get_lun_count(mdev);
     117
     118        for (i = 0; i < mdev->luns; i++) {
     119                rc = usbmast_fun_create(mdev, i);
     120                if (rc != EOK)
     121                        goto error;
     122        }
     123
     124        return EOK;
     125error:
     126        /* XXX Destroy functions */
     127        if (mdev != NULL)
     128                free(mdev);
     129        return rc;
     130}
     131
     132/** Create mass storage function.
     133 *
     134 * Called once for each LUN.
     135 *
     136 * @param mdev          Mass storage device
     137 * @param lun           LUN
     138 * @return              EOK on success or negative error code.
     139 */
     140static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
     141{
     142        int rc;
     143        char *fun_name = NULL;
     144        ddf_fun_t *fun = NULL;
     145        usbmast_fun_t *mfun = NULL;
     146
     147        /* Allocate softstate */
     148        mfun = calloc(1, sizeof(usbmast_fun_t));
     149        if (mfun == NULL) {
     150                usb_log_error("Failed allocating softstate.\n");
     151                rc = ENOMEM;
     152                goto error;
     153        }
     154
     155        mfun->mdev = mdev;
     156        mfun->lun = lun;
     157
     158        if (asprintf(&fun_name, "l%u", lun) < 0) {
     159                usb_log_error("Out of memory.\n");
     160                rc = ENOMEM;
     161                goto error;
     162        }
     163
     164        fun = ddf_fun_create(mdev->ddf_dev, fun_exposed, fun_name);
     165        if (fun == NULL) {
     166                usb_log_error("Failed to create DDF function %s.\n", fun_name);
     167                rc = ENOMEM;
     168                goto error;
     169        }
     170
     171        free(fun_name);
     172        fun_name = NULL;
     173
     174        /* Set up a connection handler. */
     175        fun->conn_handler = usbmast_bd_connection;
     176        fun->driver_data = mfun;
     177
     178        usb_log_debug("Inquire...\n");
     179        usbmast_inquiry_data_t inquiry;
     180        rc = usbmast_inquiry(mfun, &inquiry);
    113181        if (rc != EOK) {
    114                 usb_log_warning("Failed to inquiry device `%s': %s.\n",
    115                     dev->ddf_dev->name, str_error(rc));
    116                 return EOK;
    117         }
    118 
    119         usb_log_info("Mass storage `%s': " \
    120             "`%s' by `%s' is %s (%s), %zu LUN(s).\n",
    121             dev->ddf_dev->name,
    122             inquiry.product_and_revision, inquiry.vendor_id,
    123             usb_str_masstor_scsi_peripheral_device_type(inquiry.peripheral_device_type),
    124             inquiry.removable ? "removable" : "non-removable",
    125             lun_count);
     182                usb_log_warning("Failed to inquire device `%s': %s.\n",
     183                    mdev->ddf_dev->name, str_error(rc));
     184                rc = EIO;
     185                goto error;
     186        }
     187
     188        usb_log_info("Mass storage `%s' LUN %u: " \
     189            "%s by %s rev. %s is %s (%s).\n",
     190            mdev->ddf_dev->name,
     191            lun,
     192            inquiry.product,
     193            inquiry.vendor,
     194            inquiry.revision,
     195            usbmast_scsi_dev_type_str(inquiry.device_type),
     196            inquiry.removable ? "removable" : "non-removable");
     197
     198        uint32_t nblocks, block_size;
     199
     200        rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
     201        if (rc != EOK) {
     202                usb_log_warning("Failed to read capacity, device `%s': %s.\n",
     203                    mdev->ddf_dev->name, str_error(rc));
     204                rc = EIO;
     205                goto error;
     206        }
     207
     208        usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
     209            "block_size=%" PRIu32 "\n", nblocks, block_size);
     210
     211        mfun->nblocks = nblocks;
     212        mfun->block_size = block_size;
     213
     214        rc = ddf_fun_bind(fun);
     215        if (rc != EOK) {
     216                usb_log_error("Failed to bind DDF function %s: %s.\n",
     217                    fun_name, str_error(rc));
     218                goto error;
     219        }
    126220
    127221        return EOK;
     222
     223        /* Error cleanup */
     224error:
     225        if (fun != NULL)
     226                ddf_fun_destroy(fun);
     227        if (fun_name != NULL)
     228                free(fun_name);
     229        if (mfun != NULL)
     230                free(mfun);
     231        return rc;
     232}
     233
     234/** Blockdev client connection handler. */
     235static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
     236    void *arg)
     237{
     238        usbmast_fun_t *mfun;
     239        void *comm_buf = NULL;
     240        size_t comm_size;
     241        ipc_callid_t callid;
     242        ipc_call_t call;
     243        unsigned int flags;
     244        sysarg_t method;
     245        uint64_t ba;
     246        size_t cnt;
     247        int retval;
     248
     249        async_answer_0(iid, EOK);
     250
     251        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
     252                async_answer_0(callid, EHANGUP);
     253                return;
     254        }
     255
     256        comm_buf = as_get_mappable_page(comm_size);
     257        if (comm_buf == NULL) {
     258                async_answer_0(callid, EHANGUP);
     259                return;
     260        }
     261
     262        (void) async_share_out_finalize(callid, comm_buf);
     263
     264        mfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
     265
     266        while (true) {
     267                callid = async_get_call(&call);
     268                method = IPC_GET_IMETHOD(call);
     269
     270                if (!method) {
     271                        /* The other side hung up. */
     272                        async_answer_0(callid, EOK);
     273                        return;
     274                }
     275
     276                switch (method) {
     277                case BD_GET_BLOCK_SIZE:
     278                        async_answer_1(callid, EOK, mfun->block_size);
     279                        break;
     280                case BD_GET_NUM_BLOCKS:
     281                        async_answer_2(callid, EOK, LOWER32(mfun->nblocks),
     282                            UPPER32(mfun->nblocks));
     283                        break;
     284                case BD_READ_BLOCKS:
     285                        ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     286                        cnt = IPC_GET_ARG3(call);
     287                        retval = usbmast_read(mfun, ba, cnt, comm_buf);
     288                        async_answer_0(callid, retval);
     289                        break;
     290                case BD_WRITE_BLOCKS:
     291                        ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     292                        cnt = IPC_GET_ARG3(call);
     293                        retval = usbmast_write(mfun, ba, cnt, comm_buf);
     294                        async_answer_0(callid, retval);
     295                        break;
     296                default:
     297                        async_answer_0(callid, EINVAL);
     298                }
     299        }
    128300}
    129301
Note: See TracChangeset for help on using the changeset viewer.