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/>.
22 #include <grub/misc.h>
24 #include <grub/usbtrans.h>
27 grub_usb_control_msg (grub_usb_device_t dev
,
32 grub_size_t size
, char *data
)
35 grub_usb_transfer_t transfer
;
37 struct grub_usb_packet_setup setupdata
;
42 "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%d\n",
43 reqtype
, request
, value
, index
, size
);
45 /* Create a transfer. */
46 transfer
= grub_malloc (sizeof (struct grub_usb_transfer
));
50 /* Determine the maximum packet size. */
52 max
= dev
->descdev
.maxsize0
;
56 datablocks
= (size
+ max
- 1) / max
;
58 /* XXX: Discriminate between different types of control
60 transfer
->transcnt
= datablocks
+ 2;
61 transfer
->size
= size
; /* XXX ? */
62 transfer
->endpoint
= 0;
63 transfer
->devaddr
= dev
->addr
;
64 transfer
->type
= GRUB_USB_TRANSACTION_TYPE_CONTROL
;
68 /* Allocate an array of transfer data structures. */
69 transfer
->transactions
= grub_malloc (transfer
->transcnt
70 * sizeof (struct grub_usb_transfer
));
71 if (! transfer
->transactions
)
77 /* Build a Setup packet. XXX: Endianness. */
78 setupdata
.reqtype
= reqtype
;
79 setupdata
.request
= request
;
80 setupdata
.value
= value
;
81 setupdata
.index
= index
;
82 setupdata
.length
= size
;
83 transfer
->transactions
[0].size
= sizeof (setupdata
);
84 transfer
->transactions
[0].pid
= GRUB_USB_TRANSFER_TYPE_SETUP
;
85 transfer
->transactions
[0].data
= (char *) &setupdata
;
86 transfer
->transactions
[0].toggle
= 0;
88 /* Now the data... XXX: Is this the right way to transfer control
90 for (i
= 0; i
< datablocks
; i
++)
92 grub_usb_transaction_t tr
= &transfer
->transactions
[i
+ 1];
94 tr
->size
= (size
> max
) ? max
: size
;
95 /* Use the right most bit as the data toggle. Simple and
97 tr
->toggle
= !(i
& 1);
99 tr
->pid
= GRUB_USB_TRANSFER_TYPE_IN
;
101 tr
->pid
= GRUB_USB_TRANSFER_TYPE_OUT
;
102 tr
->data
= &data
[i
* max
];
106 /* End with an empty OUT transaction. */
107 transfer
->transactions
[datablocks
+ 1].size
= 0;
108 transfer
->transactions
[datablocks
+ 1].data
= NULL
;
110 transfer
->transactions
[datablocks
+ 1].pid
= GRUB_USB_TRANSFER_TYPE_OUT
;
112 transfer
->transactions
[datablocks
+ 1].pid
= GRUB_USB_TRANSFER_TYPE_IN
;
114 transfer
->transactions
[datablocks
+ 1].toggle
= 1;
116 err
= dev
->controller
.dev
->transfer (&dev
->controller
, transfer
);
118 grub_free (transfer
->transactions
);
119 grub_free (transfer
);
124 static grub_usb_err_t
125 grub_usb_bulk_readwrite (grub_usb_device_t dev
,
126 int endpoint
, grub_size_t size
, char *data
,
127 grub_transfer_type_t type
)
130 grub_usb_transfer_t transfer
;
134 int toggle
= dev
->toggle
[endpoint
];
136 /* Use the maximum packet size given in the endpoint descriptor. */
137 if (dev
->initialized
)
139 struct grub_usb_desc_endp
*endpdesc
;
140 endpdesc
= grub_usb_get_endpdescriptor (dev
, 0);
143 max
= endpdesc
->maxpacket
;
150 /* Create a transfer. */
151 transfer
= grub_malloc (sizeof (struct grub_usb_transfer
));
155 datablocks
= ((size
+ max
- 1) / max
);
156 transfer
->transcnt
= datablocks
;
157 transfer
->size
= size
- 1;
158 transfer
->endpoint
= endpoint
;
159 transfer
->devaddr
= dev
->addr
;
160 transfer
->type
= GRUB_USB_TRANSACTION_TYPE_BULK
;
164 /* Allocate an array of transfer data structures. */
165 transfer
->transactions
= grub_malloc (transfer
->transcnt
166 * sizeof (struct grub_usb_transfer
));
167 if (! transfer
->transactions
)
169 grub_free (transfer
);
173 /* Set up all transfers. */
174 for (i
= 0; i
< datablocks
; i
++)
176 grub_usb_transaction_t tr
= &transfer
->transactions
[i
];
178 tr
->size
= (size
> max
) ? max
: size
;
179 /* XXX: Use the right most bit as the data toggle. Simple and
182 toggle
= toggle
? 0 : 1;
184 tr
->data
= &data
[i
* max
];
188 err
= dev
->controller
.dev
->transfer (&dev
->controller
, transfer
);
189 grub_dprintf ("usb", "toggle=%d\n", toggle
);
190 dev
->toggle
[endpoint
] = toggle
;
192 grub_free (transfer
->transactions
);
193 grub_free (transfer
);
199 grub_usb_bulk_write (grub_usb_device_t dev
,
200 int endpoint
, grub_size_t size
, char *data
)
202 return grub_usb_bulk_readwrite (dev
, endpoint
, size
, data
,
203 GRUB_USB_TRANSFER_TYPE_OUT
);
207 grub_usb_bulk_read (grub_usb_device_t dev
,
208 int endpoint
, grub_size_t size
, char *data
)
210 return grub_usb_bulk_readwrite (dev
, endpoint
, size
, data
,
211 GRUB_USB_TRANSFER_TYPE_IN
);