1 /* usbtrans.c - USB Transfers and Transactions. */
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/>.
23 #include <grub/misc.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
;
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
)
47 grub_uint64_t endtime
;
49 err
= dev
->controller
.dev
->setup_transfer (&dev
->controller
, transfer
);
52 /* endtime moved behind setup transfer to prevent false timeouts
53 * while debugging... */
54 endtime
= grub_get_time_ms () + timeout
;
57 err
= dev
->controller
.dev
->check_transfer (&dev
->controller
, transfer
,
60 return GRUB_USB_ERR_NONE
;
61 if (err
!= GRUB_USB_ERR_WAIT
)
63 if (grub_get_time_ms () > endtime
)
65 err
= dev
->controller
.dev
->cancel_transfer (&dev
->controller
,
69 return GRUB_USB_ERR_TIMEOUT
;
76 grub_usb_control_msg (grub_usb_device_t dev
,
81 grub_size_t size0
, char *data_in
)
84 grub_usb_transfer_t transfer
;
86 volatile struct grub_usb_packet_setup
*setupdata
;
87 grub_uint32_t setupdata_addr
;
90 struct grub_pci_dma_chunk
*data_chunk
, *setupdata_chunk
;
92 grub_uint32_t data_addr
;
93 grub_size_t size
= size0
;
96 /* FIXME: avoid allocation any kind of buffer in a first place. */
97 data_chunk
= grub_memalign_dma32 (128, size
? : 16);
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
);
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
));
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
;
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
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
;
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
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
178 tr
->toggle
= !(i
& 1);
180 tr
->pid
= GRUB_USB_TRANSFER_TYPE_IN
;
182 tr
->pid
= GRUB_USB_TRANSFER_TYPE_OUT
;
183 tr
->data
= data_addr
+ i
* max
;
184 tr
->preceding
= i
* 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
;
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
);
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
)
220 grub_usb_transfer_t transfer
;
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
,
232 /* FIXME: avoid allocation any kind of buffer in a first place. */
233 data_chunk
= grub_memalign_dma32 (128, size
);
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
));
245 grub_dma_free (data_chunk
);
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
;
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
);
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
283 toggle
= toggle
? 0 : 1;
285 tr
->data
= data_addr
+ i
* max
;
286 tr
->preceding
= i
* max
;
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;
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
),
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
,
326 grub_usb_transfer_t transfer
;
328 transfer
= grub_usb_bulk_setup_readwrite (dev
, endpoint
, size0
,
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
);
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
;
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
;
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
,
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
,
397 grub_usb_check_transfer (grub_usb_transfer_t transfer
, grub_size_t
*actual
)
400 grub_usb_device_t dev
= transfer
->dev
;
402 err
= dev
->controller
.dev
->check_transfer (&dev
->controller
, transfer
,
404 if (err
== GRUB_USB_ERR_WAIT
)
407 grub_usb_bulk_finish_readwrite (transfer
);
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
)
418 grub_usb_transfer_t transfer
;
420 transfer
= grub_usb_bulk_setup_readwrite (dev
, endpoint
, size
,
421 data
, GRUB_USB_TRANSFER_TYPE_IN
);
425 err
= dev
->controller
.dev
->setup_transfer (&dev
->controller
, transfer
);
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
;
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
);