📄 ide-iops.c
字号:
/* * linux/drivers/ide/ide-iops.c Version 0.37 Mar 05, 2003 * * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat <alan@redhat.com> * */#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/major.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/blkpg.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/hdreg.h>#include <linux/ide.h>#include <linux/bitops.h>#include <linux/nmi.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/io.h>/* * Conventional PIO operations for ATA devices */static u8 ide_inb (unsigned long port){ return (u8) inb(port);}static u16 ide_inw (unsigned long port){ return (u16) inw(port);}static void ide_insw (unsigned long port, void *addr, u32 count){ insw(port, addr, count);}static void ide_insl (unsigned long port, void *addr, u32 count){ insl(port, addr, count);}static void ide_outb (u8 val, unsigned long port){ outb(val, port);}static void ide_outbsync (ide_drive_t *drive, u8 addr, unsigned long port){ outb(addr, port);}static void ide_outw (u16 val, unsigned long port){ outw(val, port);}static void ide_outsw (unsigned long port, void *addr, u32 count){ outsw(port, addr, count);}static void ide_outsl (unsigned long port, void *addr, u32 count){ outsl(port, addr, count);}void default_hwif_iops (ide_hwif_t *hwif){ hwif->OUTB = ide_outb; hwif->OUTBSYNC = ide_outbsync; hwif->OUTW = ide_outw; hwif->OUTSW = ide_outsw; hwif->OUTSL = ide_outsl; hwif->INB = ide_inb; hwif->INW = ide_inw; hwif->INSW = ide_insw; hwif->INSL = ide_insl;}/* * MMIO operations, typically used for SATA controllers */static u8 ide_mm_inb (unsigned long port){ return (u8) readb((void __iomem *) port);}static u16 ide_mm_inw (unsigned long port){ return (u16) readw((void __iomem *) port);}static void ide_mm_insw (unsigned long port, void *addr, u32 count){ __ide_mm_insw((void __iomem *) port, addr, count);}static void ide_mm_insl (unsigned long port, void *addr, u32 count){ __ide_mm_insl((void __iomem *) port, addr, count);}static void ide_mm_outb (u8 value, unsigned long port){ writeb(value, (void __iomem *) port);}static void ide_mm_outbsync (ide_drive_t *drive, u8 value, unsigned long port){ writeb(value, (void __iomem *) port);}static void ide_mm_outw (u16 value, unsigned long port){ writew(value, (void __iomem *) port);}static void ide_mm_outsw (unsigned long port, void *addr, u32 count){ __ide_mm_outsw((void __iomem *) port, addr, count);}static void ide_mm_outsl (unsigned long port, void *addr, u32 count){ __ide_mm_outsl((void __iomem *) port, addr, count);}void default_hwif_mmiops (ide_hwif_t *hwif){ hwif->OUTB = ide_mm_outb; /* Most systems will need to override OUTBSYNC, alas however this one is controller specific! */ hwif->OUTBSYNC = ide_mm_outbsync; hwif->OUTW = ide_mm_outw; hwif->OUTSW = ide_mm_outsw; hwif->OUTSL = ide_mm_outsl; hwif->INB = ide_mm_inb; hwif->INW = ide_mm_inw; hwif->INSW = ide_mm_insw; hwif->INSL = ide_mm_insl;}EXPORT_SYMBOL(default_hwif_mmiops);u32 ide_read_24 (ide_drive_t *drive){ u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG); u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG); u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG); return (hcyl<<16)|(lcyl<<8)|sect;}void SELECT_DRIVE (ide_drive_t *drive){ if (HWIF(drive)->selectproc) HWIF(drive)->selectproc(drive); HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG);}EXPORT_SYMBOL(SELECT_DRIVE);void SELECT_INTERRUPT (ide_drive_t *drive){ if (HWIF(drive)->intrproc) HWIF(drive)->intrproc(drive); else HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG);}void SELECT_MASK (ide_drive_t *drive, int mask){ if (HWIF(drive)->maskproc) HWIF(drive)->maskproc(drive, mask);}void QUIRK_LIST (ide_drive_t *drive){ if (HWIF(drive)->quirkproc) drive->quirk_list = HWIF(drive)->quirkproc(drive);}/* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data. We call this * the "vlb_sync" sequence, which consists of three successive reads * of the sector count register location, with interrupts disabled * to ensure that the reads all happen together. */static void ata_vlb_sync(ide_drive_t *drive, unsigned long port){ (void) HWIF(drive)->INB(port); (void) HWIF(drive)->INB(port); (void) HWIF(drive)->INB(port);}/* * This is used for most PIO data transfers *from* the IDE interface */static void ata_input_data(ide_drive_t *drive, void *buffer, u32 wcount){ ide_hwif_t *hwif = HWIF(drive); u8 io_32bit = drive->io_32bit; if (io_32bit) { if (io_32bit & 2) { unsigned long flags; local_irq_save(flags); ata_vlb_sync(drive, IDE_NSECTOR_REG); hwif->INSL(IDE_DATA_REG, buffer, wcount); local_irq_restore(flags); } else hwif->INSL(IDE_DATA_REG, buffer, wcount); } else { hwif->INSW(IDE_DATA_REG, buffer, wcount<<1); }}/* * This is used for most PIO data transfers *to* the IDE interface */static void ata_output_data(ide_drive_t *drive, void *buffer, u32 wcount){ ide_hwif_t *hwif = HWIF(drive); u8 io_32bit = drive->io_32bit; if (io_32bit) { if (io_32bit & 2) { unsigned long flags; local_irq_save(flags); ata_vlb_sync(drive, IDE_NSECTOR_REG); hwif->OUTSL(IDE_DATA_REG, buffer, wcount); local_irq_restore(flags); } else hwif->OUTSL(IDE_DATA_REG, buffer, wcount); } else { hwif->OUTSW(IDE_DATA_REG, buffer, wcount<<1); }}/* * The following routines are mainly used by the ATAPI drivers. * * These routines will round up any request for an odd number of bytes, * so if an odd bytecount is specified, be sure that there's at least one * extra byte allocated for the buffer. */static void atapi_input_bytes(ide_drive_t *drive, void *buffer, u32 bytecount){ ide_hwif_t *hwif = HWIF(drive); ++bytecount;#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ insw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; }#endif /* CONFIG_ATARI || CONFIG_Q40 */ hwif->ata_input_data(drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) hwif->INSW(IDE_DATA_REG, ((u8 *)buffer)+(bytecount & ~0x03), 1);}static void atapi_output_bytes(ide_drive_t *drive, void *buffer, u32 bytecount){ ide_hwif_t *hwif = HWIF(drive); ++bytecount;#if defined(CONFIG_ATARI) || defined(CONFIG_Q40) if (MACH_IS_ATARI || MACH_IS_Q40) { /* Atari has a byte-swapped IDE interface */ outsw_swapw(IDE_DATA_REG, buffer, bytecount / 2); return; }#endif /* CONFIG_ATARI || CONFIG_Q40 */ hwif->ata_output_data(drive, buffer, bytecount / 4); if ((bytecount & 0x03) >= 2) hwif->OUTSW(IDE_DATA_REG, ((u8*)buffer)+(bytecount & ~0x03), 1);}void default_hwif_transport(ide_hwif_t *hwif){ hwif->ata_input_data = ata_input_data; hwif->ata_output_data = ata_output_data; hwif->atapi_input_bytes = atapi_input_bytes; hwif->atapi_output_bytes = atapi_output_bytes;}void ide_fix_driveid (struct hd_driveid *id){#ifndef __LITTLE_ENDIAN# ifdef __BIG_ENDIAN int i; u16 *stringcast; id->config = __le16_to_cpu(id->config); id->cyls = __le16_to_cpu(id->cyls); id->reserved2 = __le16_to_cpu(id->reserved2); id->heads = __le16_to_cpu(id->heads); id->track_bytes = __le16_to_cpu(id->track_bytes); id->sector_bytes = __le16_to_cpu(id->sector_bytes); id->sectors = __le16_to_cpu(id->sectors); id->vendor0 = __le16_to_cpu(id->vendor0); id->vendor1 = __le16_to_cpu(id->vendor1); id->vendor2 = __le16_to_cpu(id->vendor2); stringcast = (u16 *)&id->serial_no[0]; for (i = 0; i < (20/2); i++) stringcast[i] = __le16_to_cpu(stringcast[i]); id->buf_type = __le16_to_cpu(id->buf_type); id->buf_size = __le16_to_cpu(id->buf_size); id->ecc_bytes = __le16_to_cpu(id->ecc_bytes); stringcast = (u16 *)&id->fw_rev[0]; for (i = 0; i < (8/2); i++) stringcast[i] = __le16_to_cpu(stringcast[i]); stringcast = (u16 *)&id->model[0]; for (i = 0; i < (40/2); i++) stringcast[i] = __le16_to_cpu(stringcast[i]); id->dword_io = __le16_to_cpu(id->dword_io); id->reserved50 = __le16_to_cpu(id->reserved50); id->field_valid = __le16_to_cpu(id->field_valid); id->cur_cyls = __le16_to_cpu(id->cur_cyls); id->cur_heads = __le16_to_cpu(id->cur_heads); id->cur_sectors = __le16_to_cpu(id->cur_sectors); id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0); id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1); id->lba_capacity = __le32_to_cpu(id->lba_capacity); id->dma_1word = __le16_to_cpu(id->dma_1word); id->dma_mword = __le16_to_cpu(id->dma_mword); id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes); id->eide_dma_min = __le16_to_cpu(id->eide_dma_min); id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); id->eide_pio = __le16_to_cpu(id->eide_pio); id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); for (i = 0; i < 2; ++i) id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); for (i = 0; i < 4; ++i) id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); id->queue_depth = __le16_to_cpu(id->queue_depth); for (i = 0; i < 4; ++i) id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); id->major_rev_num = __le16_to_cpu(id->major_rev_num); id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); id->command_set_1 = __le16_to_cpu(id->command_set_1); id->command_set_2 = __le16_to_cpu(id->command_set_2); id->cfsse = __le16_to_cpu(id->cfsse); id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1); id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); id->csf_default = __le16_to_cpu(id->csf_default); id->dma_ultra = __le16_to_cpu(id->dma_ultra); id->trseuc = __le16_to_cpu(id->trseuc); id->trsEuc = __le16_to_cpu(id->trsEuc); id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); id->mprc = __le16_to_cpu(id->mprc); id->hw_config = __le16_to_cpu(id->hw_config); id->acoustic = __le16_to_cpu(id->acoustic); id->msrqs = __le16_to_cpu(id->msrqs); id->sxfert = __le16_to_cpu(id->sxfert); id->sal = __le16_to_cpu(id->sal); id->spg = __le32_to_cpu(id->spg); id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); for (i = 0; i < 22; i++) id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); id->last_lun = __le16_to_cpu(id->last_lun); id->word127 = __le16_to_cpu(id->word127); id->dlf = __le16_to_cpu(id->dlf); id->csfo = __le16_to_cpu(id->csfo); for (i = 0; i < 26; i++) id->words130_155[i] = __le16_to_cpu(id->words130_155[i]); id->word156 = __le16_to_cpu(id->word156); for (i = 0; i < 3; i++) id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); id->cfa_power = __le16_to_cpu(id->cfa_power); for (i = 0; i < 14; i++) id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); for (i = 0; i < 31; i++) id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); for (i = 0; i < 48; i++) id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); id->integrity_word = __le16_to_cpu(id->integrity_word);# else# error "Please fix <asm/byteorder.h>"# endif#endif}/* * ide_fixstring() cleans up and (optionally) byte-swaps a text string, * removing leading/trailing blanks and compressing internal blanks. * It is primarily used to tidy up the model name/number fields as * returned by the WIN_[P]IDENTIFY commands. */void ide_fixstring (u8 *s, const int bytecount, const int byteswap)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -