Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / bus / usb / usbtrans.c
blobb614997f2bcdfbb914600a8fe10a69168a860c4b
1 /* usbtrans.c - USB Transfers and Transactions. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/dl.h>
21 #include <grub/pci.h>
22 #include <grub/mm.h>
23 #include <grub/misc.h>
24 #include <grub/usb.h>
25 #include <grub/usbtrans.h>
26 #include <grub/time.h>
29 static inline unsigned int
30 grub_usb_bulk_maxpacket (grub_usb_device_t dev,
31 struct grub_usb_desc_endp *endpoint)
33 /* Use the maximum packet size given in the endpoint descriptor. */
34 if (dev->initialized && endpoint && (unsigned int) endpoint->maxpacket)
35 return endpoint->maxpacket;
37 return 64;
41 static grub_usb_err_t
42 grub_usb_execute_and_wait_transfer (grub_usb_device_t dev,
43 grub_usb_transfer_t transfer,
44 int timeout, grub_size_t *actual)
46 grub_usb_err_t err;
47 grub_uint64_t endtime;
49 err = dev->controller.dev->setup_transfer (&dev->controller, transfer);
50 if (err)
51 return err;
52 /* endtime moved behind setup transfer to prevent false timeouts
53 * while debugging... */
54 endtime = grub_get_time_ms () + timeout;
55 while (1)
57 err = dev->controller.dev->check_transfer (&dev->controller, transfer,
58 actual);
59 if (!err)
60 return GRUB_USB_ERR_NONE;
61 if (err != GRUB_USB_ERR_WAIT)
62 return err;
63 if (grub_get_time_ms () > endtime)
65 err = dev->controller.dev->cancel_transfer (&dev->controller,
66 transfer);
67 if (err)
68 return err;
69 return GRUB_USB_ERR_TIMEOUT;
71 grub_cpu_idle ();
75 grub_usb_err_t
76 grub_usb_control_msg (grub_usb_device_t dev,
77 grub_uint8_t reqtype,
78 grub_uint8_t request,
79 grub_uint16_t value,
80 grub_uint16_t index,
81 grub_size_t size0, char *data_in)
83 int i;
84 grub_usb_transfer_t transfer;
85 int datablocks;
86 volatile struct grub_usb_packet_setup *setupdata;
87 grub_uint32_t setupdata_addr;
88 grub_usb_err_t err;
89 unsigned int max;
90 struct grub_pci_dma_chunk *data_chunk, *setupdata_chunk;
91 volatile char *data;
92 grub_uint32_t data_addr;
93 grub_size_t size = size0;
94 grub_size_t actual;
96 /* FIXME: avoid allocation any kind of buffer in a first place. */
97 data_chunk = grub_memalign_dma32 (128, size ? : 16);
98 if (!data_chunk)
99 return GRUB_USB_ERR_INTERNAL;
100 data = grub_dma_get_virt (data_chunk);
101 data_addr = grub_dma_get_phys (data_chunk);
102 grub_memcpy ((char *) data, data_in, size);
104 grub_dprintf ("usb",
105 "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%lu\n",
106 reqtype, request, value, index, (unsigned long)size);
108 /* Create a transfer. */
109 transfer = grub_malloc (sizeof (*transfer));
110 if (! transfer)
112 grub_dma_free (data_chunk);
113 return GRUB_USB_ERR_INTERNAL;
116 setupdata_chunk = grub_memalign_dma32 (32, sizeof (*setupdata));
117 if (! setupdata_chunk)
119 grub_free (transfer);
120 grub_dma_free (data_chunk);
121 return GRUB_USB_ERR_INTERNAL;
124 setupdata = grub_dma_get_virt (setupdata_chunk);
125 setupdata_addr = grub_dma_get_phys (setupdata_chunk);
127 /* Determine the maximum packet size. */
128 if (dev->descdev.maxsize0)
129 max = dev->descdev.maxsize0;
130 else
131 max = 64;
133 grub_dprintf ("usb", "control: transfer = %p, dev = %p\n", transfer, dev);
135 datablocks = (size + max - 1) / max;
137 /* XXX: Discriminate between different types of control
138 messages. */
139 transfer->transcnt = datablocks + 2;
140 transfer->size = size; /* XXX ? */
141 transfer->endpoint = 0;
142 transfer->devaddr = dev->addr;
143 transfer->type = GRUB_USB_TRANSACTION_TYPE_CONTROL;
144 transfer->max = max;
145 transfer->dev = dev;
147 /* Allocate an array of transfer data structures. */
148 transfer->transactions = grub_malloc (transfer->transcnt
149 * sizeof (struct grub_usb_transfer));
150 if (! transfer->transactions)
152 grub_free (transfer);
153 grub_dma_free (setupdata_chunk);
154 grub_dma_free (data_chunk);
155 return GRUB_USB_ERR_INTERNAL;
158 /* Build a Setup packet. XXX: Endianness. */
159 setupdata->reqtype = reqtype;
160 setupdata->request = request;
161 setupdata->value = value;
162 setupdata->index = index;
163 setupdata->length = size;
164 transfer->transactions[0].size = sizeof (*setupdata);
165 transfer->transactions[0].pid = GRUB_USB_TRANSFER_TYPE_SETUP;
166 transfer->transactions[0].data = setupdata_addr;
167 transfer->transactions[0].toggle = 0;
169 /* Now the data... XXX: Is this the right way to transfer control
170 transfers? */
171 for (i = 0; i < datablocks; i++)
173 grub_usb_transaction_t tr = &transfer->transactions[i + 1];
175 tr->size = (size > max) ? max : size;
176 /* Use the right most bit as the data toggle. Simple and
177 effective. */
178 tr->toggle = !(i & 1);
179 if (reqtype & 128)
180 tr->pid = GRUB_USB_TRANSFER_TYPE_IN;
181 else
182 tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
183 tr->data = data_addr + i * max;
184 tr->preceding = i * max;
185 size -= max;
188 /* End with an empty OUT transaction. */
189 transfer->transactions[datablocks + 1].size = 0;
190 transfer->transactions[datablocks + 1].data = 0;
191 if ((reqtype & 128) && datablocks)
192 transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
193 else
194 transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_IN;
196 transfer->transactions[datablocks + 1].toggle = 1;
198 err = grub_usb_execute_and_wait_transfer (dev, transfer, 1000, &actual);
200 grub_dprintf ("usb", "control: err=%d\n", err);
202 grub_free (transfer->transactions);
204 grub_free (transfer);
205 grub_dma_free (data_chunk);
206 grub_dma_free (setupdata_chunk);
208 grub_memcpy (data_in, (char *) data, size0);
210 return err;
213 static grub_usb_transfer_t
214 grub_usb_bulk_setup_readwrite (grub_usb_device_t dev,
215 struct grub_usb_desc_endp *endpoint,
216 grub_size_t size0, char *data_in,
217 grub_transfer_type_t type)
219 int i;
220 grub_usb_transfer_t transfer;
221 int datablocks;
222 unsigned int max;
223 volatile char *data;
224 grub_uint32_t data_addr;
225 struct grub_pci_dma_chunk *data_chunk;
226 grub_size_t size = size0;
227 int toggle = dev->toggle[endpoint->endp_addr];
229 grub_dprintf ("usb", "bulk: size=0x%02lx type=%d\n", (unsigned long) size,
230 type);
232 /* FIXME: avoid allocation any kind of buffer in a first place. */
233 data_chunk = grub_memalign_dma32 (128, size);
234 if (!data_chunk)
235 return NULL;
236 data = grub_dma_get_virt (data_chunk);
237 data_addr = grub_dma_get_phys (data_chunk);
238 if (type == GRUB_USB_TRANSFER_TYPE_OUT)
239 grub_memcpy ((char *) data, data_in, size);
241 /* Create a transfer. */
242 transfer = grub_malloc (sizeof (struct grub_usb_transfer));
243 if (! transfer)
245 grub_dma_free (data_chunk);
246 return NULL;
249 max = grub_usb_bulk_maxpacket (dev, endpoint);
251 datablocks = ((size + max - 1) / max);
252 transfer->transcnt = datablocks;
253 transfer->size = size - 1;
254 transfer->endpoint = endpoint->endp_addr;
255 transfer->devaddr = dev->addr;
256 transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK;
257 transfer->dir = type;
258 transfer->max = max;
259 transfer->dev = dev;
260 transfer->last_trans = -1; /* Reset index of last processed transaction (TD) */
261 transfer->data_chunk = data_chunk;
262 transfer->data = data_in;
264 /* Allocate an array of transfer data structures. */
265 transfer->transactions = grub_malloc (transfer->transcnt
266 * sizeof (struct grub_usb_transfer));
267 if (! transfer->transactions)
269 grub_free (transfer);
270 grub_dma_free (data_chunk);
271 return NULL;
274 /* Set up all transfers. */
275 for (i = 0; i < datablocks; i++)
277 grub_usb_transaction_t tr = &transfer->transactions[i];
279 tr->size = (size > max) ? max : size;
280 /* XXX: Use the right most bit as the data toggle. Simple and
281 effective. */
282 tr->toggle = toggle;
283 toggle = toggle ? 0 : 1;
284 tr->pid = type;
285 tr->data = data_addr + i * max;
286 tr->preceding = i * max;
287 size -= tr->size;
289 return transfer;
292 static void
293 grub_usb_bulk_finish_readwrite (grub_usb_transfer_t transfer)
295 grub_usb_device_t dev = transfer->dev;
296 int toggle = dev->toggle[transfer->endpoint];
298 /* We must remember proper toggle value even if some transactions
299 * were not processed - correct value should be inversion of last
300 * processed transaction (TD). */
301 if (transfer->last_trans >= 0)
302 toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1;
303 else
304 toggle = dev->toggle[transfer->endpoint]; /* Nothing done, take original */
305 grub_dprintf ("usb", "bulk: toggle=%d\n", toggle);
306 dev->toggle[transfer->endpoint] = toggle;
308 if (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN)
309 grub_memcpy (transfer->data, (void *)
310 grub_dma_get_virt (transfer->data_chunk),
311 transfer->size + 1);
313 grub_free (transfer->transactions);
314 grub_free (transfer);
315 grub_dma_free (transfer->data_chunk);
318 static grub_usb_err_t
319 grub_usb_bulk_readwrite (grub_usb_device_t dev,
320 struct grub_usb_desc_endp *endpoint,
321 grub_size_t size0, char *data_in,
322 grub_transfer_type_t type, int timeout,
323 grub_size_t *actual)
325 grub_usb_err_t err;
326 grub_usb_transfer_t transfer;
328 transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size0,
329 data_in, type);
330 if (!transfer)
331 return GRUB_USB_ERR_INTERNAL;
332 err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual);
334 grub_usb_bulk_finish_readwrite (transfer);
336 return err;
339 static grub_usb_err_t
340 grub_usb_bulk_readwrite_packetize (grub_usb_device_t dev,
341 struct grub_usb_desc_endp *endpoint,
342 grub_transfer_type_t type,
343 grub_size_t size, char *data)
345 grub_size_t actual, transferred;
346 grub_usb_err_t err = GRUB_USB_ERR_NONE;
347 grub_size_t current_size, position;
348 grub_size_t max_bulk_transfer_len = MAX_USB_TRANSFER_LEN;
349 grub_size_t max;
351 if (dev->controller.dev->max_bulk_tds)
353 max = grub_usb_bulk_maxpacket (dev, endpoint);
355 /* Calculate max. possible length of bulk transfer */
356 max_bulk_transfer_len = dev->controller.dev->max_bulk_tds * max;
359 for (position = 0, transferred = 0;
360 position < size; position += max_bulk_transfer_len)
362 current_size = size - position;
363 if (current_size >= max_bulk_transfer_len)
364 current_size = max_bulk_transfer_len;
365 err = grub_usb_bulk_readwrite (dev, endpoint, current_size,
366 &data[position], type, 1000, &actual);
367 transferred += actual;
368 if (err || (current_size != actual)) break;
371 if (!err && transferred != size)
372 err = GRUB_USB_ERR_DATA;
373 return err;
376 grub_usb_err_t
377 grub_usb_bulk_write (grub_usb_device_t dev,
378 struct grub_usb_desc_endp *endpoint,
379 grub_size_t size, char *data)
381 return grub_usb_bulk_readwrite_packetize (dev, endpoint,
382 GRUB_USB_TRANSFER_TYPE_OUT,
383 size, data);
386 grub_usb_err_t
387 grub_usb_bulk_read (grub_usb_device_t dev,
388 struct grub_usb_desc_endp *endpoint,
389 grub_size_t size, char *data)
391 return grub_usb_bulk_readwrite_packetize (dev, endpoint,
392 GRUB_USB_TRANSFER_TYPE_IN,
393 size, data);
396 grub_usb_err_t
397 grub_usb_check_transfer (grub_usb_transfer_t transfer, grub_size_t *actual)
399 grub_usb_err_t err;
400 grub_usb_device_t dev = transfer->dev;
402 err = dev->controller.dev->check_transfer (&dev->controller, transfer,
403 actual);
404 if (err == GRUB_USB_ERR_WAIT)
405 return err;
407 grub_usb_bulk_finish_readwrite (transfer);
409 return err;
412 grub_usb_transfer_t
413 grub_usb_bulk_read_background (grub_usb_device_t dev,
414 struct grub_usb_desc_endp *endpoint,
415 grub_size_t size, void *data)
417 grub_usb_err_t err;
418 grub_usb_transfer_t transfer;
420 transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size,
421 data, GRUB_USB_TRANSFER_TYPE_IN);
422 if (!transfer)
423 return NULL;
425 err = dev->controller.dev->setup_transfer (&dev->controller, transfer);
426 if (err)
427 return NULL;
429 return transfer;
432 void
433 grub_usb_cancel_transfer (grub_usb_transfer_t transfer)
435 grub_usb_device_t dev = transfer->dev;
436 dev->controller.dev->cancel_transfer (&dev->controller, transfer);
437 grub_errno = GRUB_ERR_NONE;
440 grub_usb_err_t
441 grub_usb_bulk_read_extended (grub_usb_device_t dev,
442 struct grub_usb_desc_endp *endpoint,
443 grub_size_t size, char *data,
444 int timeout, grub_size_t *actual)
446 return grub_usb_bulk_readwrite (dev, endpoint, size, data,
447 GRUB_USB_TRANSFER_TYPE_IN, timeout, actual);