~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* uhci.c - UHCI Support.  */
 
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/mm.h>
 
22
#include <grub/misc.h>
 
23
#include <grub/usb.h>
 
24
#include <grub/usbtrans.h>
 
25
#include <grub/pci.h>
 
26
#include <grub/i386/io.h>
 
27
#include <grub/time.h>
 
28
 
 
29
#define GRUB_UHCI_IOMASK        (0x7FF << 5)
 
30
 
 
31
#define N_QH  256
 
32
#define N_TD  640
 
33
 
 
34
typedef enum
 
35
  {
 
36
    GRUB_UHCI_REG_USBCMD = 0x00,
 
37
    GRUB_UHCI_REG_FLBASEADD = 0x08,
 
38
    GRUB_UHCI_REG_PORTSC1 = 0x10,
 
39
    GRUB_UHCI_REG_PORTSC2 = 0x12
 
40
  } grub_uhci_reg_t;
 
41
 
 
42
#define GRUB_UHCI_LINK_TERMINATE        1
 
43
#define GRUB_UHCI_LINK_QUEUE_HEAD       2
 
44
 
 
45
enum
 
46
  {
 
47
    GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED = 0x0002,
 
48
    GRUB_UHCI_REG_PORTSC_PORT_ENABLED    = 0x0004,
 
49
    GRUB_UHCI_REG_PORTSC_RESUME          = 0x0040,
 
50
    GRUB_UHCI_REG_PORTSC_RESET           = 0x0200,
 
51
    GRUB_UHCI_REG_PORTSC_SUSPEND         = 0x1000,
 
52
    GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED
 
53
    | GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET
 
54
    | GRUB_UHCI_REG_PORTSC_SUSPEND,
 
55
    /* These bits should not be written as 1 unless we really need it */
 
56
    GRUB_UHCI_PORTSC_RWC = ((1 << 1) | (1 << 3) | (1 << 11) | (3 << 13))
 
57
  };
 
58
 
 
59
/* UHCI Queue Head.  */
 
60
struct grub_uhci_qh
 
61
{
 
62
  /* Queue head link pointer which points to the next queue head.  */
 
63
  grub_uint32_t linkptr;
 
64
 
 
65
  /* Queue element link pointer which points to the first data object
 
66
     within the queue.  */
 
67
  grub_uint32_t elinkptr;
 
68
 
 
69
  /* Queue heads are aligned on 16 bytes, pad so a queue head is 16
 
70
     bytes so we can store many in a 4K page.  */
 
71
  grub_uint8_t pad[8];
 
72
} __attribute__ ((packed));
 
73
 
 
74
/* UHCI Transfer Descriptor.  */
 
75
struct grub_uhci_td
 
76
{
 
77
  /* Pointer to the next TD in the list.  */
 
78
  grub_uint32_t linkptr;
 
79
 
 
80
  /* Control and status bits.  */
 
81
  grub_uint32_t ctrl_status;
 
82
 
 
83
  /* All information required to transfer the Token packet.  */
 
84
  grub_uint32_t token;
 
85
 
 
86
  /* A pointer to the data buffer, UHCI requires this pointer to be 32
 
87
     bits.  */
 
88
  grub_uint32_t buffer;
 
89
 
 
90
  /* Another linkptr that is not overwritten by the Host Controller.
 
91
     This is GRUB specific.  */
 
92
  grub_uint32_t linkptr2;
 
93
 
 
94
  /* 3 additional 32 bits words reserved for the Host Controller Driver.  */
 
95
  grub_uint32_t data[3];
 
96
} __attribute__ ((packed));
 
97
 
 
98
typedef volatile struct grub_uhci_td *grub_uhci_td_t;
 
99
typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
 
100
 
 
101
struct grub_uhci
 
102
{
 
103
  int iobase;
 
104
  grub_uint32_t *framelist;
 
105
 
 
106
  /* N_QH Queue Heads.  */
 
107
  grub_uhci_qh_t qh;
 
108
 
 
109
  /* N_TD Transfer Descriptors.  */
 
110
  grub_uhci_td_t td;
 
111
 
 
112
  /* Free Transfer Descriptors.  */
 
113
  grub_uhci_td_t tdfree;
 
114
 
 
115
  int qh_busy[N_QH];
 
116
 
 
117
  struct grub_uhci *next;
 
118
};
 
119
 
 
120
static struct grub_uhci *uhci;
 
121
 
 
122
static grub_uint16_t
 
123
grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg)
 
124
{
 
125
  return grub_inw (u->iobase + reg);
 
126
}
 
127
 
 
128
#if 0
 
129
static grub_uint32_t
 
130
grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg)
 
131
{
 
132
  return grub_inl (u->iobase + reg);
 
133
}
 
134
#endif
 
135
 
 
136
static void
 
137
grub_uhci_writereg16 (struct grub_uhci *u,
 
138
                      grub_uhci_reg_t reg, grub_uint16_t val)
 
139
{
 
140
  grub_outw (val, u->iobase + reg);
 
141
}
 
142
 
 
143
static void
 
144
grub_uhci_writereg32 (struct grub_uhci *u,
 
145
                    grub_uhci_reg_t reg, grub_uint32_t val)
 
146
{
 
147
  grub_outl (val, u->iobase + reg);
 
148
}
 
149
 
 
150
static grub_err_t
 
151
grub_uhci_portstatus (grub_usb_controller_t dev,
 
152
                      unsigned int port, unsigned int enable);
 
153
 
 
154
 
 
155
/* Iterate over all PCI devices.  Determine if a device is an UHCI
 
156
   controller.  If this is the case, initialize it.  */
 
157
static int NESTED_FUNC_ATTR
 
158
grub_uhci_pci_iter (grub_pci_device_t dev,
 
159
                    grub_pci_id_t pciid __attribute__((unused)))
 
160
{
 
161
  grub_uint32_t class_code;
 
162
  grub_uint32_t class;
 
163
  grub_uint32_t subclass;
 
164
  grub_uint32_t interf;
 
165
  grub_uint32_t base;
 
166
  grub_uint32_t fp;
 
167
  grub_pci_address_t addr;
 
168
  struct grub_uhci *u;
 
169
  int i;
 
170
 
 
171
  addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
 
172
  class_code = grub_pci_read (addr) >> 8;
 
173
 
 
174
  interf = class_code & 0xFF;
 
175
  subclass = (class_code >> 8) & 0xFF;
 
176
  class = class_code >> 16;
 
177
 
 
178
  /* If this is not an UHCI controller, just return.  */
 
179
  if (class != 0x0c || subclass != 0x03 || interf != 0x00)
 
180
    return 0;
 
181
 
 
182
  /* Determine IO base address.  */
 
183
  addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4);
 
184
  base = grub_pci_read (addr);
 
185
  /* Stop if there is no IO space base address defined.  */
 
186
  if (! (base & 1))
 
187
    return 0;
 
188
 
 
189
  /* Allocate memory for the controller and register it.  */
 
190
  u = grub_zalloc (sizeof (*u));
 
191
  if (! u)
 
192
    return 1;
 
193
 
 
194
  u->iobase = base & GRUB_UHCI_IOMASK;
 
195
 
 
196
  /* Reserve a page for the frame list.  */
 
197
  u->framelist = grub_memalign (4096, 4096);
 
198
  if (! u->framelist)
 
199
    goto fail;
 
200
 
 
201
  grub_dprintf ("uhci", "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
 
202
                class, subclass, interf, u->iobase, u->framelist);
 
203
 
 
204
  /* The framelist pointer of UHCI is only 32 bits, make sure this
 
205
     code works on on 64 bits architectures.  */
 
206
#if GRUB_CPU_SIZEOF_VOID_P == 8
 
207
  if ((grub_uint64_t) u->framelist >> 32)
 
208
    {
 
209
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
 
210
                  "allocated frame list memory not <4GB");
 
211
      goto fail;
 
212
    }
 
213
#endif
 
214
 
 
215
  /* The QH pointer of UHCI is only 32 bits, make sure this
 
216
     code works on on 64 bits architectures.  */
 
217
  u->qh = (grub_uhci_qh_t) grub_memalign (4096, sizeof(struct grub_uhci_qh)*N_QH);
 
218
  if (! u->qh)
 
219
    goto fail;
 
220
 
 
221
#if GRUB_CPU_SIZEOF_VOID_P == 8
 
222
  if ((grub_uint64_t) u->qh >> 32)
 
223
    {
 
224
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB");
 
225
      goto fail;
 
226
    }
 
227
#endif
 
228
 
 
229
  /* The TD pointer of UHCI is only 32 bits, make sure this
 
230
     code works on on 64 bits architectures.  */
 
231
  u->td = (grub_uhci_td_t) grub_memalign (4096, sizeof(struct grub_uhci_td)*N_TD);
 
232
  if (! u->td)
 
233
    goto fail;
 
234
 
 
235
#if GRUB_CPU_SIZEOF_VOID_P == 8
 
236
  if ((grub_uint64_t) u->td >> 32)
 
237
    {
 
238
      grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB");
 
239
      goto fail;
 
240
    }
 
241
#endif
 
242
 
 
243
  grub_dprintf ("uhci", "QH=%p, TD=%p\n",
 
244
                u->qh, u->td);
 
245
 
 
246
  /* Link all Transfer Descriptors in a list of available Transfer
 
247
     Descriptors.  */
 
248
  for (i = 0; i < N_TD; i++)
 
249
    u->td[i].linkptr = (grub_uint32_t) (grub_addr_t) &u->td[i + 1];
 
250
  u->td[N_TD - 2].linkptr = 0;
 
251
  u->tdfree = u->td;
 
252
 
 
253
  /* Make sure UHCI is disabled!  */
 
254
  grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
 
255
 
 
256
  /* Setup the frame list pointers.  Since no isochronous transfers
 
257
     are and will be supported, they all point to the (same!) queue
 
258
     head.  */
 
259
  fp = (grub_uint32_t) (grub_addr_t) u->qh & (~15);
 
260
  /* Mark this as a queue head.  */
 
261
  fp |= 2;
 
262
  for (i = 0; i < 1024; i++)
 
263
    u->framelist[i] = fp;
 
264
  /* Program the framelist address into the UHCI controller.  */
 
265
  grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD,
 
266
                        (grub_uint32_t) (grub_addr_t) u->framelist);
 
267
 
 
268
  /* Make the Queue Heads point to each other.  */
 
269
  for (i = 0; i < N_QH; i++)
 
270
    {
 
271
      /* Point to the next QH.  */
 
272
      u->qh[i].linkptr = (grub_uint32_t) (grub_addr_t) (&u->qh[i + 1]) & (~15);
 
273
 
 
274
      /* This is a QH.  */
 
275
      u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
 
276
 
 
277
      /* For the moment, do not point to a Transfer Descriptor.  These
 
278
         are set at transfer time, so just terminate it.  */
 
279
      u->qh[i].elinkptr = 1;
 
280
    }
 
281
 
 
282
  /* The last Queue Head should terminate.  */
 
283
  u->qh[N_QH - 1].linkptr = 1;
 
284
 
 
285
  /* Enable UHCI again.  */
 
286
  grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7));
 
287
 
 
288
  /* UHCI is initialized and ready for transfers.  */
 
289
  grub_dprintf ("uhci", "UHCI initialized\n");
 
290
 
 
291
 
 
292
#if 0
 
293
  {
 
294
    int i;
 
295
    for (i = 0; i < 10; i++)
 
296
      {
 
297
        grub_uint16_t frnum;
 
298
 
 
299
        frnum = grub_uhci_readreg16 (u, 6);
 
300
        grub_dprintf ("uhci", "Framenum=%d\n", frnum);
 
301
        grub_millisleep (100);
 
302
      }
 
303
  }
 
304
#endif
 
305
 
 
306
  /* Link to uhci now that initialisation is successful.  */
 
307
  u->next = uhci;
 
308
  uhci = u;
 
309
 
 
310
  return 0;
 
311
 
 
312
 fail:
 
313
  if (u)
 
314
    {
 
315
      grub_free ((void *) u->qh);
 
316
      grub_free (u->framelist);
 
317
    }
 
318
  grub_free (u);
 
319
 
 
320
  return 1;
 
321
}
 
322
 
 
323
static void
 
324
grub_uhci_inithw (void)
 
325
{
 
326
  grub_pci_iterate (grub_uhci_pci_iter);
 
327
}
 
328
 
 
329
static grub_uhci_td_t
 
330
grub_alloc_td (struct grub_uhci *u)
 
331
{
 
332
  grub_uhci_td_t ret;
 
333
 
 
334
  /* Check if there is a Transfer Descriptor available.  */
 
335
  if (! u->tdfree)
 
336
    return NULL;
 
337
 
 
338
  ret = u->tdfree;
 
339
  u->tdfree = (grub_uhci_td_t) (grub_addr_t) u->tdfree->linkptr;
 
340
 
 
341
  return ret;
 
342
}
 
343
 
 
344
static void
 
345
grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
 
346
{
 
347
  td->linkptr = (grub_uint32_t) (grub_addr_t) u->tdfree;
 
348
  u->tdfree = td;
 
349
}
 
350
 
 
351
static void
 
352
grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
 
353
                 grub_usb_transfer_t transfer, grub_size_t *actual)
 
354
{
 
355
  int i; /* Index of TD in transfer */
 
356
 
 
357
  u->qh_busy[qh - u->qh] = 0;
 
358
 
 
359
  *actual = 0;
 
360
  
 
361
  /* Free the TDs in this queue and set last_trans.  */
 
362
  for (i=0; td; i++)
 
363
    {
 
364
      grub_uhci_td_t tdprev;
 
365
 
 
366
      /* Check state of TD and possibly set last_trans */
 
367
      if (transfer && (td->linkptr & 1))
 
368
        transfer->last_trans = i;
 
369
 
 
370
      *actual += (td->ctrl_status + 1) & 0x7ff;
 
371
      
 
372
      /* Unlink the queue.  */
 
373
      tdprev = td;
 
374
      td = (grub_uhci_td_t) (grub_addr_t) td->linkptr2;
 
375
 
 
376
      /* Free the TD.  */
 
377
      grub_free_td (u, tdprev);
 
378
    }
 
379
}
 
380
 
 
381
static grub_uhci_qh_t
 
382
grub_alloc_qh (struct grub_uhci *u,
 
383
               grub_transaction_type_t tr __attribute__((unused)))
 
384
{
 
385
  int i;
 
386
  grub_uhci_qh_t qh;
 
387
 
 
388
  /* Look for a Queue Head for this transfer.  Skip the first QH if
 
389
     this is a Interrupt Transfer.  */
 
390
#if 0
 
391
  if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT)
 
392
    i = 0;
 
393
  else
 
394
#endif
 
395
    i = 1;
 
396
 
 
397
  for (; i < N_QH; i++)
 
398
    {
 
399
      if (!u->qh_busy[i])
 
400
        break;
 
401
    }
 
402
  qh = &u->qh[i];
 
403
  if (i == N_QH)
 
404
    {
 
405
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
 
406
                  "no free queue heads available");
 
407
      return NULL;
 
408
    }
 
409
 
 
410
  u->qh_busy[qh - u->qh] = 1;
 
411
 
 
412
  return qh;
 
413
}
 
414
 
 
415
static grub_uhci_td_t
 
416
grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
 
417
                       grub_transfer_type_t type, unsigned int addr,
 
418
                       unsigned int toggle, grub_size_t size,
 
419
                       grub_uint32_t data, grub_usb_speed_t speed)
 
420
{
 
421
  grub_uhci_td_t td;
 
422
  static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
 
423
 
 
424
  /* XXX: Check if data is <4GB.  If it isn't, just copy stuff around.
 
425
     This is only relevant for 64 bits architectures.  */
 
426
 
 
427
  /* Grab a free Transfer Descriptor and initialize it.  */
 
428
  td = grub_alloc_td (u);
 
429
  if (! td)
 
430
    {
 
431
      grub_error (GRUB_ERR_OUT_OF_MEMORY,
 
432
                  "no transfer descriptors available for UHCI transfer");
 
433
      return 0;
 
434
    }
 
435
 
 
436
  grub_dprintf ("uhci",
 
437
                "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%lu data=0x%x td=%p\n",
 
438
                endp, type, addr, toggle, (unsigned long) size, data, td);
 
439
 
 
440
  /* Don't point to any TD, just terminate.  */
 
441
  td->linkptr = 1;
 
442
 
 
443
  /* Active!  Only retry a transfer 3 times.  */
 
444
  td->ctrl_status = (1 << 23) | (3 << 27) |
 
445
                    ((speed == GRUB_USB_SPEED_LOW) ? (1 << 26) : 0);
 
446
 
 
447
  /* If zero bytes are transmitted, size is 0x7FF.  Otherwise size is
 
448
     size-1.  */
 
449
  if (size == 0)
 
450
    size = 0x7FF;
 
451
  else
 
452
    size = size - 1;
 
453
 
 
454
  /* Setup whatever is required for the token packet.  */
 
455
  td->token = ((size << 21) | (toggle << 19) | (endp << 15)
 
456
               | (addr << 8) | tf[type]);
 
457
 
 
458
  td->buffer = data;
 
459
 
 
460
  return td;
 
461
}
 
462
 
 
463
struct grub_uhci_transfer_controller_data
 
464
{
 
465
  grub_uhci_qh_t qh;
 
466
  grub_uhci_td_t td_first;
 
467
};
 
468
 
 
469
static grub_usb_err_t
 
470
grub_uhci_setup_transfer (grub_usb_controller_t dev,
 
471
                          grub_usb_transfer_t transfer)
 
472
{
 
473
  struct grub_uhci *u = (struct grub_uhci *) dev->data;
 
474
  grub_uhci_td_t td;
 
475
  grub_uhci_td_t td_prev = NULL;
 
476
  int i;
 
477
  struct grub_uhci_transfer_controller_data *cdata;
 
478
 
 
479
  cdata = grub_malloc (sizeof (*cdata));
 
480
  if (!cdata)
 
481
    return GRUB_USB_ERR_INTERNAL;
 
482
 
 
483
  cdata->td_first = NULL;
 
484
 
 
485
  /* Allocate a queue head for the transfer queue.  */
 
486
  cdata->qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
 
487
  if (! cdata->qh)
 
488
    {
 
489
      grub_free (cdata);
 
490
      return GRUB_USB_ERR_INTERNAL;
 
491
    }
 
492
 
 
493
  grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
 
494
  
 
495
  for (i = 0; i < transfer->transcnt; i++)
 
496
    {
 
497
      grub_usb_transaction_t tr = &transfer->transactions[i];
 
498
 
 
499
      td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid,
 
500
                                  transfer->devaddr, tr->toggle,
 
501
                                  tr->size, tr->data,
 
502
                                  transfer->dev->speed);
 
503
      if (! td)
 
504
        {
 
505
          grub_size_t actual = 0;
 
506
          /* Terminate and free.  */
 
507
          td_prev->linkptr2 = 0;
 
508
          td_prev->linkptr = 1;
 
509
 
 
510
          if (cdata->td_first)
 
511
            grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual);
 
512
 
 
513
          grub_free (cdata);
 
514
          return GRUB_USB_ERR_INTERNAL;
 
515
        }
 
516
 
 
517
      if (! cdata->td_first)
 
518
        cdata->td_first = td;
 
519
      else
 
520
        {
 
521
          td_prev->linkptr2 = (grub_uint32_t) (grub_addr_t) td;
 
522
          td_prev->linkptr = (grub_uint32_t) (grub_addr_t) td;
 
523
          td_prev->linkptr |= 4;
 
524
        }
 
525
      td_prev = td;
 
526
    }
 
527
  td_prev->linkptr2 = 0;
 
528
  td_prev->linkptr = 1;
 
529
 
 
530
  grub_dprintf ("uhci", "setup transaction %d\n", transfer->type);
 
531
 
 
532
  /* Link it into the queue and terminate.  Now the transaction can
 
533
     take place.  */
 
534
  cdata->qh->elinkptr = (grub_uint32_t) (grub_addr_t) cdata->td_first;
 
535
 
 
536
  grub_dprintf ("uhci", "initiate transaction\n");
 
537
 
 
538
  transfer->controller_data = cdata;
 
539
 
 
540
  return GRUB_USB_ERR_NONE;
 
541
}
 
542
 
 
543
static grub_usb_err_t
 
544
grub_uhci_check_transfer (grub_usb_controller_t dev,
 
545
                          grub_usb_transfer_t transfer,
 
546
                          grub_size_t *actual)
 
547
{
 
548
  struct grub_uhci *u = (struct grub_uhci *) dev->data;
 
549
  grub_uhci_td_t errtd;
 
550
  struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
 
551
 
 
552
  *actual = 0;
 
553
 
 
554
  errtd = (grub_uhci_td_t) (grub_addr_t) (cdata->qh->elinkptr & ~0x0f);
 
555
  
 
556
  grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n",
 
557
                errtd->ctrl_status, errtd->buffer & (~15), errtd);
 
558
 
 
559
  /* Check if the transaction completed.  */
 
560
  if (cdata->qh->elinkptr & 1)
 
561
    {
 
562
      grub_dprintf ("uhci", "transaction complete\n");
 
563
 
 
564
      /* Place the QH back in the free list and deallocate the associated
 
565
         TDs.  */
 
566
      cdata->qh->elinkptr = 1;
 
567
      grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
 
568
      grub_free (cdata);
 
569
      return GRUB_USB_ERR_NONE;
 
570
    }
 
571
 
 
572
  grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status);
 
573
 
 
574
  if (!(errtd->ctrl_status & (1 << 23)))
 
575
    {
 
576
      grub_usb_err_t err = GRUB_USB_ERR_NONE;
 
577
 
 
578
      /* Check if the endpoint is stalled.  */
 
579
      if (errtd->ctrl_status & (1 << 22))
 
580
        err = GRUB_USB_ERR_STALL;
 
581
      
 
582
      /* Check if an error related to the data buffer occurred.  */
 
583
      else if (errtd->ctrl_status & (1 << 21))
 
584
        err = GRUB_USB_ERR_DATA;
 
585
      
 
586
      /* Check if a babble error occurred.  */
 
587
      else if (errtd->ctrl_status & (1 << 20))
 
588
        err = GRUB_USB_ERR_BABBLE;
 
589
      
 
590
      /* Check if a NAK occurred.  */
 
591
      else if (errtd->ctrl_status & (1 << 19))
 
592
        err = GRUB_USB_ERR_NAK;
 
593
      
 
594
      /* Check if a timeout occurred.  */
 
595
      else if (errtd->ctrl_status & (1 << 18))
 
596
        err = GRUB_USB_ERR_TIMEOUT;
 
597
      
 
598
      /* Check if a bitstuff error occurred.  */
 
599
      else if (errtd->ctrl_status & (1 << 17))
 
600
        err = GRUB_USB_ERR_BITSTUFF;
 
601
      
 
602
      if (err)
 
603
        {
 
604
          grub_dprintf ("uhci", "transaction failed\n");
 
605
 
 
606
          /* Place the QH back in the free list and deallocate the associated
 
607
             TDs.  */
 
608
          cdata->qh->elinkptr = 1;
 
609
          grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
 
610
          grub_free (cdata);
 
611
 
 
612
          return err;
 
613
        }
 
614
    }
 
615
 
 
616
  /* Fall through, no errors occurred, so the QH might be
 
617
     updated.  */
 
618
  grub_dprintf ("uhci", "transaction fallthrough\n");
 
619
 
 
620
  return GRUB_USB_ERR_WAIT;
 
621
}
 
622
 
 
623
static grub_usb_err_t
 
624
grub_uhci_cancel_transfer (grub_usb_controller_t dev,
 
625
                           grub_usb_transfer_t transfer)
 
626
{
 
627
  struct grub_uhci *u = (struct grub_uhci *) dev->data;
 
628
  grub_size_t actual;
 
629
  struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
 
630
 
 
631
  grub_dprintf ("uhci", "transaction cancel\n");
 
632
 
 
633
  /* Place the QH back in the free list and deallocate the associated
 
634
     TDs.  */
 
635
  cdata->qh->elinkptr = 1;
 
636
  grub_free_queue (u, cdata->qh, cdata->td_first, transfer, &actual);
 
637
  grub_free (cdata);
 
638
 
 
639
  return GRUB_USB_ERR_NONE;
 
640
}
 
641
 
 
642
static int
 
643
grub_uhci_iterate (int (*hook) (grub_usb_controller_t dev))
 
644
{
 
645
  struct grub_uhci *u;
 
646
  struct grub_usb_controller dev;
 
647
 
 
648
  for (u = uhci; u; u = u->next)
 
649
    {
 
650
      dev.data = u;
 
651
      if (hook (&dev))
 
652
        return 1;
 
653
    }
 
654
 
 
655
  return 0;
 
656
}
 
657
 
 
658
static grub_err_t
 
659
grub_uhci_portstatus (grub_usb_controller_t dev,
 
660
                      unsigned int port, unsigned int enable)
 
661
{
 
662
  struct grub_uhci *u = (struct grub_uhci *) dev->data;
 
663
  int reg;
 
664
  unsigned int status;
 
665
  grub_uint64_t endtime;
 
666
 
 
667
  grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase);
 
668
  
 
669
  grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
 
670
 
 
671
  if (port == 0)
 
672
    reg = GRUB_UHCI_REG_PORTSC1;
 
673
  else if (port == 1)
 
674
    reg = GRUB_UHCI_REG_PORTSC2;
 
675
  else
 
676
    return grub_error (GRUB_ERR_OUT_OF_RANGE,
 
677
                       "UHCI Root Hub port does not exist");
 
678
 
 
679
  status = grub_uhci_readreg16 (u, reg);
 
680
  grub_dprintf ("uhci", "detect=0x%02x\n", status);
 
681
 
 
682
  if (!enable) /* We don't need reset port */
 
683
    {
 
684
      /* Disable the port.  */
 
685
      grub_uhci_writereg16 (u, reg, 0 << 2);
 
686
      grub_dprintf ("uhci", "waiting for the port to be disabled\n");
 
687
      endtime = grub_get_time_ms () + 1000;
 
688
      while ((grub_uhci_readreg16 (u, reg) & (1 << 2)))
 
689
        if (grub_get_time_ms () > endtime)
 
690
          return grub_error (GRUB_ERR_IO, "UHCI Timed out - disable");
 
691
 
 
692
      status = grub_uhci_readreg16 (u, reg);
 
693
      grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
 
694
      return GRUB_ERR_NONE;
 
695
    }
 
696
    
 
697
  /* Reset the port.  */
 
698
  status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
 
699
  grub_uhci_writereg16 (u, reg, status | (1 << 9));
 
700
  grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
 
701
 
 
702
  /* Wait for the reset to complete.  XXX: How long exactly?  */
 
703
  grub_millisleep (50); /* For root hub should be nominaly 50ms */
 
704
  status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
 
705
  grub_uhci_writereg16 (u, reg, status & ~(1 << 9));
 
706
  grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
 
707
 
 
708
  /* Note: some debug prints were removed because they affected reset/enable timing. */
 
709
 
 
710
  grub_millisleep (1); /* Probably not needed at all or only few microsecs. */
 
711
 
 
712
  /* Reset bits Connect & Enable Status Change */
 
713
  status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
 
714
  grub_uhci_writereg16 (u, reg, status | (1 << 3) | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
 
715
  grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
 
716
 
 
717
  /* Enable the port.  */
 
718
  status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
 
719
  grub_uhci_writereg16 (u, reg, status | (1 << 2));
 
720
  grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
 
721
 
 
722
  endtime = grub_get_time_ms () + 1000;
 
723
  while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2)))
 
724
    if (grub_get_time_ms () > endtime)
 
725
      return grub_error (GRUB_ERR_IO, "UHCI Timed out - enable");
 
726
 
 
727
  /* Reset recovery time */
 
728
  grub_millisleep (10);
 
729
 
 
730
  /* Read final port status */
 
731
  status = grub_uhci_readreg16 (u, reg);
 
732
  grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
 
733
 
 
734
 
 
735
  return GRUB_ERR_NONE;
 
736
}
 
737
 
 
738
static grub_usb_speed_t
 
739
grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
 
740
{
 
741
  struct grub_uhci *u = (struct grub_uhci *) dev->data;
 
742
  int reg;
 
743
  unsigned int status;
 
744
 
 
745
  grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase);
 
746
  
 
747
  if (port == 0)
 
748
    reg = GRUB_UHCI_REG_PORTSC1;
 
749
  else if (port == 1)
 
750
    reg = GRUB_UHCI_REG_PORTSC2;
 
751
  else
 
752
    return grub_error (GRUB_ERR_OUT_OF_RANGE,
 
753
                       "UHCI Root Hub port does not exist");
 
754
 
 
755
  status = grub_uhci_readreg16 (u, reg);
 
756
 
 
757
  grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
 
758
 
 
759
  /* Connect Status Change bit - it detects change of connection */
 
760
  if (status & (1 << 1))
 
761
    {
 
762
      *changed = 1;
 
763
      /* Reset bit Connect Status Change */
 
764
      grub_uhci_writereg16 (u, reg, (status & GRUB_UHCI_REG_PORTSC_RW)
 
765
                            | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
 
766
    }
 
767
  else
 
768
    *changed = 0;
 
769
    
 
770
  if (! (status & 1))
 
771
    return GRUB_USB_SPEED_NONE;
 
772
  else if (status & (1 << 8))
 
773
    return GRUB_USB_SPEED_LOW;
 
774
  else
 
775
    return GRUB_USB_SPEED_FULL;
 
776
}
 
777
 
 
778
static int
 
779
grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused)))
 
780
{
 
781
  /* The root hub has exactly two ports.  */
 
782
  return 2;
 
783
}
 
784
 
 
785
 
 
786
static struct grub_usb_controller_dev usb_controller =
 
787
{
 
788
  .name = "uhci",
 
789
  .iterate = grub_uhci_iterate,
 
790
  .setup_transfer = grub_uhci_setup_transfer,
 
791
  .check_transfer = grub_uhci_check_transfer,
 
792
  .cancel_transfer = grub_uhci_cancel_transfer,
 
793
  .hubports = grub_uhci_hubports,
 
794
  .portstatus = grub_uhci_portstatus,
 
795
  .detect_dev = grub_uhci_detect_dev
 
796
};
 
797
 
 
798
GRUB_MOD_INIT(uhci)
 
799
{
 
800
  grub_uhci_inithw ();
 
801
  grub_usb_controller_dev_register (&usb_controller);
 
802
  grub_dprintf ("uhci", "registered\n");
 
803
}
 
804
 
 
805
GRUB_MOD_FINI(uhci)
 
806
{
 
807
  struct grub_uhci *u;
 
808
 
 
809
  /* Disable all UHCI controllers.  */
 
810
  for (u = uhci; u; u = u->next)
 
811
    grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
 
812
 
 
813
  /* Unregister the controller.  */
 
814
  grub_usb_controller_dev_unregister (&usb_controller);
 
815
}