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

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

Minor USB changes.

Add more const qualifiers where possible.
Do not limit the number possible usbhid subdrivers.
This should not break anything. If it does feel free to revert this merge.

  • Property mode set to 100644
File size: 9.1 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 <ipc/bd.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
54#define GET_BULK_IN(dev) ((dev)->pipes[BULK_IN_EP].pipe)
55#define GET_BULK_OUT(dev) ((dev)->pipes[BULK_OUT_EP].pipe)
56
57static usb_endpoint_description_t bulk_in_ep = {
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};
65static usb_endpoint_description_t bulk_out_ep = {
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
74static const usb_endpoint_description_t *mast_endpoints[] = {
75 &bulk_in_ep,
76 &bulk_out_ep,
77 NULL
78};
79
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
84/** Callback when a device is removed from the system.
85 *
86 * @param dev Representation of USB device.
87 * @return Error code.
88 */
89static int usbmast_device_gone(usb_device_t *dev)
90{
91 usbmast_dev_t *mdev = dev->driver_data;
92 assert(mdev);
93
94 for (size_t i = 0; i < mdev->lun_count; ++i) {
95 const int rc = ddf_fun_unbind(mdev->luns[i]);
96 if (rc != EOK) {
97 usb_log_error("Failed to unbind LUN function %zu: "
98 "%s\n", i, str_error(rc));
99 return rc;
100 }
101 ddf_fun_destroy(mdev->luns[i]);
102 mdev->luns[i] = NULL;
103 }
104 free(mdev->luns);
105 return EOK;
106}
107
108/** Callback when new device is attached and recognized as a mass storage.
109 *
110 * @param dev Representation of a the USB device.
111 * @return Error code.
112 */
113static int usbmast_device_add(usb_device_t *dev)
114{
115 int rc;
116 usbmast_dev_t *mdev = NULL;
117 unsigned i;
118
119 /* Allocate softstate */
120 mdev = usb_device_data_alloc(dev, sizeof(usbmast_dev_t));
121 if (mdev == NULL) {
122 usb_log_error("Failed allocating softstate.\n");
123 return ENOMEM;
124 }
125
126 mdev->ddf_dev = dev->ddf_dev;
127 mdev->usb_dev = dev;
128
129 usb_log_info("Initializing mass storage `%s'.\n", dev->ddf_dev->name);
130 usb_log_debug(" Bulk in endpoint: %d [%zuB].\n",
131 dev->pipes[BULK_IN_EP].pipe->endpoint_no,
132 (size_t) dev->pipes[BULK_IN_EP].descriptor->max_packet_size);
133 usb_log_debug("Bulk out endpoint: %d [%zuB].\n",
134 dev->pipes[BULK_OUT_EP].pipe->endpoint_no,
135 (size_t) dev->pipes[BULK_OUT_EP].descriptor->max_packet_size);
136
137 usb_log_debug("Get LUN count...\n");
138 mdev->lun_count = usb_masstor_get_lun_count(mdev);
139 mdev->luns = calloc(mdev->lun_count, sizeof(ddf_fun_t*));
140 if (mdev->luns == NULL) {
141 rc = ENOMEM;
142 usb_log_error("Failed allocating luns table.\n");
143 goto error;
144 }
145
146 for (i = 0; i < mdev->lun_count; i++) {
147 rc = usbmast_fun_create(mdev, i);
148 if (rc != EOK)
149 goto error;
150 }
151
152 return EOK;
153error:
154 /* Destroy functions */
155 for (size_t i = 0; i < mdev->lun_count; ++i) {
156 if (mdev->luns[i] == NULL)
157 continue;
158 const int rc = ddf_fun_unbind(mdev->luns[i]);
159 if (rc != EOK) {
160 usb_log_warning("Failed to unbind LUN function %zu: "
161 "%s.\n", i, str_error(rc));
162 }
163 ddf_fun_destroy(mdev->luns[i]);
164 }
165 free(mdev->luns);
166 return rc;
167}
168
169/** Create mass storage function.
170 *
171 * Called once for each LUN.
172 *
173 * @param mdev Mass storage device
174 * @param lun LUN
175 * @return EOK on success or negative error code.
176 */
177static int usbmast_fun_create(usbmast_dev_t *mdev, unsigned lun)
178{
179 int rc;
180 char *fun_name = NULL;
181 ddf_fun_t *fun = NULL;
182 usbmast_fun_t *mfun = NULL;
183
184 if (asprintf(&fun_name, "l%u", lun) < 0) {
185 usb_log_error("Out of memory.\n");
186 rc = ENOMEM;
187 goto error;
188 }
189
190 fun = ddf_fun_create(mdev->ddf_dev, fun_exposed, fun_name);
191 if (fun == NULL) {
192 usb_log_error("Failed to create DDF function %s.\n", fun_name);
193 rc = ENOMEM;
194 goto error;
195 }
196
197 /* Allocate soft state */
198 mfun = ddf_fun_data_alloc(fun, sizeof(usbmast_fun_t));
199 if (mfun == NULL) {
200 usb_log_error("Failed allocating softstate.\n");
201 rc = ENOMEM;
202 goto error;
203 }
204
205 mfun->ddf_fun = fun;
206 mfun->mdev = mdev;
207 mfun->lun = lun;
208
209 /* Set up a connection handler. */
210 fun->conn_handler = usbmast_bd_connection;
211
212 usb_log_debug("Inquire...\n");
213 usbmast_inquiry_data_t inquiry;
214 rc = usbmast_inquiry(mfun, &inquiry);
215 if (rc != EOK) {
216 usb_log_warning("Failed to inquire device `%s': %s.\n",
217 mdev->ddf_dev->name, str_error(rc));
218 rc = EIO;
219 goto error;
220 }
221
222 usb_log_info("Mass storage `%s' LUN %u: " \
223 "%s by %s rev. %s is %s (%s).\n",
224 mdev->ddf_dev->name,
225 lun,
226 inquiry.product,
227 inquiry.vendor,
228 inquiry.revision,
229 usbmast_scsi_dev_type_str(inquiry.device_type),
230 inquiry.removable ? "removable" : "non-removable");
231
232 uint32_t nblocks, block_size;
233
234 rc = usbmast_read_capacity(mfun, &nblocks, &block_size);
235 if (rc != EOK) {
236 usb_log_warning("Failed to read capacity, device `%s': %s.\n",
237 mdev->ddf_dev->name, str_error(rc));
238 rc = EIO;
239 goto error;
240 }
241
242 usb_log_info("Read Capacity: nblocks=%" PRIu32 ", "
243 "block_size=%" PRIu32 "\n", nblocks, block_size);
244
245 mfun->nblocks = nblocks;
246 mfun->block_size = block_size;
247
248 rc = ddf_fun_bind(fun);
249 if (rc != EOK) {
250 usb_log_error("Failed to bind DDF function %s: %s.\n",
251 fun_name, str_error(rc));
252 goto error;
253 }
254
255 free(fun_name);
256 mdev->luns[lun] = fun;
257
258 return EOK;
259
260 /* Error cleanup */
261error:
262 if (fun != NULL)
263 ddf_fun_destroy(fun);
264 if (fun_name != NULL)
265 free(fun_name);
266 return rc;
267}
268
269/** Blockdev client connection handler. */
270static void usbmast_bd_connection(ipc_callid_t iid, ipc_call_t *icall,
271 void *arg)
272{
273 usbmast_fun_t *mfun;
274 void *comm_buf = NULL;
275 size_t comm_size;
276 ipc_callid_t callid;
277 ipc_call_t call;
278 unsigned int flags;
279 sysarg_t method;
280 uint64_t ba;
281 size_t cnt;
282 int retval;
283
284 async_answer_0(iid, EOK);
285
286 if (!async_share_out_receive(&callid, &comm_size, &flags)) {
287 async_answer_0(callid, EHANGUP);
288 return;
289 }
290
291 comm_buf = as_get_mappable_page(comm_size);
292 if (comm_buf == NULL) {
293 async_answer_0(callid, EHANGUP);
294 return;
295 }
296
297 (void) async_share_out_finalize(callid, comm_buf);
298
299 mfun = (usbmast_fun_t *) ((ddf_fun_t *)arg)->driver_data;
300
301 while (true) {
302 callid = async_get_call(&call);
303 method = IPC_GET_IMETHOD(call);
304
305 if (!method) {
306 /* The other side hung up. */
307 async_answer_0(callid, EOK);
308 return;
309 }
310
311 switch (method) {
312 case BD_GET_BLOCK_SIZE:
313 async_answer_1(callid, EOK, mfun->block_size);
314 break;
315 case BD_GET_NUM_BLOCKS:
316 async_answer_2(callid, EOK, LOWER32(mfun->nblocks),
317 UPPER32(mfun->nblocks));
318 break;
319 case BD_READ_BLOCKS:
320 ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
321 cnt = IPC_GET_ARG3(call);
322 retval = usbmast_read(mfun, ba, cnt, comm_buf);
323 async_answer_0(callid, retval);
324 break;
325 case BD_WRITE_BLOCKS:
326 ba = MERGE_LOUP32(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
327 cnt = IPC_GET_ARG3(call);
328 retval = usbmast_write(mfun, ba, cnt, comm_buf);
329 async_answer_0(callid, retval);
330 break;
331 default:
332 async_answer_0(callid, EINVAL);
333 }
334 }
335}
336
337/** USB mass storage driver ops. */
338static usb_driver_ops_t usbmast_driver_ops = {
339 .device_add = usbmast_device_add,
340 .device_gone = usbmast_device_gone,
341};
342
343/** USB mass storage driver. */
344static usb_driver_t usbmast_driver = {
345 .name = NAME,
346 .ops = &usbmast_driver_ops,
347 .endpoints = mast_endpoints
348};
349
350int main(int argc, char *argv[])
351{
352 usb_log_enable(USB_LOG_LEVEL_DEFAULT, NAME);
353
354 return usb_driver_main(&usbmast_driver);
355}
356
357/**
358 * @}
359 */
Note: See TracBrowser for help on using the repository browser.