2009-05-21 Felix Zielcke <fzielcke@z-51.de>
[grub2/phcoder/solaris.git] / bus / usb / usbtrans.c
blobfd8295741fda5347f0e6db2436a875b6280a2c51
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/mm.h>
22 #include <grub/misc.h>
23 #include <grub/usb.h>
24 #include <grub/usbtrans.h>
26 grub_usb_err_t
27 grub_usb_control_msg (grub_usb_device_t dev,
28 grub_uint8_t reqtype,
29 grub_uint8_t request,
30 grub_uint16_t value,
31 grub_uint16_t index,
32 grub_size_t size, char *data)
34 int i;
35 grub_usb_transfer_t transfer;
36 int datablocks;
37 struct grub_usb_packet_setup setupdata;
38 grub_usb_err_t err;
39 unsigned int max;
41 grub_dprintf ("usb",
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));
47 if (! transfer)
48 return grub_errno;
50 /* Determine the maximum packet size. */
51 if (dev->initialized)
52 max = dev->descdev.maxsize0;
53 else
54 max = 64;
56 datablocks = (size + max - 1) / max;
58 /* XXX: Discriminate between different types of control
59 messages. */
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;
65 transfer->max = max;
66 transfer->dev = dev;
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)
73 grub_free (transfer);
74 return grub_errno;
77 /* Build a Setup packet. XXX: Endianess. */
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
89 transfers? */
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
96 effective. */
97 tr->toggle = !(i & 1);
98 if (reqtype & 128)
99 tr->pid = GRUB_USB_TRANSFER_TYPE_IN;
100 else
101 tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
102 tr->data = &data[i * max];
103 size -= max;
106 /* End with an empty OUT transaction. */
107 transfer->transactions[datablocks + 1].size = 0;
108 transfer->transactions[datablocks + 1].data = NULL;
109 if (reqtype & 128)
110 transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
111 else
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);
121 return err;
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)
129 int i;
130 grub_usb_transfer_t transfer;
131 int datablocks;
132 unsigned int max;
133 grub_usb_err_t err;
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);
142 if (endpdesc)
143 max = endpdesc->maxpacket;
144 else
145 max = 64;
147 else
148 max = 64;
150 /* Create a transfer. */
151 transfer = grub_malloc (sizeof (struct grub_usb_transfer));
152 if (! transfer)
153 return grub_errno;
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;
161 transfer->max = max;
162 transfer->dev = dev;
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);
170 return grub_errno;
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
180 effective. */
181 tr->toggle = toggle;
182 toggle = toggle ? 0 : 1;
183 tr->pid = type;
184 tr->data = &data[i * max];
185 size -= tr->size;
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);
195 return err;
198 grub_usb_err_t
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);
206 grub_usb_err_t
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);