source: mainline/uspace/drv/bus/usb/usbmast/main.c@ fa65df1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fa65df1 was 8e7c9fe, checked in by Jan Vesely <jano.vesely@…>, 11 years ago

merge mainline changes

most usb changes were reverted. blink and usbmass were fixed
known problems:
ehci won't initialize
usbmast asserts on unmount (happens on mainline too)

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