merge mainline into ahci
This commit is contained in:
		
						commit
						de2690be7c
					
				
					 984 changed files with 85724 additions and 20016 deletions
				
			
		
							
								
								
									
										513
									
								
								grub-core/disk/pata.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								grub-core/disk/pata.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,513 @@ | |||
| /* ata_pthru.c - ATA pass through for ata.mod.  */ | ||||
| /*
 | ||||
|  *  GRUB  --  GRand Unified Bootloader | ||||
|  *  Copyright (C) 2009  Free Software Foundation, Inc. | ||||
|  * | ||||
|  *  GRUB is free software: you can redistribute it and/or modify | ||||
|  *  it under the terms of the GNU General Public License as published by | ||||
|  *  the Free Software Foundation, either version 3 of the License, or | ||||
|  *  (at your option) any later version. | ||||
|  * | ||||
|  *  GRUB is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *  GNU General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU General Public License | ||||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #include <grub/ata.h> | ||||
| #include <grub/scsi.h> | ||||
| #include <grub/disk.h> | ||||
| #include <grub/dl.h> | ||||
| #include <grub/mm.h> | ||||
| #include <grub/pci.h> | ||||
| #include <grub/cs5536.h> | ||||
| #include <grub/time.h> | ||||
| 
 | ||||
| /* At the moment, only two IDE ports are supported.  */ | ||||
| static const grub_port_t grub_pata_ioaddress[] = { GRUB_ATA_CH0_PORT1, | ||||
| 						   GRUB_ATA_CH1_PORT1 }; | ||||
| static const grub_port_t grub_pata_ioaddress2[] = { GRUB_ATA_CH0_PORT2,  | ||||
| 						    GRUB_ATA_CH1_PORT2 }; | ||||
| 
 | ||||
| struct grub_pata_device | ||||
| { | ||||
|   /* IDE port to use.  */ | ||||
|   int port; | ||||
| 
 | ||||
|   /* IO addresses on which the registers for this device can be
 | ||||
|      found.  */ | ||||
|   grub_port_t ioaddress; | ||||
|   grub_port_t ioaddress2; | ||||
| 
 | ||||
|   /* Two devices can be connected to a single cable.  Use this field
 | ||||
|      to select device 0 (commonly known as "master") or device 1 | ||||
|      (commonly known as "slave").  */ | ||||
|   int device; | ||||
| 
 | ||||
|   struct grub_pata_device *next; | ||||
| }; | ||||
| 
 | ||||
| static struct grub_pata_device *grub_pata_devices; | ||||
| 
 | ||||
| static inline void | ||||
| grub_pata_regset (struct grub_pata_device *dev, int reg, int val) | ||||
| { | ||||
|   grub_outb (val, dev->ioaddress + reg); | ||||
| } | ||||
| 
 | ||||
| static inline grub_uint8_t | ||||
| grub_pata_regget (struct grub_pata_device *dev, int reg) | ||||
| { | ||||
|   return grub_inb (dev->ioaddress + reg); | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| grub_pata_regset2 (struct grub_pata_device *dev, int reg, int val) | ||||
| { | ||||
|   grub_outb (val, dev->ioaddress2 + reg); | ||||
| } | ||||
| 
 | ||||
| static inline grub_uint8_t | ||||
| grub_pata_regget2 (struct grub_pata_device *dev, int reg) | ||||
| { | ||||
|   return grub_inb (dev->ioaddress2 + reg); | ||||
| } | ||||
| 
 | ||||
| /* Wait for !BSY.  */ | ||||
| static grub_err_t | ||||
| grub_pata_wait_not_busy (struct grub_pata_device *dev, int milliseconds) | ||||
| { | ||||
|   /* ATA requires 400ns (after a write to CMD register) or
 | ||||
|      1 PIO cycle (after a DRQ block transfer) before | ||||
|      first check of BSY.  */ | ||||
|   grub_millisleep (1); | ||||
| 
 | ||||
|   int i = 1; | ||||
|   grub_uint8_t sts; | ||||
|   while ((sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS)) | ||||
| 	 & GRUB_ATA_STATUS_BUSY) | ||||
|     { | ||||
|       if (i >= milliseconds) | ||||
|         { | ||||
| 	  grub_dprintf ("pata", "timeout: %dms, status=0x%x\n", | ||||
| 			milliseconds, sts); | ||||
| 	  return grub_error (GRUB_ERR_TIMEOUT, "PATA timeout"); | ||||
| 	} | ||||
| 
 | ||||
|       grub_millisleep (1); | ||||
|       i++; | ||||
|     } | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static inline grub_err_t | ||||
| grub_pata_check_ready (struct grub_pata_device *dev) | ||||
| { | ||||
|   if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) & GRUB_ATA_STATUS_BUSY) | ||||
|     return grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_STD); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static inline void | ||||
| grub_pata_wait (void) | ||||
| { | ||||
|   grub_millisleep (50); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_pata_pio_read (struct grub_pata_device *dev, char *buf, grub_size_t size) | ||||
| {  | ||||
|   grub_uint16_t *buf16 = (grub_uint16_t *) buf; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   /* Read in the data, word by word.  */ | ||||
|   for (i = 0; i < size / 2; i++) | ||||
|     buf16[i] = grub_le_to_cpu16 (grub_inw(dev->ioaddress + GRUB_ATA_REG_DATA)); | ||||
|   if (size & 1) | ||||
|     buf[size - 1] = (char) grub_le_to_cpu16 (grub_inw (dev->ioaddress | ||||
| 						       + GRUB_ATA_REG_DATA)); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| grub_pata_pio_write (struct grub_pata_device *dev, char *buf, grub_size_t size) | ||||
| { | ||||
|   grub_uint16_t *buf16 = (grub_uint16_t *) buf; | ||||
|   unsigned int i; | ||||
| 
 | ||||
|   /* Write the data, word by word.  */ | ||||
|   for (i = 0; i < size / 2; i++) | ||||
|     grub_outw(grub_cpu_to_le16 (buf16[i]), dev->ioaddress + GRUB_ATA_REG_DATA); | ||||
| } | ||||
| 
 | ||||
| /* ATA pass through support, used by hdparm.mod.  */ | ||||
| static grub_err_t | ||||
| grub_pata_readwrite (struct grub_ata *disk, | ||||
| 		     struct grub_disk_ata_pass_through_parms *parms) | ||||
| { | ||||
|   struct grub_pata_device *dev = (struct grub_pata_device *) disk->data; | ||||
|   grub_size_t nread = 0; | ||||
| 
 | ||||
|   if (! (parms->cmdsize == 0 || parms->cmdsize == 12)) | ||||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, | ||||
| 		       "ATAPI non-12 byte commands not supported"); | ||||
| 
 | ||||
|   grub_dprintf ("pata", "pata_pass_through: cmd=0x%x, features=0x%x, sectors=0x%x\n", | ||||
| 		parms->taskfile.cmd, | ||||
| 		parms->taskfile.features, | ||||
| 		parms->taskfile.sectors); | ||||
|   grub_dprintf ("pata", "lba_high=0x%x, lba_mid=0x%x, lba_low=0x%x, size=%d\n", | ||||
| 	        parms->taskfile.lba_high, | ||||
| 	        parms->taskfile.lba_mid, | ||||
| 	        parms->taskfile.lba_low, parms->size); | ||||
| 
 | ||||
|   /* Set registers.  */ | ||||
|   grub_pata_regset (dev, GRUB_ATA_REG_DISK, (parms->cmdsize ? 0 : 0xE0) | ||||
| 		    | dev->device << 4 | ||||
| 		    | (parms->taskfile.disk & 0xf)); | ||||
|   if (grub_pata_check_ready (dev)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = GRUB_ATA_REG_SECTORS; i <= GRUB_ATA_REG_LBAHIGH; i++) | ||||
|     grub_pata_regset (dev, i, | ||||
| 		     parms->taskfile.raw[7 + (i - GRUB_ATA_REG_SECTORS)]); | ||||
|   for (i = GRUB_ATA_REG_FEATURES; i <= GRUB_ATA_REG_LBAHIGH; i++) | ||||
|     grub_pata_regset (dev, i, parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES]); | ||||
| 
 | ||||
|   /* Start command. */ | ||||
|   grub_pata_regset (dev, GRUB_ATA_REG_CMD, parms->taskfile.cmd); | ||||
| 
 | ||||
|   /* Wait for !BSY.  */ | ||||
|   if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Check status.  */ | ||||
|   grub_int8_t sts = grub_pata_regget (dev, GRUB_ATA_REG_STATUS); | ||||
|   grub_dprintf ("pata", "status=0x%x\n", sts); | ||||
| 
 | ||||
|   if (parms->cmdsize) | ||||
|     { | ||||
|       grub_uint8_t irs = grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON); | ||||
|       /* OK if DRQ is asserted and interrupt reason is as expected.  */ | ||||
|       if (!((sts & GRUB_ATA_STATUS_DRQ) | ||||
| 	    && (irs & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_CMD_OUT)) | ||||
| 	return grub_error (GRUB_ERR_READ_ERROR, "ATAPI protocol error"); | ||||
|       /* Write the packet.  */ | ||||
|       grub_pata_pio_write (dev, parms->cmd, parms->cmdsize); | ||||
|     } | ||||
| 
 | ||||
|   /* Transfer data.  */ | ||||
|   while (nread < parms->size | ||||
| 	 && ((sts & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
| 	     == GRUB_ATA_STATUS_DRQ) | ||||
| 	 && (!parms->cmdsize  | ||||
| 	     || ((grub_pata_regget (dev, GRUB_ATAPI_REG_IREASON) | ||||
| 		  & GRUB_ATAPI_IREASON_MASK) == GRUB_ATAPI_IREASON_DATA_IN))) | ||||
|     { | ||||
|       unsigned cnt; | ||||
|       if (parms->cmdsize) | ||||
| 	{ | ||||
| 	  cnt = grub_pata_regget (dev, GRUB_ATAPI_REG_CNTHIGH) << 8 | ||||
| 	    | grub_pata_regget (dev, GRUB_ATAPI_REG_CNTLOW); | ||||
| 	  grub_dprintf("pata", "DRQ count=%u\n", cnt); | ||||
| 
 | ||||
| 	  /* Count of last transfer may be uneven.  */ | ||||
| 	  if (! (0 < cnt && cnt <= parms->size - nread | ||||
| 		 && (! (cnt & 1) || cnt == parms->size - nread))) | ||||
| 	    return grub_error (GRUB_ERR_READ_ERROR, | ||||
| 			       "invalid ATAPI transfer count"); | ||||
| 	} | ||||
|       else | ||||
| 	cnt = GRUB_DISK_SECTOR_SIZE; | ||||
|       if (cnt > parms->size - nread) | ||||
| 	cnt = parms->size - nread; | ||||
| 
 | ||||
|       if (parms->write) | ||||
| 	grub_pata_pio_write (dev, (char *) parms->buffer + nread, cnt); | ||||
|       else | ||||
| 	grub_pata_pio_read (dev, (char *) parms->buffer + nread, cnt); | ||||
| 
 | ||||
|       nread += cnt; | ||||
|     } | ||||
|   if (parms->write) | ||||
|     { | ||||
|       /* Check for write error.  */ | ||||
|       if (grub_pata_wait_not_busy (dev, GRUB_ATA_TOUT_DATA)) | ||||
| 	return grub_errno; | ||||
| 
 | ||||
|       if (grub_pata_regget (dev, GRUB_ATA_REG_STATUS) | ||||
| 	  & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
| 	return grub_error (GRUB_ERR_WRITE_ERROR, "ATA write error"); | ||||
|     } | ||||
|   parms->size = nread; | ||||
| 
 | ||||
|   /* Return registers.  */ | ||||
|   for (i = GRUB_ATA_REG_ERROR; i <= GRUB_ATA_REG_STATUS; i++) | ||||
|     parms->taskfile.raw[i - GRUB_ATA_REG_FEATURES] = grub_pata_regget (dev, i); | ||||
| 
 | ||||
|   grub_dprintf ("pata", "status=0x%x, error=0x%x, sectors=0x%x\n", | ||||
| 	        parms->taskfile.status, | ||||
| 	        parms->taskfile.error, | ||||
| 		parms->taskfile.sectors); | ||||
| 
 | ||||
|   if (parms->taskfile.status | ||||
|       & (GRUB_ATA_STATUS_DRQ | GRUB_ATA_STATUS_ERR)) | ||||
|     return grub_error (GRUB_ERR_READ_ERROR, "PATA passthrough failed"); | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| check_device (struct grub_pata_device *dev) | ||||
| { | ||||
|   grub_pata_regset (dev, GRUB_ATA_REG_DISK, dev->device << 4); | ||||
|   grub_pata_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_pata_regset (dev, GRUB_ATA_REG_SECTORS, 0x5A); | ||||
|   grub_pata_wait (); | ||||
|   grub_uint8_t sec = grub_pata_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.  */ | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_pata_device_initialize (int port, int device, int addr, int addr2) | ||||
| { | ||||
|   struct grub_pata_device *dev; | ||||
|   struct grub_pata_device **devp; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   grub_dprintf ("pata", "detecting device %d,%d (0x%x, 0x%x)\n", | ||||
| 		port, device, addr, addr2); | ||||
| 
 | ||||
|   dev = grub_malloc (sizeof(*dev)); | ||||
|   if (! dev) | ||||
|     return grub_errno; | ||||
| 
 | ||||
|   /* Setup the device information.  */ | ||||
|   dev->port = port; | ||||
|   dev->device = device; | ||||
|   dev->ioaddress = addr + GRUB_MACHINE_PCI_IO_BASE; | ||||
|   dev->ioaddress2 = addr2 + GRUB_MACHINE_PCI_IO_BASE; | ||||
|   dev->next = NULL; | ||||
| 
 | ||||
|   /* Register the device.  */ | ||||
|   for (devp = &grub_pata_devices; *devp; devp = &(*devp)->next); | ||||
|   *devp = dev; | ||||
| 
 | ||||
|   err = check_device (dev); | ||||
|   if (err) | ||||
|     grub_print_error (); | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int NESTED_FUNC_ATTR | ||||
| grub_pata_pciinit (grub_pci_device_t dev, | ||||
| 		   grub_pci_id_t pciid) | ||||
| { | ||||
|   static int compat_use[2] = { 0 }; | ||||
|   grub_pci_address_t addr; | ||||
|   grub_uint32_t class; | ||||
|   grub_uint32_t bar1; | ||||
|   grub_uint32_t bar2; | ||||
|   int rega; | ||||
|   int regb; | ||||
|   int i; | ||||
|   static int controller = 0; | ||||
|   int cs5536 = 0; | ||||
|   int nports = 2; | ||||
| 
 | ||||
|   /* Read class.  */ | ||||
|   addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS); | ||||
|   class = grub_pci_read (addr); | ||||
| 
 | ||||
|   /* AMD CS5536 Southbridge.  */ | ||||
|   if (pciid == GRUB_CS5536_PCIID) | ||||
|     { | ||||
|       cs5536 = 1; | ||||
|       nports = 1; | ||||
|     } | ||||
| 
 | ||||
|   /* Check if this class ID matches that of a PCI IDE Controller.  */ | ||||
|   if (!cs5536 && (class >> 16 != 0x0101)) | ||||
|     return 0; | ||||
| 
 | ||||
|   for (i = 0; i < nports; i++) | ||||
|     { | ||||
|       /* Set to 0 when the channel operated in compatibility mode.  */ | ||||
|       int compat; | ||||
| 
 | ||||
|       /* We don't support non-compatibility mode for CS5536.  */ | ||||
|       if (cs5536) | ||||
| 	compat = 0; | ||||
|       else | ||||
| 	compat = (class >> (8 + 2 * i)) & 1; | ||||
| 
 | ||||
|       rega = 0; | ||||
|       regb = 0; | ||||
| 
 | ||||
|       /* If the channel is in compatibility mode, just assign the
 | ||||
| 	 default registers.  */ | ||||
|       if (compat == 0 && !compat_use[i]) | ||||
| 	{ | ||||
| 	  rega = grub_pata_ioaddress[i]; | ||||
| 	  regb = grub_pata_ioaddress2[i]; | ||||
| 	  compat_use[i] = 1; | ||||
| 	} | ||||
|       else if (compat) | ||||
| 	{ | ||||
| 	  /* Read the BARs, which either contain a mmapped IO address
 | ||||
| 	     or the IO port address.  */ | ||||
| 	  addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES | ||||
| 					+ sizeof (grub_uint64_t) * i); | ||||
| 	  bar1 = grub_pci_read (addr); | ||||
| 	  addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESSES | ||||
| 					+ sizeof (grub_uint64_t) * i | ||||
| 					+ sizeof (grub_uint32_t)); | ||||
| 	  bar2 = grub_pci_read (addr); | ||||
| 
 | ||||
| 	  /* Check if the BARs describe an IO region.  */ | ||||
| 	  if ((bar1 & 1) && (bar2 & 1)) | ||||
| 	    { | ||||
| 	      rega = bar1 & ~3; | ||||
| 	      regb = bar2 & ~3; | ||||
| 	    } | ||||
| 	} | ||||
| 
 | ||||
|       grub_dprintf ("pata", | ||||
| 		    "PCI dev (%d,%d,%d) compat=%d rega=0x%x regb=0x%x\n", | ||||
| 		    grub_pci_get_bus (dev), grub_pci_get_device (dev), | ||||
| 		    grub_pci_get_function (dev), compat, rega, regb); | ||||
| 
 | ||||
|       if (rega && regb) | ||||
| 	{ | ||||
| 	  grub_errno = GRUB_ERR_NONE; | ||||
| 	  grub_pata_device_initialize (controller * 2 + i, 0, rega, regb); | ||||
| 
 | ||||
| 	  /* Most errors raised by grub_ata_device_initialize() are harmless.
 | ||||
| 	     They just indicate this particular drive is not responding, most | ||||
| 	     likely because it doesn't exist.  We might want to ignore specific | ||||
| 	     error types here, instead of printing them.  */ | ||||
| 	  if (grub_errno) | ||||
| 	    { | ||||
| 	      grub_print_error (); | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	    } | ||||
| 
 | ||||
| 	  grub_pata_device_initialize (controller * 2 + i, 1, rega, regb); | ||||
| 
 | ||||
| 	  /* Likewise.  */ | ||||
| 	  if (grub_errno) | ||||
| 	    { | ||||
| 	      grub_print_error (); | ||||
| 	      grub_errno = GRUB_ERR_NONE; | ||||
| 	    } | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   controller++; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_pata_initialize (void) | ||||
| { | ||||
|   grub_pci_iterate (grub_pata_pciinit); | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static grub_err_t | ||||
| grub_pata_open (int id, int devnum, struct grub_ata *ata) | ||||
| { | ||||
|   struct grub_pata_device *dev; | ||||
|   struct grub_pata_device *devfnd = 0; | ||||
|   grub_err_t err; | ||||
| 
 | ||||
|   if (id != GRUB_SCSI_SUBSYSTEM_PATA) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a PATA device"); | ||||
| 
 | ||||
|   for (dev = grub_pata_devices; dev; dev = dev->next) | ||||
|     { | ||||
|       if (dev->port * 2 + dev->device == devnum) | ||||
| 	{ | ||||
| 	  devfnd = dev; | ||||
| 	  break; | ||||
| 	} | ||||
|     } | ||||
| 
 | ||||
|   grub_dprintf ("pata", "opening PATA dev `ata%d'\n", devnum); | ||||
| 
 | ||||
|   if (! devfnd) | ||||
|     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no such PATA device"); | ||||
| 
 | ||||
|   err = check_device (devfnd); | ||||
|   if (err) | ||||
|     return err; | ||||
| 
 | ||||
|   ata->data = devfnd; | ||||
| 
 | ||||
|   return GRUB_ERR_NONE; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| grub_pata_iterate (int (*hook) (int id, int bus)) | ||||
| { | ||||
|   struct grub_pata_device *dev; | ||||
| 
 | ||||
|   for (dev = grub_pata_devices; dev; dev = dev->next) | ||||
|     if (hook (GRUB_SCSI_SUBSYSTEM_PATA, dev->port * 2 + dev->device)) | ||||
|       return 1; | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static struct grub_ata_dev grub_pata_dev = | ||||
|   { | ||||
|     .iterate = grub_pata_iterate, | ||||
|     .open = grub_pata_open, | ||||
|     .readwrite = grub_pata_readwrite, | ||||
|   }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| GRUB_MOD_INIT(ata_pthru) | ||||
| { | ||||
|   /* To prevent two drivers operating on the same disks.  */ | ||||
|   grub_disk_firmware_is_tainted = 1; | ||||
|   if (grub_disk_firmware_fini) | ||||
|     { | ||||
|       grub_disk_firmware_fini (); | ||||
|       grub_disk_firmware_fini = NULL; | ||||
|     } | ||||
| 
 | ||||
|   /* ATA initialization.  */ | ||||
|   grub_pata_initialize (); | ||||
| 
 | ||||
|   grub_ata_dev_register (&grub_pata_dev); | ||||
| } | ||||
| 
 | ||||
| GRUB_MOD_FINI(ata_pthru) | ||||
| { | ||||
|   grub_ata_dev_unregister (&grub_pata_dev); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue