source: mainline/uspace/drv/block/usbmast/main.c@ 2fc9bfd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2fc9bfd was 1433ecda, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

  • Property mode set to 100644
File size: 10.8 KB
RevLine 
[2715978]1/*
2 * Copyright (c) 2011 Vojtech Horky
[ff65e91]3 * Copyright (c) 2011 Jiri Svoboda
[e0a5d4c]4 * Copyright (c) 2018 Ondrej Hlavaty
[2715978]5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup drvusbmast
32 * @{
33 */
34/**
35 * @file
36 * Main routines of USB mass storage driver.
37 */
[58563585]38
[ff65e91]39#include <as.h>
40#include <async.h>
[4802dd7]41#include <bd_srv.h>
[ff65e91]42#include <macros.h>
[7d521e24]43#include <usb/dev/driver.h>
[2715978]44#include <usb/debug.h>
45#include <usb/classes/classes.h>
46#include <usb/classes/massstor.h>
47#include <errno.h>
[7a1757e]48#include <io/logctl.h>
[2715978]49#include <str_error.h>
[89d3f3c7]50#include "cmdw.h"
51#include "bo_trans.h"
[6430ac6]52#include "scsi_ms.h"
[7190bbc]53#include "usbmast.h"
[2715978]54
55#define NAME "usbmast"
56
[9871bca]57static const usb_endpoint_description_t bulk_in_ep = {
[2715978]58 .transfer_type = USB_TRANSFER_BULK,
59 .direction = USB_DIRECTION_IN,
60 .interface_class = USB_CLASS_MASS_STORAGE,
61 .interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
62 .interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
63 .flags = 0
64};
[9871bca]65static const usb_endpoint_description_t bulk_out_ep = {
[2715978]66 .transfer_type = USB_TRANSFER_BULK,
67 .direction = USB_DIRECTION_OUT,
68 .interface_class = USB_CLASS_MASS_STORAGE,
69 .interface_subclass = USB_MASSSTOR_SUBCLASS_SCSI,
70 .interface_protocol = USB_MASSSTOR_PROTOCOL_BBB,
71 .flags = 0
72};
73
[b803845]74static const usb_endpoint_description_t *mast_endpoints[] = {
[2715978]75 &bulk_in_ep,
76 &bulk_out_ep,
77 NULL
78};
79
[5a6cc679]80static errno_t usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun);
[a46e56b]81static void usbmast_bd_connection(cap_call_handle_t icall_handle, ipc_call_t *icall,
[ff65e91]82 void *arg);
83
[5a6cc679]84static errno_t usbmast_bd_open(bd_srvs_t *, bd_srv_t *);
85static errno_t usbmast_bd_close(bd_srv_t *);
86static errno_t usbmast_bd_read_blocks(bd_srv_t *, aoff64_t, size_t, void *, size_t);
87static errno_t usbmast_bd_sync_cache(bd_srv_t *, aoff64_t, size_t);
88static errno_t usbmast_bd_write_blocks(bd_srv_t *, aoff64_t, size_t, const void *, size_t);
89static errno_t usbmast_bd_get_block_size(bd_srv_t *, size_t *);
90static errno_t usbmast_bd_get_num_blocks(bd_srv_t *, aoff64_t *);
[4802dd7]91
92static bd_ops_t usbmast_bd_ops = {
93 .open = usbmast_bd_open,
94 .close = usbmast_bd_close,
95 .read_blocks = usbmast_bd_read_blocks,
[dd8b6a8]96 .sync_cache = usbmast_bd_sync_cache,
[4802dd7]97 .write_blocks = usbmast_bd_write_blocks,
98 .get_block_size = usbmast_bd_get_block_size,
99 .get_num_blocks = usbmast_bd_get_num_blocks
100};
101
102static usbmast_fun_t *bd_srv_usbmast(bd_srv_t *bd)
103{
[f73b291]104 return (usbmast_fun_t *) bd->srvs->sarg;
[4802dd7]105}
106
[3002434]107/** Callback when a device is removed from the system.
108 *
109 * @param dev Representation of USB device.
110 * @return Error code.
111 */
[5a6cc679]112static errno_t usbmast_device_gone(usb_device_t *dev)
[3002434]113{
[c39e9fb]114 usbmast_dev_t *mdev = usb_device_data_get(dev);
[3002434]115 assert(mdev);
116
117 for (size_t i = 0; i < mdev->lun_count; ++i) {
[5a6cc679]118 const errno_t rc = ddf_fun_unbind(mdev->luns[i]);
[3002434]119 if (rc != EOK) {
120 usb_log_error("Failed to unbind LUN function %zu: "
121 "%s\n", i, str_error(rc));
122 return rc;
123 }
124 ddf_fun_destroy(mdev->luns[i]);
125 mdev->luns[i] = NULL;
126 }
127 free(mdev->luns);
128 return EOK;
129}
130
[9871bca]131/** Callback when a device is about to be removed.
132 *
133 * @param dev Representation of USB device.
134 * @return Error code.
135 */
[5a6cc679]136static errno_t usbmast_device_remove(usb_device_t *dev)
[9871bca]137{
138 //TODO: flush buffers, or whatever.
[dcc10b8d]139 //TODO: remove device
[9871bca]140 return ENOTSUP;
141}
142
[2715978]143/** Callback when new device is attached and recognized as a mass storage.
144 *
[9871bca]145 * @param dev Representation of USB device.
[2715978]146 * @return Error code.
147 */
[5a6cc679]148static errno_t usbmast_device_add(usb_device_t *dev)
[2715978]149{
[5a6cc679]150 errno_t rc;
[2aceec5]151 usbmast_dev_t *mdev = NULL;
152 unsigned i;
[2715978]153
[3e23316]154 usb_endpoint_mapping_t *epm_in =
155 usb_device_get_mapped_ep_desc(dev, &bulk_in_ep);
156 usb_endpoint_mapping_t *epm_out =
157 usb_device_get_mapped_ep_desc(dev, &bulk_out_ep);
158 if (!epm_in || !epm_out || !epm_in->present || !epm_out->present) {
[a1732929]159 usb_log_error("Required EPs were not mapped.");
[3e23316]160 return ENOENT;
161 }
162
[ff65e91]163 /* Allocate softstate */
[065064e6]164 mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
[2aceec5]165 if (mdev == NULL) {
[a1732929]166 usb_log_error("Failed allocating softstate.");
[d6c953e9]167 return ENOMEM;
[2715978]168 }
[ff65e91]169
[2aceec5]170 mdev->usb_dev = dev;
[ff65e91]171
[a1732929]172 usb_log_info("Initializing mass storage `%s'.",
[7c69861]173 usb_device_get_name(dev));
[a1732929]174 usb_log_debug("Bulk in endpoint: %d [%zuB].",
[9efad54]175 epm_in->pipe.desc.endpoint_no, epm_in->pipe.desc.max_transfer_size);
[a1732929]176 usb_log_debug("Bulk out endpoint: %d [%zuB].",
[9efad54]177 epm_out->pipe.desc.endpoint_no, epm_out->pipe.desc.max_transfer_size);
[2715978]178
[a1732929]179 usb_log_debug("Get LUN count...");
[87037cc9]180 mdev->lun_count = usb_masstor_get_lun_count(mdev);
[1433ecda]181 mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t *));
[87037cc9]182 if (mdev->luns == NULL) {
[a1732929]183 usb_log_error("Failed allocating luns table.");
[4172db4a]184 return ENOMEM;
[87037cc9]185 }
[239e7e10]186
[3cc55b47]187 mdev->bulk_in_pipe = &epm_in->pipe;
188 mdev->bulk_out_pipe = &epm_out->pipe;
[87037cc9]189 for (i = 0; i < mdev->lun_count; i++) {
[2aceec5]190 rc = usbmast_fun_create(mdev, i);
191 if (rc != EOK)
192 goto error;
[ff65e91]193 }
194
[2aceec5]195 return EOK;
196error:
[3002434]197 /* Destroy functions */
198 for (size_t i = 0; i < mdev->lun_count; ++i) {
199 if (mdev->luns[i] == NULL)
200 continue;
[5a6cc679]201 const errno_t rc = ddf_fun_unbind(mdev->luns[i]);
[3002434]202 if (rc != EOK) {
203 usb_log_warning("Failed to unbind LUN function %zu: "
204 "%s.\n", i, str_error(rc));
205 }
206 ddf_fun_destroy(mdev->luns[i]);
207 }
208 free(mdev->luns);
[2aceec5]209 return rc;
210}
211
212/** Create mass storage function.
213 *
214 * Called once for each LUN.
215 *
216 * @param mdev Mass storage device
217 * @param lun LUN
[cde999a]218 * @return EOK on success or an error code.
[2aceec5]219 */
[5a6cc679]220static errno_t usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
[2aceec5]221{
[5a6cc679]222 errno_t rc;
[2aceec5]223 char *fun_name = NULL;
224 ddf_fun_t *fun = NULL;
225 usbmast_fun_t *mfun = NULL;
226
227 if (asprintf(&fun_name, "l%u", lun) < 0) {
[a1732929]228 usb_log_error("Out of memory.");
[2aceec5]229 rc = ENOMEM;
230 goto error;
231 }
232
[7c69861]233 fun = usb_device_ddf_fun_create(mdev->usb_dev, fun_exposed, fun_name);
[2aceec5]234 if (fun == NULL) {
[a1732929]235 usb_log_error("Failed to create DDF function %s.", fun_name);
[2aceec5]236 rc = ENOMEM;
237 goto error;
238 }
239
[5f6e25e]240 /* Allocate soft state */
[d95f02ff]241 mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
[5f6e25e]242 if (mfun == NULL) {
[a1732929]243 usb_log_error("Failed allocating softstate.");
[5f6e25e]244 rc = ENOMEM;
245 goto error;
246 }
247
[87037cc9]248 mfun->ddf_fun = fun;
[5f6e25e]249 mfun->mdev = mdev;
250 mfun->lun = lun;
251
[135486d]252 bd_srvs_init(&mfun->bds);
253 mfun->bds.ops = &usbmast_bd_ops;
254 mfun->bds.sarg = mfun;
[4802dd7]255
[2aceec5]256 /* Set up a connection handler. */
[56fd7cf]257 ddf_fun_set_conn_handler(fun, usbmast_bd_connection);
[2aceec5]258
[a1732929]259 usb_log_debug("Inquire...");
[6430ac6]260 usbmast_inquiry_data_t inquiry;
[2aceec5]261 rc = usbmast_inquiry(mfun, &inquiry);
[70c12d6]262 if (rc != EOK) {
[a1732929]263 usb_log_warning("Failed to inquire device `%s': %s.",
[7c69861]264 usb_device_get_name(mdev->usb_dev), str_error(rc));
[ff65e91]265 rc = EIO;
266 goto error;
[70c12d6]267 }
268
[5ef16903]269 usb_log_info("Mass storage `%s' LUN %u: "
[2aceec5]270 "%s by %s rev. %s is %s (%s).\n",
[7c69861]271 usb_device_get_name(mdev->usb_dev),
[2aceec5]272 lun,
[7b2c17c]273 inquiry.product,
274 inquiry.vendor,
275 inquiry.revision,
[6430ac6]276 usbmast_scsi_dev_type_str(inquiry.device_type),
[2aceec5]277 inquiry.removable ? "removable" : "non-removable");
[7a5c8b8f]278
[71fa44c]279 uint32_t nblocks, block_size;
280
[2aceec5]281 rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
[71fa44c]282 if (rc != EOK) {
[a1732929]283 usb_log_warning("Failed to read capacity, device `%s': %s.",
[7c69861]284 usb_device_get_name(mdev->usb_dev), str_error(rc));
[ff65e91]285 rc = EIO;
286 goto error;
[71fa44c]287 }
288
289 usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
290 "block_size=%" PRIu32 "\n", nblocks, block_size);
291
[2aceec5]292 mfun->nblocks = nblocks;
293 mfun->block_size = block_size;
[f7a55f9]294
[ff65e91]295 rc = ddf_fun_bind(fun);
[f7a55f9]296 if (rc != EOK) {
[a1732929]297 usb_log_error("Failed to bind DDF function %s: %s.",
[ff65e91]298 fun_name, str_error(rc));
299 goto error;
[f7a55f9]300 }
301
[f97f5cc2]302 ddf_fun_add_to_category(fun, "disk");
303
[60c6fe0]304 free(fun_name);
[87037cc9]305 mdev->luns[lun] = fun;
[60c6fe0]306
[ff65e91]307 return EOK;
[f7a55f9]308
[ff65e91]309 /* Error cleanup */
310error:
311 if (fun != NULL)
312 ddf_fun_destroy(fun);
[2aceec5]313 if (fun_name != NULL)
314 free(fun_name);
[ff65e91]315 return rc;
316}
317
318/** Blockdev client connection handler. */
[a46e56b]319static void usbmast_bd_connection(cap_call_handle_t icall_handle, ipc_call_t *icall,
[ff65e91]320 void *arg)
321{
[2aceec5]322 usbmast_fun_t *mfun;
[4802dd7]323
[56fd7cf]324 mfun = (usbmast_fun_t *) ddf_fun_data_get((ddf_fun_t *)arg);
[a46e56b]325 bd_conn(icall_handle, icall, &mfun->bds);
[4802dd7]326}
[ff65e91]327
[4802dd7]328/** Open device. */
[5a6cc679]329static errno_t usbmast_bd_open(bd_srvs_t *bds, bd_srv_t *bd)
[4802dd7]330{
331 return EOK;
332}
[ff65e91]333
[4802dd7]334/** Close device. */
[5a6cc679]335static errno_t usbmast_bd_close(bd_srv_t *bd)
[4802dd7]336{
337 return EOK;
338}
[ff65e91]339
[4802dd7]340/** Read blocks from the device. */
[5a6cc679]341static errno_t usbmast_bd_read_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt, void *buf,
[4802dd7]342 size_t size)
343{
344 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
345
346 if (size < cnt * mfun->block_size)
347 return EINVAL;
348
349 return usbmast_read(mfun, ba, cnt, buf);
350}
351
[dd8b6a8]352/** Synchronize blocks to nonvolatile storage. */
[5a6cc679]353static errno_t usbmast_bd_sync_cache(bd_srv_t *bd, uint64_t ba, size_t cnt)
[dd8b6a8]354{
355 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
356
357 return usbmast_sync_cache(mfun, ba, cnt);
358}
359
[4802dd7]360/** Write blocks to the device. */
[5a6cc679]361static errno_t usbmast_bd_write_blocks(bd_srv_t *bd, uint64_t ba, size_t cnt,
[4802dd7]362 const void *buf, size_t size)
363{
364 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
365
366 if (size < cnt * mfun->block_size)
367 return EINVAL;
368
369 return usbmast_write(mfun, ba, cnt, buf);
[2715978]370}
371
[4802dd7]372/** Get device block size. */
[5a6cc679]373static errno_t usbmast_bd_get_block_size(bd_srv_t *bd, size_t *rsize)
[4802dd7]374{
375 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
376 *rsize = mfun->block_size;
377 return EOK;
378}
379
380/** Get number of blocks on device. */
[5a6cc679]381static errno_t usbmast_bd_get_num_blocks(bd_srv_t *bd, aoff64_t *rnb)
[4802dd7]382{
383 usbmast_fun_t *mfun = bd_srv_usbmast(bd);
384 *rnb = mfun->nblocks;
385 return EOK;
386}
387
388
[2715978]389/** USB mass storage driver ops. */
[9871bca]390static const usb_driver_ops_t usbmast_driver_ops = {
[1a4ea01d]391 .device_add = usbmast_device_add,
[c54b898]392 .device_remove = usbmast_device_remove,
[3002434]393 .device_gone = usbmast_device_gone,
[2715978]394};
395
396/** USB mass storage driver. */
[9871bca]397static const usb_driver_t usbmast_driver = {
[2715978]398 .name = NAME,
399 .ops = &usbmast_driver_ops,
400 .endpoints = mast_endpoints
401};
402
403int main(int argc, char *argv[])
404{
[920d0fc]405 log_init(NAME);
[7a1757e]406 logctl_set_log_level(NAME, LVL_NOTE);
[2715978]407 return usb_driver_main(&usbmast_driver);
408}
409
410/**
411 * @}
412 */
Note: See TracBrowser for help on using the repository browser.