📄 ide.c
字号:
/* * Mambo Hard Disk Device Driver for PC * * by Ho Lee 2003/06/12 */#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/delay.h>#include <asm/byteorder.h>#include <linux/hdreg.h>/*#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif*/#include "mum.h"#include "mambo.h"#include "ide.h"// #define IDE_VERBOSE 1//// IDE registers// #define IDE_DATA_OFFSET (0)#define IDE_ERROR_OFFSET (1)#define IDE_NSECTOR_OFFSET (2)#define IDE_SECTOR_OFFSET (3)#define IDE_LCYL_OFFSET (4)#define IDE_HCYL_OFFSET (5)#define IDE_SELECT_OFFSET (6)#define IDE_STATUS_OFFSET (7)#define IDE_DATA_REG (MAMBO_IDE_BASE + (IDE_DATA_OFFSET << 2))#define IDE_ERROR_REG (MAMBO_IDE_BASE + (IDE_ERROR_OFFSET << 2))#define IDE_NSECTOR_REG (MAMBO_IDE_BASE + (IDE_NSECTOR_OFFSET << 2))#define IDE_SECTOR_REG (MAMBO_IDE_BASE + (IDE_SECTOR_OFFSET << 2))#define IDE_LCYL_REG (MAMBO_IDE_BASE + (IDE_LCYL_OFFSET << 2))#define IDE_HCYL_REG (MAMBO_IDE_BASE + (IDE_HCYL_OFFSET << 2))#define IDE_SELECT_REG (MAMBO_IDE_BASE + (IDE_SELECT_OFFSET << 2))#define IDE_STATUS_REG (MAMBO_IDE_BASE + (IDE_STATUS_OFFSET << 2))#define IDE_FEATURE_REG IDE_ERROR_REG#define IDE_COMMAND_REG IDE_STATUS_REG// ATA/ATAPI commands#define WIN_NOP 0x00#define WIN_DEVICE_RESET 0x08#define WIN_READ 0x20 /* 28-Bit */#define WIN_WRITE 0x30 /* 28-Bit */#define WIN_FORMAT 0x50#define WIN_SEEK 0x70#define WIN_DIAGNOSE 0x90#define WIN_PIDENTIFY 0xA1 #define WIN_READDMA 0xC8 /* read sectors using DMA transfers */#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */#define WIN_IDENTIFY 0xEC#define WIN_SETFEATURES 0xEF /* set special drive features *//* WIN_SETFEATURES sub-commands */#define SETFEATURES_XFER 0x03 /* Set transfer mode */# define XFER_UDMA_7 0x47 /* 0100|0111 */# define XFER_UDMA_6 0x46 /* 0100|0110 */# define XFER_UDMA_5 0x45 /* 0100|0101 */# define XFER_UDMA_4 0x44 /* 0100|0100 */# define XFER_UDMA_3 0x43 /* 0100|0011 */# define XFER_UDMA_2 0x42 /* 0100|0010 */# define XFER_UDMA_1 0x41 /* 0100|0001 */# define XFER_UDMA_0 0x40 /* 0100|0000 */# define XFER_MW_DMA_2 0x22 /* 0010|0010 */# define XFER_MW_DMA_1 0x21 /* 0010|0001 */# define XFER_MW_DMA_0 0x20 /* 0010|0000 */# define XFER_SW_DMA_2 0x12 /* 0001|0010 */# define XFER_SW_DMA_1 0x11 /* 0001|0001 */# define XFER_SW_DMA_0 0x10 /* 0001|0000 */# define XFER_PIO_4 0x0C /* 0000|1100 */# define XFER_PIO_3 0x0B /* 0000|1011 */# define XFER_PIO_2 0x0A /* 0000|1010 */# define XFER_PIO_1 0x09 /* 0000|1001 */# define XFER_PIO_0 0x08 /* 0000|1000 */# define XFER_PIO_SLOW 0x00 /* 0000|0000 */// status#define ERR_STAT 0x01#define INDEX_STAT 0x02#define ECC_STAT 0x04#define DRQ_STAT 0x08#define SEEK_STAT 0x10#define WRERR_STAT 0x20#define READY_STAT 0x40#define BUSY_STAT 0x80//// IDE register I/O//static __inline__ void OUT_BYTE(int drive, unsigned char data, unsigned int port){ mum_writew(IDE_CONTROLLER(drive), (unsigned short) data, port);}static __inline__ void OUT_WORD(int drive, unsigned short data, unsigned int port){ mum_writew(IDE_CONTROLLER(drive), (unsigned short) data, port);}static __inline unsigned char IN_BYTE(int drive, unsigned int port){ unsigned char data = (unsigned char) (mum_readw(IDE_CONTROLLER(drive), port) & 0xff); return data;}static __inline unsigned short IN_WORD(int drive, unsigned int port){ unsigned short data = (unsigned short) (mum_readw(IDE_CONTROLLER(drive), port)); return data;}//// IDE Initialize//static int g_ide_dsinited = 0;ide_info_t g_ideinfo[MAX_DRIVES];int ide_dsinit(void){ int i; memset(g_ideinfo, 0, sizeof g_ideinfo); for (i = 0; i < MAX_DRIVES; ++i) g_ideinfo[i].select.all = ((IDE_DRIVE(i) << 4) | 0xa0); g_ide_dsinited = 1; return 0;}int ide_found(int mask){ int drive, found = 0; ide_info_t *pideinfo; if (!g_ide_dsinited) ide_dsinit(); for (drive = 0; drive < MAX_DRIVES; ++drive) { pideinfo = g_ideinfo + drive; if (pideinfo->type & mask) found |= (1 << drive); } return found;}int ide_probe(int drivemask, int verbose){ int drive, nfound; ide_info_t *pideinfo; if (!g_ide_dsinited) ide_dsinit(); for (drive = 0, nfound = 0; drive < MAX_DRIVES; ++drive) { if (drivemask & (1 << drive)) { if (verbose) printk("Probing drive %d:%d :\n", IDE_CONTROLLER(drive), IDE_DRIVE(drive)); pideinfo = ide_identify(drive); if (pideinfo->type != IDE_NONE) { if (verbose) printk(" Found %s device : ", (pideinfo->type == IDE_ATA) ? "ATA" : "ATAPI"); else printk("IDE %d:%d (%s) : ", IDE_CONTROLLER(drive), IDE_DRIVE(drive), (pideinfo->type == IDE_ATA) ? "ATA" : "ATAPI"); } if (pideinfo->type != IDE_NONE) { ++nfound; printk("%s, %dMB, %s, %s\n", pideinfo->id.model, pideinfo->size, pideinfo->lba ? "LBA" : "CHS", pideinfo->cap_udma ? "UDMA" : (pideinfo->cap_dma ? "DMA" : "No DMA")); if (!pideinfo->lba && verbose) printk(" cylinders = %d, heads = %d, sectors = %d\n", pideinfo->cyls, pideinfo->heads, pideinfo->sectors); if (verbose) { printk(" "); if (pideinfo->cap_udma) printk("Ultra DMA = 0x%04x, ", pideinfo->id.dma_ultra); printk("Multi-word DMA = 0x%04x, Single-word DMA = 0x%04x, PIO = 0x%04x\n", pideinfo->id.dma_mword, pideinfo->id.dma_1word, pideinfo->id.eide_pio_modes); printk(" EIDE DMA Min = 0x%04x, EIDE DMA Time = 0x%04x\n", pideinfo->id.eide_dma_min, pideinfo->id.eide_dma_time); printk(" PIO mode support :"); if (pideinfo->id.eide_pio_modes & 0x01) printk(" 3"); if (pideinfo->id.eide_pio_modes & 0x02) printk(" 4"); printk("\n"); printk(" Major Rev = 0x%04x, Minor Rev = 0x%04x\n", pideinfo->id.major_rev_num, pideinfo->id.minor_rev_num); // dump_memory(&pideinfo->id, 0, SECTOR_SIZE, 1); } // setup DMA mode /* if (pideinfo->id.dma_mword & 0x0f) { // find the most high DMA mode for (i = 2; i >= 0; --i) { if (pideinfo->id.dma_mword & (1 << i)) { ide_set_drive_speed(drive, XFER_MW_DMA_0 | i); if (verbose) printk(" Use Multiword DMA mode %d\n", i); break; } } } */ } } } return nfound;}//// IDE command//static int ide_command(int cmd, int drive, int feature, int cyl, int head, int sector, int nsector, void *buf, int buflen);static int ide_wait_stat(int drive, int mask, int waitmask, int usetimeout);static int ide_select_drive(int drive);static void ide_input_data(int drive, unsigned int *buf, unsigned int wcount);static void ide_output_data(int drive, unsigned int *buf, unsigned int wcount);static void ide_fixstring(unsigned char *s, const int bytecount, const int byteswap);int ide_command(int cmd, int drive, int feature, int cyl, int head, int sector, int nsector, void *buf, int buflen){#if IDE_VERBOSE static struct { int cmd; char *name; } s_cmdnamelist[] = { { WIN_NOP, "NOP" }, { WIN_DEVICE_RESET, "Device Reset" }, { WIN_READ, "Read Sector" }, { WIN_WRITE, "Write Sector" }, { WIN_FORMAT, "Format Sector" }, { WIN_SEEK, "Seek" }, { WIN_DIAGNOSE, "Diagnose" }, { WIN_PIDENTIFY, "ATAPI Identify" }, { WIN_READDMA, "Read Sector by DMA" }, { WIN_WRITEDMA, "Write Sector by DMA" }, { WIN_IDENTIFY, "ATA Identify" }, { -1, NULL }, }; int i;#endif int status; // Selecting drive#if IDE_VERBOSE printk(" Select, ");#endif if (ide_select_drive(drive)) {#if IDE_VERBOSE printk("No device\n");#endif return 1; } // Sending command OUT_BYTE(drive, feature, IDE_FEATURE_REG); OUT_BYTE(drive, nsector, IDE_NSECTOR_REG); OUT_BYTE(drive, sector, IDE_SECTOR_REG); OUT_BYTE(drive, (cyl & 0xff), IDE_LCYL_REG); OUT_BYTE(drive, (cyl >> 8) & 0xff, IDE_HCYL_REG); OUT_BYTE(drive, head | g_ideinfo[drive].select.all, IDE_SELECT_REG); #if IDE_VERBOSE for (i = 0; s_cmdnamelist[i].cmd >= 0; ++i) { if (cmd == s_cmdnamelist[i].cmd) { printk("%s, ", s_cmdnamelist[i].name); break; } } if (s_cmdnamelist[i].cmd < 0) printk("Command 0x%02x, ", cmd);#endif OUT_BYTE(drive, cmd, IDE_COMMAND_REG); // Reading or Writing data if (buf && buflen > 0) { if (cmd == WIN_WRITE) { while (buflen > 0) {#if IDE_VERBOSE printk("Writing\n"); if (buflen > SECTOR_SIZE) printk(", "); else printk("\n");#endif ide_wait_stat(drive, DRQ_STAT, DRQ_STAT, 0); ide_output_data(drive, (unsigned int *) buf, SECTOR_SIZE / 4); buf = (unsigned char *) buf + SECTOR_SIZE; buflen -= SECTOR_SIZE; ide_wait_stat(drive, BUSY_STAT, 0, 0); } } else { memset(buf, 0, buflen); while (buflen > 0) { ide_wait_stat(drive, BUSY_STAT, 0, 0); status = IN_BYTE(drive, IDE_STATUS_REG); if (status & DRQ_STAT) {#if IDE_VERBOSE printk("Reading"); if (buflen > SECTOR_SIZE) printk(", "); else printk("\n");#endif ide_input_data(drive, (unsigned int *) buf, SECTOR_SIZE / 4); buf = (unsigned char *) buf + SECTOR_SIZE; buflen -= SECTOR_SIZE; } else {#if IDE_VERBOSE printk("No Data\n"); #endif return 2; } } } } #if IDE_VERBOSE else printk("\n");#endif return 0;}#define IDE_WAIT_TIMEOUT 20000int ide_wait_stat(int drive, int mask, int waitmask, int usetimeout){ int status; int timeout = IDE_WAIT_TIMEOUT; do { status = IN_BYTE(drive, IDE_STATUS_REG); if (usetimeout) { if (timeout-- == 0) return 1; mdelay(1); } } while ((status & mask) != waitmask);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -