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


Ignore:
Timestamp:
2011-07-06T19:45:55Z (13 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
38c9505
Parents:
5e2aa83
Message:

Implement block device interface in USB mass storage driver.
Allow DDF driver to provide its own connection handler for a function.
Fix bug in ata_bd, comm_size is per-connection, not global.

File:
1 edited

Legend:

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

    r5e2aa83 rff65e91  
    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>
     
    7277};
    7378
     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
    7497/** Callback when new device is attached and recognized as a mass storage.
    7598 *
     
    80103{
    81104        int rc;
    82         const char *fun_name = "ctl";
    83 
    84         ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed,
    85             fun_name);
    86         if (ctl_fun == NULL) {
    87                 usb_log_error("Failed to create control function.\n");
    88                 return ENOMEM;
    89         }
    90         rc = ddf_fun_bind(ctl_fun);
    91         if (rc != EOK) {
    92                 usb_log_error("Failed to bind control function: %s.\n",
    93                     str_error(rc));
    94                 return rc;
    95         }
    96 
    97         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",
    98129            dev->ddf_dev->name);
    99130        usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
     
    107138        size_t lun_count = usb_masstor_get_lun_count(dev);
    108139
     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
    109146        usb_log_debug("Inquire...\n");
    110147        usbmast_inquiry_data_t inquiry;
     
    113150                usb_log_warning("Failed to inquire device `%s': %s.\n",
    114151                    dev->ddf_dev->name, str_error(rc));
    115                 return EOK;
     152                rc = EIO;
     153                goto error;
    116154        }
    117155
     
    132170                usb_log_warning("Failed to read capacity, device `%s': %s.\n",
    133171                    dev->ddf_dev->name, str_error(rc));
    134                 return EOK;
     172                rc = EIO;
     173                goto error;
    135174        }
    136175
     
    138177            "block_size=%" PRIu32 "\n", nblocks, block_size);
    139178
    140         usb_log_info("Doing test read of block 0.\n");
    141         static uint8_t bdata[512];
    142 
    143         rc = usbmast_read(dev, 0, 1, 512, &bdata);
     179        msfun->nblocks = nblocks;
     180        msfun->block_size = block_size;
     181        msfun->usb_dev = dev;
     182
     183        rc = ddf_fun_bind(fun);
    144184        if (rc != EOK) {
    145                 usb_log_warning("Failed to read block 0, device `%s': %s.\n",
    146                     dev->ddf_dev->name, str_error(rc));
    147                 return EOK;
    148         }
    149 
    150         usb_log_info("Requesting sense data.\n");
    151         static scsi_sense_data_t sdata;
    152 
    153         rc = usbmast_request_sense(dev, &sdata, sizeof(sdata));
    154         if (rc != EOK) {
    155                 usb_log_warning("Failed to get sense data, device `%s': %s.\n",
    156                     dev->ddf_dev->name, str_error(rc));
    157                 return EOK;
     185                usb_log_error("Failed to bind DDF function %s: %s.\n",
     186                    fun_name, str_error(rc));
     187                goto error;
    158188        }
    159189
    160190        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        usb_log_debug("usbmast_bd_connection()\n");
     217
     218        async_answer_0(iid, EOK);
     219
     220        if (!async_share_out_receive(&callid, &comm_size, &flags)) {
     221                async_answer_0(callid, EHANGUP);
     222                return;
     223        }
     224
     225        comm_buf = as_get_mappable_page(comm_size);
     226        if (comm_buf == NULL) {
     227                async_answer_0(callid, EHANGUP);
     228                return;
     229        }
     230
     231        (void) async_share_out_finalize(callid, comm_buf);
     232
     233        msfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
     234
     235        while (true) {
     236                callid = async_get_call(&call);
     237                method = IPC_GET_IMETHOD(call);
     238
     239                if (!method) {
     240                        /* The other side hung up. */
     241                        async_answer_0(callid, EOK);
     242                        return;
     243                }
     244
     245                switch (method) {
     246                case BD_GET_BLOCK_SIZE:
     247                        async_answer_1(callid, EOK, msfun->block_size);
     248                        break;
     249                case BD_GET_NUM_BLOCKS:
     250                        async_answer_2(callid, EOK, LOWER32(msfun->nblocks),
     251                            UPPER32(msfun->nblocks));
     252                        break;
     253                case BD_READ_BLOCKS:
     254                        ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     255                        cnt = IPC_GET_ARG3(call);
     256                        retval = usbmast_read(msfun->usb_dev, ba, cnt,
     257                            msfun->block_size, comm_buf);
     258                        async_answer_0(callid, retval);
     259                        break;
     260                case BD_WRITE_BLOCKS:
     261                        usb_log_debug("usbmast_bd_connection() - BD_WRITE_BLOCKS\n");
     262/*                      ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
     263                        cnt = IPC_GET_ARG3(call);
     264                        retval = 0;
     265                        async_answer_0(callid, retval);
     266                        break;*/
     267                default:
     268                        async_answer_0(callid, EINVAL);
     269                }
     270        }
    161271}
    162272
Note: See TracChangeset for help on using the changeset viewer.