~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to grub-core/bus/usb/usbtrans.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* usbtrans.c - USB Transfers and Transactions.  */
 
2
/*
 
3
 *  GRUB  --  GRand Unified Bootloader
 
4
 *  Copyright (C) 2008  Free Software Foundation, Inc.
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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/>.
 
18
 */
 
19
 
 
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>
 
27
 
 
28
static grub_usb_err_t
 
29
grub_usb_execute_and_wait_transfer (grub_usb_device_t dev, 
 
30
                                    grub_usb_transfer_t transfer,
 
31
                                    int timeout, grub_size_t *actual)
 
32
{
 
33
  grub_usb_err_t err;
 
34
  grub_uint64_t endtime;
 
35
 
 
36
  err = dev->controller.dev->setup_transfer (&dev->controller, transfer);
 
37
  if (err)
 
38
    return err;
 
39
  /* endtime moved behind setup transfer to prevent false timeouts
 
40
   * while debugging... */
 
41
  endtime = grub_get_time_ms () + timeout;
 
42
  while (1)
 
43
    {
 
44
      err = dev->controller.dev->check_transfer (&dev->controller, transfer,
 
45
                                                 actual);
 
46
      if (!err)
 
47
        return GRUB_USB_ERR_NONE;
 
48
      if (err != GRUB_USB_ERR_WAIT)
 
49
        return err;
 
50
      if (grub_get_time_ms () > endtime)
 
51
        {
 
52
          err = dev->controller.dev->cancel_transfer (&dev->controller,
 
53
                                                      transfer);
 
54
          if (err)
 
55
            return err;
 
56
          return GRUB_USB_ERR_TIMEOUT;
 
57
        }
 
58
      grub_cpu_idle ();
 
59
    }
 
60
}
 
61
 
 
62
grub_usb_err_t
 
63
grub_usb_control_msg (grub_usb_device_t dev,
 
64
                      grub_uint8_t reqtype,
 
65
                      grub_uint8_t request,
 
66
                      grub_uint16_t value,
 
67
                      grub_uint16_t index,
 
68
                      grub_size_t size0, char *data_in)
 
69
{
 
70
  int i;
 
71
  grub_usb_transfer_t transfer;
 
72
  int datablocks;
 
73
  volatile struct grub_usb_packet_setup *setupdata;
 
74
  grub_uint32_t setupdata_addr;
 
75
  grub_usb_err_t err;
 
76
  unsigned int max;
 
77
  struct grub_pci_dma_chunk *data_chunk, *setupdata_chunk;
 
78
  volatile char *data;
 
79
  grub_uint32_t data_addr;
 
80
  grub_size_t size = size0;
 
81
  grub_size_t actual;
 
82
 
 
83
  /* FIXME: avoid allocation any kind of buffer in a first place.  */
 
84
  data_chunk = grub_memalign_dma32 (128, size ? : 16);
 
85
  if (!data_chunk)
 
86
    return GRUB_USB_ERR_INTERNAL;
 
87
  data = grub_dma_get_virt (data_chunk);
 
88
  data_addr = grub_dma_get_phys (data_chunk);
 
89
  grub_memcpy ((char *) data, data_in, size);
 
90
 
 
91
  grub_dprintf ("usb",
 
92
                "control: reqtype=0x%02x req=0x%02x val=0x%02x idx=0x%02x size=%lu\n",
 
93
                reqtype, request,  value, index, (unsigned long)size);
 
94
 
 
95
  /* Create a transfer.  */
 
96
  transfer = grub_malloc (sizeof (*transfer));
 
97
  if (! transfer)
 
98
    {
 
99
      grub_dma_free (data_chunk);
 
100
      return grub_errno;
 
101
    }
 
102
 
 
103
  setupdata_chunk = grub_memalign_dma32 (32, sizeof (*setupdata));
 
104
  if (! setupdata_chunk)
 
105
    {
 
106
      grub_free (transfer);
 
107
      grub_dma_free (data_chunk);
 
108
      return grub_errno;
 
109
    }
 
110
 
 
111
  setupdata = grub_dma_get_virt (setupdata_chunk);
 
112
  setupdata_addr = grub_dma_get_phys (setupdata_chunk);
 
113
 
 
114
  /* Determine the maximum packet size.  */
 
115
  if (dev->descdev.maxsize0)
 
116
    max = dev->descdev.maxsize0;
 
117
  else
 
118
    max = 64;
 
119
 
 
120
  grub_dprintf ("usb", "control: transfer = %p, dev = %p\n", transfer, dev);
 
121
 
 
122
  datablocks = (size + max - 1) / max;
 
123
 
 
124
  /* XXX: Discriminate between different types of control
 
125
     messages.  */
 
126
  transfer->transcnt = datablocks + 2;
 
127
  transfer->size = size; /* XXX ? */
 
128
  transfer->endpoint = 0;
 
129
  transfer->devaddr = dev->addr;
 
130
  transfer->type = GRUB_USB_TRANSACTION_TYPE_CONTROL;
 
131
  transfer->max = max;
 
132
  transfer->dev = dev;
 
133
 
 
134
  /* Allocate an array of transfer data structures.  */
 
135
  transfer->transactions = grub_malloc (transfer->transcnt
 
136
                                        * sizeof (struct grub_usb_transfer));
 
137
  if (! transfer->transactions)
 
138
    {
 
139
      grub_free (transfer);
 
140
      grub_dma_free (setupdata_chunk);
 
141
      grub_dma_free (data_chunk);
 
142
      return grub_errno;
 
143
    }
 
144
 
 
145
  /* Build a Setup packet.  XXX: Endianness.  */
 
146
  setupdata->reqtype = reqtype;
 
147
  setupdata->request = request;
 
148
  setupdata->value = value;
 
149
  setupdata->index = index;
 
150
  setupdata->length = size;
 
151
  transfer->transactions[0].size = sizeof (*setupdata);
 
152
  transfer->transactions[0].pid = GRUB_USB_TRANSFER_TYPE_SETUP;
 
153
  transfer->transactions[0].data = setupdata_addr;
 
154
  transfer->transactions[0].toggle = 0;
 
155
 
 
156
  /* Now the data...  XXX: Is this the right way to transfer control
 
157
     transfers?  */
 
158
  for (i = 0; i < datablocks; i++)
 
159
    {
 
160
      grub_usb_transaction_t tr = &transfer->transactions[i + 1];
 
161
 
 
162
      tr->size = (size > max) ? max : size;
 
163
      /* Use the right most bit as the data toggle.  Simple and
 
164
         effective.  */
 
165
      tr->toggle = !(i & 1);
 
166
      if (reqtype & 128)
 
167
        tr->pid = GRUB_USB_TRANSFER_TYPE_IN;
 
168
      else
 
169
        tr->pid = GRUB_USB_TRANSFER_TYPE_OUT;
 
170
      tr->data = data_addr + i * max;
 
171
      tr->preceding = i * max;
 
172
      size -= max;
 
173
    }
 
174
 
 
175
  /* End with an empty OUT transaction.  */
 
176
  transfer->transactions[datablocks + 1].size = 0;
 
177
  transfer->transactions[datablocks + 1].data = 0;
 
178
  if ((reqtype & 128) && datablocks)
 
179
    transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_OUT;
 
180
  else
 
181
    transfer->transactions[datablocks + 1].pid = GRUB_USB_TRANSFER_TYPE_IN;
 
182
 
 
183
  transfer->transactions[datablocks + 1].toggle = 1;
 
184
 
 
185
  err = grub_usb_execute_and_wait_transfer (dev, transfer, 1000, &actual);
 
186
 
 
187
  grub_dprintf ("usb", "control: err=%d\n", err);
 
188
 
 
189
  grub_free (transfer->transactions);
 
190
  
 
191
  grub_free (transfer);
 
192
  grub_dma_free (data_chunk);
 
193
  grub_dma_free (setupdata_chunk);
 
194
 
 
195
  grub_memcpy (data_in, (char *) data, size0);
 
196
 
 
197
  return err;
 
198
}
 
199
 
 
200
static grub_usb_transfer_t
 
201
grub_usb_bulk_setup_readwrite (grub_usb_device_t dev,
 
202
                               int endpoint, grub_size_t size0, char *data_in,
 
203
                               grub_transfer_type_t type)
 
204
{
 
205
  int i;
 
206
  grub_usb_transfer_t transfer;
 
207
  int datablocks;
 
208
  unsigned int max;
 
209
  volatile char *data;
 
210
  grub_uint32_t data_addr;
 
211
  struct grub_pci_dma_chunk *data_chunk;
 
212
  grub_size_t size = size0;
 
213
  int toggle = dev->toggle[endpoint];
 
214
 
 
215
  grub_dprintf ("usb", "bulk: size=0x%02lx type=%d\n", (unsigned long) size,
 
216
                type);
 
217
 
 
218
  /* FIXME: avoid allocation any kind of buffer in a first place.  */
 
219
  data_chunk = grub_memalign_dma32 (128, size);
 
220
  if (!data_chunk)
 
221
    return NULL;
 
222
  data = grub_dma_get_virt (data_chunk);
 
223
  data_addr = grub_dma_get_phys (data_chunk);
 
224
  if (type == GRUB_USB_TRANSFER_TYPE_OUT)
 
225
    grub_memcpy ((char *) data, data_in, size);
 
226
 
 
227
  /* Use the maximum packet size given in the endpoint descriptor.  */
 
228
  if (dev->initialized)
 
229
    {
 
230
      struct grub_usb_desc_endp *endpdesc;
 
231
      endpdesc = grub_usb_get_endpdescriptor (dev, endpoint);
 
232
 
 
233
      if (endpdesc)
 
234
        max = endpdesc->maxpacket;
 
235
      else
 
236
        max = 64;
 
237
    }
 
238
  else
 
239
    max = 64;
 
240
 
 
241
  /* Create a transfer.  */
 
242
  transfer = grub_malloc (sizeof (struct grub_usb_transfer));
 
243
  if (! transfer)
 
244
    {
 
245
      grub_dma_free (data_chunk);
 
246
      return NULL;
 
247
    }
 
248
 
 
249
  datablocks = ((size + max - 1) / max);
 
250
  transfer->transcnt = datablocks;
 
251
  transfer->size = size - 1;
 
252
  transfer->endpoint = endpoint;
 
253
  transfer->devaddr = dev->addr;
 
254
  transfer->type = GRUB_USB_TRANSACTION_TYPE_BULK;
 
255
  transfer->dir = type;
 
256
  transfer->max = max;
 
257
  transfer->dev = dev;
 
258
  transfer->last_trans = -1; /* Reset index of last processed transaction (TD) */
 
259
  transfer->data_chunk = data_chunk;
 
260
  transfer->data = data_in;
 
261
 
 
262
  /* Allocate an array of transfer data structures.  */
 
263
  transfer->transactions = grub_malloc (transfer->transcnt
 
264
                                        * sizeof (struct grub_usb_transfer));
 
265
  if (! transfer->transactions)
 
266
    {
 
267
      grub_free (transfer);
 
268
      grub_dma_free (data_chunk);
 
269
      return NULL;
 
270
    }
 
271
 
 
272
  /* Set up all transfers.  */
 
273
  for (i = 0; i < datablocks; i++)
 
274
    {
 
275
      grub_usb_transaction_t tr = &transfer->transactions[i];
 
276
 
 
277
      tr->size = (size > max) ? max : size;
 
278
      /* XXX: Use the right most bit as the data toggle.  Simple and
 
279
         effective.  */
 
280
      tr->toggle = toggle;
 
281
      toggle = toggle ? 0 : 1;
 
282
      tr->pid = type;
 
283
      tr->data = data_addr + i * max;
 
284
      tr->preceding = i * max;
 
285
      size -= tr->size;
 
286
    }
 
287
  return transfer;
 
288
}
 
289
 
 
290
static void
 
291
grub_usb_bulk_finish_readwrite (grub_usb_transfer_t transfer)
 
292
{
 
293
  grub_usb_device_t dev = transfer->dev;
 
294
  int toggle = dev->toggle[transfer->endpoint];
 
295
 
 
296
  /* We must remember proper toggle value even if some transactions
 
297
   * were not processed - correct value should be inversion of last
 
298
   * processed transaction (TD). */
 
299
  if (transfer->last_trans >= 0)
 
300
    toggle = transfer->transactions[transfer->last_trans].toggle ? 0 : 1;
 
301
  else
 
302
    toggle = dev->toggle[transfer->endpoint]; /* Nothing done, take original */
 
303
  grub_dprintf ("usb", "bulk: toggle=%d\n", toggle);
 
304
  dev->toggle[transfer->endpoint] = toggle;
 
305
 
 
306
  if (transfer->dir == GRUB_USB_TRANSFER_TYPE_IN)
 
307
    grub_memcpy (transfer->data, (void *)
 
308
                 grub_dma_get_virt (transfer->data_chunk),
 
309
                 transfer->size + 1);
 
310
 
 
311
  grub_free (transfer->transactions);
 
312
  grub_free (transfer);
 
313
  grub_dma_free (transfer->data_chunk);
 
314
}
 
315
 
 
316
static grub_usb_err_t
 
317
grub_usb_bulk_readwrite (grub_usb_device_t dev,
 
318
                         int endpoint, grub_size_t size0, char *data_in,
 
319
                         grub_transfer_type_t type, int timeout,
 
320
                         grub_size_t *actual)
 
321
{
 
322
  grub_usb_err_t err;
 
323
  grub_usb_transfer_t transfer;
 
324
 
 
325
  transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size0,
 
326
                                            data_in, type);
 
327
  if (!transfer)
 
328
    return GRUB_USB_ERR_INTERNAL;
 
329
  err = grub_usb_execute_and_wait_transfer (dev, transfer, timeout, actual);
 
330
 
 
331
  grub_usb_bulk_finish_readwrite (transfer);
 
332
 
 
333
  return err;
 
334
}
 
335
 
 
336
grub_usb_err_t
 
337
grub_usb_bulk_write (grub_usb_device_t dev,
 
338
                     int endpoint, grub_size_t size, char *data)
 
339
{
 
340
  grub_size_t actual;
 
341
  grub_usb_err_t err;
 
342
 
 
343
  err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
 
344
                                 GRUB_USB_TRANSFER_TYPE_OUT, 1000, &actual);
 
345
  if (!err && actual != size)
 
346
    err = GRUB_USB_ERR_DATA;
 
347
  return err;
 
348
}
 
349
 
 
350
grub_usb_err_t
 
351
grub_usb_bulk_read (grub_usb_device_t dev,
 
352
                    int endpoint, grub_size_t size, char *data)
 
353
{
 
354
  grub_size_t actual;
 
355
  grub_usb_err_t err;
 
356
  err = grub_usb_bulk_readwrite (dev, endpoint, size, data,
 
357
                                 GRUB_USB_TRANSFER_TYPE_IN, 1000, &actual);
 
358
  if (!err && actual != size)
 
359
    err = GRUB_USB_ERR_DATA;
 
360
  return err;
 
361
}
 
362
 
 
363
grub_usb_err_t
 
364
grub_usb_check_transfer (grub_usb_transfer_t transfer, grub_size_t *actual)
 
365
{
 
366
  grub_usb_err_t err;
 
367
  grub_usb_device_t dev = transfer->dev;
 
368
 
 
369
  err = dev->controller.dev->check_transfer (&dev->controller, transfer,
 
370
                                             actual);
 
371
  if (err == GRUB_USB_ERR_WAIT)
 
372
    return err;
 
373
 
 
374
  grub_usb_bulk_finish_readwrite (transfer);
 
375
 
 
376
  return err;
 
377
}
 
378
 
 
379
grub_usb_transfer_t
 
380
grub_usb_bulk_read_background (grub_usb_device_t dev,
 
381
                               int endpoint, grub_size_t size, void *data)
 
382
{
 
383
  grub_usb_err_t err;
 
384
  grub_usb_transfer_t transfer;
 
385
 
 
386
  transfer = grub_usb_bulk_setup_readwrite (dev, endpoint, size,
 
387
                                            data, GRUB_USB_TRANSFER_TYPE_IN);
 
388
  if (!transfer)
 
389
    return NULL;
 
390
 
 
391
  err = dev->controller.dev->setup_transfer (&dev->controller, transfer);
 
392
  if (err)
 
393
    return NULL;
 
394
 
 
395
  return transfer;
 
396
}
 
397
 
 
398
void
 
399
grub_usb_cancel_transfer (grub_usb_transfer_t transfer)
 
400
{
 
401
  grub_usb_device_t dev = transfer->dev;
 
402
  dev->controller.dev->cancel_transfer (&dev->controller, transfer);
 
403
  grub_errno = GRUB_ERR_NONE;
 
404
}
 
405
 
 
406
grub_usb_err_t
 
407
grub_usb_bulk_read_extended (grub_usb_device_t dev,
 
408
                             int endpoint, grub_size_t size, char *data,
 
409
                             int timeout, grub_size_t *actual)
 
410
{
 
411
  return grub_usb_bulk_readwrite (dev, endpoint, size, data,
 
412
                                  GRUB_USB_TRANSFER_TYPE_IN, timeout, actual);
 
413
}