Handle defered device registration

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-03-14 23:18:13 +01:00
parent 5dbb0fc055
commit 9b6e10bbbf

View file

@ -332,11 +332,38 @@ grub_ata_identify (struct grub_ata_device *dev)
return 0; return 0;
} }
static grub_err_t
check_device (struct grub_ata_device *dev)
{
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
grub_ata_wait ();
/* Try to detect if the port is in use by writing to it,
waiting for a while and reading it again. If the value
was preserved, there is a device connected. */
grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
grub_ata_wait ();
grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
grub_dprintf ("ata", "sectors=0x%x\n", sec);
if (sec != 0x5A)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no device connected");
/* The above test may detect a second (slave) device
connected to a SATA controller which supports only one
(master) device. It is not safe to use the status register
READY bit to check for controller channel existence. Some
ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
/* Use the IDENTIFY DEVICE command to query the device. */
return grub_ata_identify (dev);
}
static grub_err_t static grub_err_t
grub_ata_device_initialize (int port, int device, int addr, int addr2) grub_ata_device_initialize (int port, int device, int addr, int addr2)
{ {
struct grub_ata_device *dev; struct grub_ata_device *dev;
struct grub_ata_device **devp; struct grub_ata_device **devp;
grub_err_t err;
grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n", grub_dprintf ("ata", "detecting device %d,%d (0x%x, 0x%x)\n",
port, device, addr, addr2); port, device, addr, addr2);
@ -352,39 +379,14 @@ grub_ata_device_initialize (int port, int device, int addr, int addr2)
dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE;
dev->next = NULL; dev->next = NULL;
grub_ata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4);
grub_ata_wait ();
/* Try to detect if the port is in use by writing to it,
waiting for a while and reading it again. If the value
was preserved, there is a device connected. */
grub_ata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A);
grub_ata_wait ();
grub_uint8_t sec = grub_ata_regget (dev, GRUB_ATA_REG_SECTORS);
grub_dprintf ("ata", "sectors=0x%x\n", sec);
if (sec != 0x5A)
{
grub_free(dev);
return 0;
}
/* The above test may detect a second (slave) device
connected to a SATA controller which supports only one
(master) device. It is not safe to use the status register
READY bit to check for controller channel existence. Some
ATAPI commands (RESET, DIAGNOSTIC) may clear this bit. */
/* Use the IDENTIFY DEVICE command to query the device. */
if (grub_ata_identify (dev))
{
grub_free (dev);
return 0;
}
/* Register the device. */ /* Register the device. */
for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next); for (devp = &grub_ata_devices; *devp; devp = &(*devp)->next);
*devp = dev; *devp = dev;
err = check_device (dev);
if (err)
grub_print_error ();
return 0; return 0;
} }
@ -667,6 +669,14 @@ grub_ata_iterate (int (*hook) (const char *name))
for (dev = grub_ata_devices; dev; dev = dev->next) for (dev = grub_ata_devices; dev; dev = dev->next)
{ {
char devname[10]; char devname[10];
grub_err_t err;
err = check_device (dev);
if (err)
{
grub_errno = GRUB_ERR_NONE;
continue;
}
if (dev->atapi) if (dev->atapi)
continue; continue;
@ -685,6 +695,7 @@ static grub_err_t
grub_ata_open (const char *name, grub_disk_t disk) grub_ata_open (const char *name, grub_disk_t disk)
{ {
struct grub_ata_device *dev; struct grub_ata_device *dev;
grub_err_t err;
for (dev = grub_ata_devices; dev; dev = dev->next) for (dev = grub_ata_devices; dev; dev = dev->next)
{ {
@ -701,6 +712,11 @@ grub_ata_open (const char *name, grub_disk_t disk)
if (dev->atapi) if (dev->atapi)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not an ATA harddisk");
err = check_device (dev);
if (err)
return err;
disk->total_sectors = dev->size; disk->total_sectors = dev->size;
disk->id = (unsigned long) dev; disk->id = (unsigned long) dev;
@ -757,6 +773,16 @@ grub_atapi_iterate (int (*hook) (const char *name, int luns))
for (dev = grub_ata_devices; dev; dev = dev->next) for (dev = grub_ata_devices; dev; dev = dev->next)
{ {
char devname[10]; char devname[10];
grub_err_t err;
err = check_device (dev);
if (err)
{
grub_errno = GRUB_ERR_NONE;
continue;
}
grub_snprintf (devname, sizeof (devname), grub_snprintf (devname, sizeof (devname),
"ata%d", dev->port * 2 + dev->device); "ata%d", dev->port * 2 + dev->device);
@ -827,6 +853,7 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi)
{ {
struct grub_ata_device *dev; struct grub_ata_device *dev;
struct grub_ata_device *devfnd = 0; struct grub_ata_device *devfnd = 0;
grub_err_t err;
for (dev = grub_ata_devices; dev; dev = dev->next) for (dev = grub_ata_devices; dev; dev = dev->next)
{ {
@ -846,6 +873,13 @@ grub_atapi_open (const char *name, struct grub_scsi *scsi)
if (! devfnd) if (! devfnd)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
err = check_device (devfnd);
if (err)
return err;
if (! devfnd->atapi)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such ATAPI device");
scsi->data = devfnd; scsi->data = devfnd;
return GRUB_ERR_NONE; return GRUB_ERR_NONE;