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

« back to all changes in this revision

Viewing changes to disk/usbms.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
 
/* usbms.c - USB Mass Storage 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/usb.h>
23
 
#include <grub/scsi.h>
24
 
#include <grub/scsicmd.h>
25
 
#include <grub/misc.h>
26
 
 
27
 
#define GRUB_USBMS_DIRECTION_BIT        7
28
 
 
29
 
/* The USB Mass Storage Command Block Wrapper.  */
30
 
struct grub_usbms_cbw
31
 
{
32
 
  grub_uint32_t signature;
33
 
  grub_uint32_t tag;
34
 
  grub_uint32_t transfer_length;
35
 
  grub_uint8_t flags;
36
 
  grub_uint8_t lun;
37
 
  grub_uint8_t length;
38
 
  grub_uint8_t cbwcb[16];
39
 
} __attribute__ ((packed));
40
 
 
41
 
struct grub_usbms_csw
42
 
{
43
 
  grub_uint32_t signature;
44
 
  grub_uint32_t tag;
45
 
  grub_uint32_t residue;
46
 
  grub_uint8_t status;
47
 
} __attribute__ ((packed));
48
 
 
49
 
struct grub_usbms_dev
50
 
{
51
 
  struct grub_usb_device *dev;
52
 
 
53
 
  int luns;
54
 
 
55
 
  int config;
56
 
  int interface;
57
 
  struct grub_usb_desc_endp *in;
58
 
  struct grub_usb_desc_endp *out;
59
 
 
60
 
  int in_maxsz;
61
 
  int out_maxsz;
62
 
};
63
 
typedef struct grub_usbms_dev *grub_usbms_dev_t;
64
 
 
65
 
/* FIXME: remove limit.  */
66
 
#define MAX_USBMS_DEVICES 128
67
 
static grub_usbms_dev_t grub_usbms_devices[MAX_USBMS_DEVICES];
68
 
 
69
 
static grub_err_t
70
 
grub_usbms_reset (grub_usb_device_t dev, int interface)
71
 
{
72
 
  return grub_usb_control_msg (dev, 0x21, 255, 0, interface, 0, 0);
73
 
}
74
 
 
75
 
static void
76
 
grub_usbms_detach (grub_usb_device_t usbdev, int config, int interface)
77
 
{
78
 
  unsigned i;
79
 
  for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
80
 
    if (grub_usbms_devices[i] && grub_usbms_devices[i]->dev == usbdev
81
 
        && grub_usbms_devices[i]->interface == interface
82
 
        && grub_usbms_devices[i]->config == config)
83
 
      {
84
 
        grub_free (grub_usbms_devices[i]);
85
 
        grub_usbms_devices[i] = 0;
86
 
      }
87
 
}
88
 
 
89
 
static int
90
 
grub_usbms_attach (grub_usb_device_t usbdev, int configno, int interfno)
91
 
{
92
 
  struct grub_usb_desc_if *interf
93
 
    = usbdev->config[configno].interf[interfno].descif;
94
 
  int j;
95
 
  grub_uint8_t luns = 0;
96
 
  unsigned curnum;
97
 
  grub_usb_err_t err;
98
 
 
99
 
  for (curnum = 0; curnum < ARRAY_SIZE (grub_usbms_devices); curnum++)
100
 
    if (!grub_usbms_devices[curnum])
101
 
      break;
102
 
 
103
 
  if (curnum == ARRAY_SIZE (grub_usbms_devices))
104
 
    return 0;
105
 
 
106
 
  interf = usbdev->config[configno].interf[interfno].descif;
107
 
 
108
 
  if ((interf->subclass != GRUB_USBMS_SUBCLASS_BULK
109
 
       /* Experimental support of RBC, MMC-2, UFI, SFF-8070i devices */
110
 
       && interf->subclass != GRUB_USBMS_SUBCLASS_RBC
111
 
       && interf->subclass != GRUB_USBMS_SUBCLASS_MMC2
112
 
       && interf->subclass != GRUB_USBMS_SUBCLASS_UFI 
113
 
       && interf->subclass != GRUB_USBMS_SUBCLASS_SFF8070 )
114
 
      || interf->protocol != GRUB_USBMS_PROTOCOL_BULK)
115
 
    return 0;
116
 
 
117
 
  grub_usbms_devices[curnum] = grub_zalloc (sizeof (struct grub_usbms_dev));
118
 
  if (! grub_usbms_devices[curnum])
119
 
    return 0;
120
 
 
121
 
  grub_usbms_devices[curnum]->dev = usbdev;
122
 
  grub_usbms_devices[curnum]->interface = interfno;
123
 
 
124
 
  grub_dprintf ("usbms", "alive\n");
125
 
 
126
 
  /* Iterate over all endpoints of this interface, at least a
127
 
     IN and OUT bulk endpoint are required.  */
128
 
  for (j = 0; j < interf->endpointcnt; j++)
129
 
    {
130
 
      struct grub_usb_desc_endp *endp;
131
 
      endp = &usbdev->config[0].interf[interfno].descendp[j];
132
 
 
133
 
      if ((endp->endp_addr & 128) && (endp->attrib & 3) == 2)
134
 
        {
135
 
          /* Bulk IN endpoint.  */
136
 
          grub_usbms_devices[curnum]->in = endp;
137
 
          /* Clear Halt is not possible yet! */
138
 
          /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
139
 
          grub_usbms_devices[curnum]->in_maxsz = endp->maxpacket;
140
 
        }
141
 
      else if (!(endp->endp_addr & 128) && (endp->attrib & 3) == 2)
142
 
        {
143
 
          /* Bulk OUT endpoint.  */
144
 
          grub_usbms_devices[curnum]->out = endp;
145
 
          /* Clear Halt is not possible yet! */
146
 
          /* grub_usb_clear_halt (usbdev, endp->endp_addr); */
147
 
          grub_usbms_devices[curnum]->out_maxsz = endp->maxpacket;
148
 
        }
149
 
    }
150
 
 
151
 
  if (!grub_usbms_devices[curnum]->in || !grub_usbms_devices[curnum]->out)
152
 
    {
153
 
      grub_free (grub_usbms_devices[curnum]);
154
 
      grub_usbms_devices[curnum] = 0;
155
 
      return 0;
156
 
    }
157
 
 
158
 
  grub_dprintf ("usbms", "alive\n");
159
 
 
160
 
  /* XXX: Activate the first configuration.  */
161
 
  grub_usb_set_configuration (usbdev, 1);
162
 
 
163
 
  /* Query the amount of LUNs.  */
164
 
  err = grub_usb_control_msg (usbdev, 0xA1, 254, 0, interfno, 1, (char *) &luns);
165
 
                
166
 
  if (err)
167
 
    {
168
 
      /* In case of a stall, clear the stall.  */
169
 
      if (err == GRUB_USB_ERR_STALL)
170
 
        {
171
 
          grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->in->endp_addr);
172
 
          grub_usb_clear_halt (usbdev, grub_usbms_devices[curnum]->out->endp_addr);
173
 
        }
174
 
      /* Just set the amount of LUNs to one.  */
175
 
      grub_errno = GRUB_ERR_NONE;
176
 
      grub_usbms_devices[curnum]->luns = 1;
177
 
    }
178
 
  else
179
 
    /* luns = 0 means one LUN with ID 0 present ! */
180
 
    /* We get from device not number of LUNs but highest
181
 
     * LUN number. LUNs are numbered from 0, 
182
 
     * i.e. number of LUNs is luns+1 ! */
183
 
    grub_usbms_devices[curnum]->luns = luns + 1;
184
 
 
185
 
  grub_dprintf ("usbms", "alive\n");
186
 
 
187
 
  usbdev->config[configno].interf[interfno].detach_hook = grub_usbms_detach;
188
 
 
189
 
#if 0 /* All this part should be probably deleted.
190
 
       * This make trouble on some devices if they are not in
191
 
       * Phase Error state - and there they should be not in such state...
192
 
       * Bulk only mass storage reset procedure should be used only
193
 
       * on place and in time when it is really necessary. */
194
 
  /* Reset recovery procedure */
195
 
  /* Bulk-Only Mass Storage Reset, after the reset commands
196
 
     will be accepted.  */
197
 
  grub_usbms_reset (usbdev, i);
198
 
  grub_usb_clear_halt (usbdev, usbms->in->endp_addr);
199
 
  grub_usb_clear_halt (usbdev, usbms->out->endp_addr);
200
 
#endif
201
 
 
202
 
  return 1;
203
 
}
204
 
 
205
 
 
206
 
 
207
 
static int
208
 
grub_usbms_iterate (int (*hook) (int bus, int luns))
209
 
{
210
 
  unsigned i;
211
 
 
212
 
  grub_usb_poll_devices ();
213
 
 
214
 
  for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
215
 
    if (grub_usbms_devices[i])
216
 
      {
217
 
        if (hook (i, grub_usbms_devices[i]->luns))
218
 
          return 1;
219
 
      }
220
 
 
221
 
  return 0;
222
 
}
223
 
 
224
 
static grub_err_t
225
 
grub_usbms_transfer (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
226
 
                     grub_size_t size, char *buf, int read_write)
227
 
{
228
 
  struct grub_usbms_cbw cbw;
229
 
  grub_usbms_dev_t dev = (grub_usbms_dev_t) scsi->data;
230
 
  struct grub_usbms_csw status;
231
 
  static grub_uint32_t tag = 0;
232
 
  grub_usb_err_t err = GRUB_USB_ERR_NONE;
233
 
  grub_usb_err_t errCSW = GRUB_USB_ERR_NONE;
234
 
  int retrycnt = 3 + 1;
235
 
 
236
 
 retry:
237
 
  retrycnt--;
238
 
  if (retrycnt == 0)
239
 
    return grub_error (GRUB_ERR_IO, "USB Mass Storage stalled");
240
 
 
241
 
  /* Setup the request.  */
242
 
  grub_memset (&cbw, 0, sizeof (cbw));
243
 
  cbw.signature = grub_cpu_to_le32 (0x43425355);
244
 
  cbw.tag = tag++;
245
 
  cbw.transfer_length = grub_cpu_to_le32 (size);
246
 
  cbw.flags = (!read_write) << GRUB_USBMS_DIRECTION_BIT;
247
 
  cbw.lun = scsi->lun; /* In USB MS CBW are LUN bits on another place than in SCSI CDB, both should be set correctly. */
248
 
  cbw.length = cmdsize;
249
 
  grub_memcpy (cbw.cbwcb, cmd, cmdsize);
250
 
  
251
 
  /* Debug print of CBW content. */
252
 
  grub_dprintf ("usb", "CBW: sign=0x%08x tag=0x%08x len=0x%08x\n",
253
 
        cbw.signature, cbw.tag, cbw.transfer_length);
254
 
  grub_dprintf ("usb", "CBW: flags=0x%02x lun=0x%02x CB_len=0x%02x\n",
255
 
        cbw.flags, cbw.lun, cbw.length);
256
 
  grub_dprintf ("usb", "CBW: cmd:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
257
 
        cbw.cbwcb[ 0], cbw.cbwcb[ 1], cbw.cbwcb[ 2], cbw.cbwcb[ 3],
258
 
        cbw.cbwcb[ 4], cbw.cbwcb[ 5], cbw.cbwcb[ 6], cbw.cbwcb[ 7],
259
 
        cbw.cbwcb[ 8], cbw.cbwcb[ 9], cbw.cbwcb[10], cbw.cbwcb[11],
260
 
        cbw.cbwcb[12], cbw.cbwcb[13], cbw.cbwcb[14], cbw.cbwcb[15]);
261
 
 
262
 
  /* Write the request.
263
 
   * XXX: Error recovery is maybe still not fully correct. */
264
 
  err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr,
265
 
                             sizeof (cbw), (char *) &cbw);
266
 
  if (err)
267
 
    {
268
 
      if (err == GRUB_USB_ERR_STALL)
269
 
        {
270
 
          grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
271
 
          goto CheckCSW;
272
 
        }
273
 
      return grub_error (GRUB_ERR_IO, "USB Mass Storage request failed");
274
 
    }
275
 
 
276
 
  /* Read/write the data, (maybe) according to specification.  */
277
 
  if (size && (read_write == 0))
278
 
    {
279
 
      err = grub_usb_bulk_read (dev->dev, dev->in->endp_addr, size, buf);
280
 
      grub_dprintf ("usb", "read: %d %d\n", err, GRUB_USB_ERR_STALL); 
281
 
      if (err)
282
 
        {
283
 
          if (err == GRUB_USB_ERR_STALL)
284
 
            grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
285
 
          goto CheckCSW;
286
 
        }
287
 
      /* Debug print of received data. */
288
 
      grub_dprintf ("usb", "buf:\n");
289
 
      if (size <= 64)
290
 
        {
291
 
          unsigned i;
292
 
          for (i = 0; i < size; i++)
293
 
            grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
294
 
        }
295
 
      else
296
 
          grub_dprintf ("usb", "Too much data for debug print...\n");
297
 
    }
298
 
  else if (size)
299
 
    {
300
 
      err = grub_usb_bulk_write (dev->dev, dev->out->endp_addr, size, buf);
301
 
      grub_dprintf ("usb", "write: %d %d\n", err, GRUB_USB_ERR_STALL);
302
 
      grub_dprintf ("usb", "First 16 bytes of sent data:\n %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
303
 
        buf[ 0], buf[ 1], buf[ 2], buf[ 3],
304
 
        buf[ 4], buf[ 5], buf[ 6], buf[ 7],
305
 
        buf[ 8], buf[ 9], buf[10], buf[11],
306
 
        buf[12], buf[13], buf[14], buf[15]);
307
 
      if (err)
308
 
        {
309
 
          if (err == GRUB_USB_ERR_STALL)
310
 
            grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
311
 
          goto CheckCSW;
312
 
        }
313
 
      /* Debug print of sent data. */
314
 
      if (size <= 256)
315
 
        {
316
 
          unsigned i;
317
 
          for (i=0; i<size; i++)
318
 
            grub_dprintf ("usb", "0x%02x: 0x%02x\n", i, buf[i]);
319
 
        }
320
 
      else
321
 
          grub_dprintf ("usb", "Too much data for debug print...\n");
322
 
    }
323
 
 
324
 
  /* Read the status - (maybe) according to specification.  */
325
 
CheckCSW:
326
 
  errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
327
 
                    sizeof (status), (char *) &status);
328
 
  if (errCSW)
329
 
    {
330
 
      grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
331
 
      errCSW = grub_usb_bulk_read (dev->dev, dev->in->endp_addr,
332
 
                                sizeof (status), (char *) &status);
333
 
      if (errCSW)
334
 
        { /* Bulk-only reset device. */
335
 
          grub_dprintf ("usb", "Bulk-only reset device - errCSW\n");
336
 
          grub_usbms_reset (dev->dev, dev->interface);
337
 
          grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
338
 
          grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
339
 
          goto retry;
340
 
        }
341
 
    }
342
 
 
343
 
  /* Debug print of CSW content. */
344
 
  grub_dprintf ("usb", "CSW: sign=0x%08x tag=0x%08x resid=0x%08x\n",
345
 
        status.signature, status.tag, status.residue);
346
 
  grub_dprintf ("usb", "CSW: status=0x%02x\n", status.status);
347
 
  
348
 
  /* If phase error or not valid signature, do bulk-only reset device. */
349
 
  if ((status.status == 2) ||
350
 
      (status.signature != grub_cpu_to_le32(0x53425355)))
351
 
    { /* Bulk-only reset device. */
352
 
      grub_dprintf ("usb", "Bulk-only reset device - bad status\n");
353
 
      grub_usbms_reset (dev->dev, dev->interface);
354
 
      grub_usb_clear_halt (dev->dev, dev->in->endp_addr);
355
 
      grub_usb_clear_halt (dev->dev, dev->out->endp_addr);
356
 
 
357
 
      goto retry;
358
 
    }
359
 
 
360
 
  /* If "command failed" status or data transfer failed -> error */
361
 
  if ((status.status || err) && !read_write)
362
 
    return grub_error (GRUB_ERR_READ_ERROR,
363
 
                       "error communication with USB Mass Storage device");
364
 
  else if ((status.status || err) && read_write)
365
 
    return grub_error (GRUB_ERR_WRITE_ERROR,
366
 
                       "error communication with USB Mass Storage device");
367
 
 
368
 
  return GRUB_ERR_NONE;
369
 
}
370
 
 
371
 
 
372
 
static grub_err_t
373
 
grub_usbms_read (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
374
 
                 grub_size_t size, char *buf)
375
 
{
376
 
  return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 0);
377
 
}
378
 
 
379
 
static grub_err_t
380
 
grub_usbms_write (struct grub_scsi *scsi, grub_size_t cmdsize, char *cmd,
381
 
                  grub_size_t size, char *buf)
382
 
{
383
 
  return grub_usbms_transfer (scsi, cmdsize, cmd, size, buf, 1);
384
 
}
385
 
 
386
 
static grub_err_t
387
 
grub_usbms_open (int devnum, struct grub_scsi *scsi)
388
 
{
389
 
  grub_usb_poll_devices ();
390
 
 
391
 
  if (!grub_usbms_devices[devnum])
392
 
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
393
 
                       "unknown USB Mass Storage device");
394
 
 
395
 
  scsi->data = grub_usbms_devices[devnum];
396
 
  scsi->luns = grub_usbms_devices[devnum]->luns;
397
 
 
398
 
  return GRUB_ERR_NONE;
399
 
}
400
 
 
401
 
static struct grub_scsi_dev grub_usbms_dev =
402
 
  {
403
 
    .name = "usb",
404
 
    .id = GRUB_SCSI_SUBSYSTEM_USBMS,
405
 
    .iterate = grub_usbms_iterate,
406
 
    .open = grub_usbms_open,
407
 
    .read = grub_usbms_read,
408
 
    .write = grub_usbms_write
409
 
  };
410
 
 
411
 
struct grub_usb_attach_desc attach_hook =
412
 
{
413
 
  .class = GRUB_USB_CLASS_MASS_STORAGE,
414
 
  .hook = grub_usbms_attach
415
 
};
416
 
 
417
 
GRUB_MOD_INIT(usbms)
418
 
{
419
 
  grub_usb_register_attach_hook_class (&attach_hook);
420
 
  grub_scsi_dev_register (&grub_usbms_dev);
421
 
}
422
 
 
423
 
GRUB_MOD_FINI(usbms)
424
 
{
425
 
  unsigned i;
426
 
  for (i = 0; i < ARRAY_SIZE (grub_usbms_devices); i++)
427
 
    {
428
 
      grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
429
 
        .interf[grub_usbms_devices[i]->interface].detach_hook = 0;
430
 
      grub_usbms_devices[i]->dev->config[grub_usbms_devices[i]->config]
431
 
        .interf[grub_usbms_devices[i]->interface].attached = 0;
432
 
    }
433
 
  grub_usb_unregister_attach_hook_class (&attach_hook);
434
 
  grub_scsi_dev_unregister (&grub_usbms_dev);
435
 
}