Mercurial > ecos
diff packages/devs/disk/ide/current/src/ide_disk.c @ 2535:6ffeb2616b4b
* cdl/ide_disk.cdl: Rename of the devices to be /dev/idediskX/Y
so that all disk drivers have unique device names.
* cdl/ide_disk.cdl:
* src/ide_diskc: Add a configurable startup delay to allow slow
disks to initialize. Add support for 8-bit data path. Remove the
identity check which are retired in the ATA standard. Optimize the
read/write functions.
| author | asl |
|---|---|
| date | Sun, 24 Aug 2008 12:55:41 +0000 |
| parents | 6d4c075d2939 |
| children | 74dbf4c3f2e1 |
line wrap: on
line diff
--- a/packages/devs/disk/ide/current/src/ide_disk.c +++ b/packages/devs/disk/ide/current/src/ide_disk.c @@ -48,6 +48,7 @@ //========================================================================== #include <pkgconf/devs_disk_ide.h> +#include <pkgconf/io_disk.h> #include <cyg/infra/cyg_type.h> #include <cyg/infra/cyg_ass.h> @@ -64,7 +65,9 @@ // ---------------------------------------------------------------------------- -//#define DEBUG 1 +#ifdef CYGDBG_IO_DISK_DEBUG +# define DEBUG 1 +#endif #ifdef DEBUG # define D(fmt,args...) diag_printf(fmt, ## args) @@ -94,6 +97,8 @@ IDE_DISK_INSTANCE(2, 1, 0, true, CYGDAT_ IDE_DISK_INSTANCE(3, 1, 1, true, CYGDAT_IO_DISK_IDE_DISK3_NAME); #endif +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + // ---------------------------------------------------------------------------- static void @@ -101,8 +106,7 @@ id_strcpy(char *dest, cyg_uint16 *src, c { int i; - for (i = 0; i < size; i+=2) - { + for (i=0; i<size; i+=2) { *dest++ = (char)(*src >> 8); *dest++ = (char)(*src & 0x00FF); src++; @@ -121,7 +125,9 @@ static inline void } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ)); } +// ---------------------------------------------------------------------------- // Wait while the device is busy with the last command + static inline int __wait_busy(int ctlr) { @@ -137,6 +143,8 @@ static inline int return 0; } +// ---------------------------------------------------------------------------- + static inline int __wait_for_drq(int ctlr) { @@ -156,18 +164,20 @@ static inline int return 0; } +// ---------------------------------------------------------------------------- // Return true if any devices attached to controller + static int ide_presence_detect(int ctlr) { cyg_uint8 sel, val; int i; - for (i = 0; i < 2; i++) { + for (i = 0; i < HAL_IDE_NUM_CONTROLLERS; i++) { sel = (i << 4) | 0xA0; - CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); + CYGACC_CALL_IF_DELAY_US(50000U); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel); - CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); + CYGACC_CALL_IF_DELAY_US(50000U); HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val); if (val == sel) { #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE @@ -180,6 +190,8 @@ ide_presence_detect(int ctlr) return 0; } +// ---------------------------------------------------------------------------- + static int ide_reset(int ctlr) { @@ -193,14 +205,14 @@ ide_reset(int ctlr) // #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted - CYGACC_CALL_IF_DELAY_US(5000); + CYGACC_CALL_IF_DELAY_US(5000U); HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared - CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); + CYGACC_CALL_IF_DELAY_US(50000U); #endif // wait 30 seconds max for not busy and drive ready - for (delay = 0; delay < 300; ++delay) { - CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000); + for (delay=0; delay<300; ++delay) { + CYGACC_CALL_IF_DELAY_US(100000U); HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status); if (!(status & IDE_STAT_BSY)) { if (status & IDE_STAT_DRDY) { @@ -211,43 +223,76 @@ ide_reset(int ctlr) return 0; } +// ---------------------------------------------------------------------------- + static int ide_ident(int ctlr, int dev, cyg_uint16 *buf) { int i; - if (!__wait_busy(ctlr)) { + if (!__wait_busy(ctlr)) return 0; - } - + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEC); - CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000); + CYGACC_CALL_IF_DELAY_US(50000U); - if (!__wait_for_drq(ctlr)) { + if (!__wait_for_drq(ctlr)) return 0; + + for (i=0; i<(CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE/sizeof(cyg_uint16)); + i++, buf++) { + HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); } - - for (i = 0; i < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16)); - i++, buf++) - HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf); - return 1; } +// ---------------------------------------------------------------------------- +// Requests the disk to use an 8-bit data path. This is probably ignored by +// most modern drives, but is supported by compact flash devices. + +#ifdef CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH +static int +ide_8bit_mode(int ctlr, int dev, cyg_bool on) +{ + cyg_uint8 stat; + + if (!__wait_busy(ctlr)) + return 0; + + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4); + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_FEATURES, 0x01); + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEF); + + if (!__wait_busy(ctlr)) + return 0; + + HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, stat); + return (stat & 1) ? 0 : 1; +} +#endif + +// ---------------------------------------------------------------------------- +// Reads a group of contiguous sectors from the drive. +// It can read up to 256 sectors. + static int ide_read_sector(int ctlr, int dev, cyg_uint32 start, cyg_uint8 *buf, cyg_uint32 len) { - int j, c; - cyg_uint16 p; - cyg_uint8 * b=buf; + int i, nword; + cyg_uint8 lenb; + cyg_uint16 w; + + if (len==0 || !__wait_busy(ctlr)) + return 0; - if(!__wait_busy(ctlr)) { - return 0; - } - - HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1 + len = MIN(len, 256); + lenb = (len == 256) ? 0 : ((cyg_uint8) len); + + nword = len * CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16); + + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, lenb); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff); @@ -257,52 +302,68 @@ ide_read_sector(int ctlr, int dev, cyg_u if (!__wait_for_drq(ctlr)) return 0; - // - // It would be fine if all buffers were word aligned, - // but who knows - // - for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16)); - j++) { - HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, p); - if (c++<(len*512)) *b++=p&0xff; - if (c++<(len*512)) *b++=(p>>8)&0xff; + + if ((int) buf & 1) { + // Unaligned buffer, so split each word manually + for (i=0; i<nword; i++) { + HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, w); + *buf++ = w & 0xff; + *buf++ = (w>>8) & 0xff; + } } - return 1; + else { + cyg_uint16* wbuf = (cyg_uint16*) buf; + for (i=0; i<nword; i++, wbuf++) + HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *wbuf); + } + return (int) len; } +// ---------------------------------------------------------------------------- +// Writes a group of contiguous sectors to the drive. +// It can write up to 256 sectors. + static int ide_write_sector(int ctlr, int dev, cyg_uint32 start, - cyg_uint8 *buf, cyg_uint32 len) + cyg_uint8 *buf, cyg_uint32 len) { - int j, c; - cyg_uint16 p; - cyg_uint8 * b=buf; + int i, nword; + cyg_uint8 lenb; + cyg_uint16 w; - if(!__wait_busy(ctlr)) { - return 0; - } - - HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1 + if (len==0 || !__wait_busy(ctlr)) + return 0; + + len = MIN(len, 256); + lenb = (len == 256) ? 0 : ((cyg_uint8) len); + + nword = len * CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16); + + HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, lenb); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, - ((start >> 24) & 0xf) | (dev << 4) | 0x40); + ((start >> 24) & 0xf) | (dev << 4) | 0x40); HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x30); if (!__wait_for_drq(ctlr)) return 0; - // - // It would be fine if all buffers were word aligned, - // but who knows - // - for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16)); - j++) { - p = (c++<(len*512)) ? *b++ : 0; - p |= (c++<(len*512)) ? (*b++<<8) : 0; - HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, p); + + if ((int) buf & 1) { + // Unaligned buffer, so assemble each word manually + for (i=0; i<nword; ++i) { + w = *buf++; + w |= (cyg_uint16) (*buf++) << 8; + HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, w); + } } - return 1; + else { + cyg_uint16* wbuf = (cyg_uint16*) buf; + for (i=0; i<nword; ++i) + HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, *wbuf++); + } + return (int) len; } // ---------------------------------------------------------------------------- @@ -328,6 +389,11 @@ ide_disk_init(struct cyg_devtab_entry *t D("No IDE controller for channel %d:%d\n", info->port, info->chan); return false; } + +#if CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY + CYGACC_CALL_IF_DELAY_US(CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY*1000U); +#endif + if (!ide_present[info->port]) { ide_present[info->port]=ide_presence_detect(info->port); if (!ide_present[info->port]) { @@ -342,6 +408,13 @@ ide_disk_init(struct cyg_devtab_entry *t return false; } } + +#ifdef CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH + if (!ide_8bit_mode(info->port, info->chan, true)) { + D("IDE disk %d:%d failed to enter 8-bit mode\n", + info->port, info->chan); + } +#endif D("IDE %d:%d identify drive\n", info->port, info->chan); @@ -350,9 +423,9 @@ ide_disk_init(struct cyg_devtab_entry *t return false; } - id_strcpy(ident.serial, ide_idData->serial, 20); + id_strcpy(ident.serial, ide_idData->serial, 20); id_strcpy(ident.firmware_rev, ide_idData->firmware_rev, 8); - id_strcpy(ident.model_num, ide_idData->model_num, 40); + id_strcpy(ident.model_num, ide_idData->model_num, 40); ident.cylinders_num = ide_idData->num_cylinders; ident.heads_num = ide_idData->num_heads; @@ -360,6 +433,8 @@ ide_disk_init(struct cyg_devtab_entry *t ident.lba_sectors_num = ide_idData->lba_total_sectors[1] << 16 | ide_idData->lba_total_sectors[0]; ident.phys_block_size = 1; + + // TODO: Should this be CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE? ident.max_transfer = 512; D("\tSerial : %s\n", ident.serial); @@ -367,13 +442,7 @@ ide_disk_init(struct cyg_devtab_entry *t D("\tModel : %s\n", ident.model_num); D("\tC/H/S : %d/%d/%d\n", ident.cylinders_num, ident.heads_num, ident.sectors_num); - D("\tKind : %x\n", (ide_idData->general_conf>>8)&0x1f); - if (((ide_idData->general_conf>>8)&0x1f)!=2) { - diag_printf("IDE device %d:%d is not a hard disk!\n", - info->port, info->chan); - return false; - } if (!(chan->callbacks->disk_init)(tab)) return false;
