Mercurial > ecos
changeset 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 | 41a4df71f380 |
| children | 8e41333db259 |
| files | packages/devs/disk/ide/current/ChangeLog packages/devs/disk/ide/current/cdl/ide_disk.cdl packages/devs/disk/ide/current/src/ide_disk.c |
| diffstat | 3 files changed, 185 insertions(+), 76 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/devs/disk/ide/current/ChangeLog +++ b/packages/devs/disk/ide/current/ChangeLog @@ -1,3 +1,16 @@ +2008-08-19 Andrew Lunn <andrew.lunn@ascom.ch> + + * cdl/ide_disk.cdl: Rename of the devices to be /dev/idediskX/Y + so that all disk drivers have unique device names. + +2008-08-18 Frank Pagliughi <fpagliughi@mindspring.com> + + * 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. + 2006-11-17 Jonathan Larmour <jifl@eCosCentric.com> * src/ide_disk.c (ide_read_sector, ide_write_sector): Length
--- a/packages/devs/disk/ide/current/cdl/ide_disk.cdl +++ b/packages/devs/disk/ide/current/cdl/ide_disk.cdl @@ -55,7 +55,7 @@ cdl_package CYGPKG_DEVS_DISK_IDE { compile -library=libextras.a ide_disk.c cdl_component CYGVAR_DEVS_DISK_IDE_DISK0 { - display "Provide disk 0 device" + display "Provide disk 0 device" flavor bool default_value 1 description "IDE chanel 0:0 disk driver" @@ -63,12 +63,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE { cdl_option CYGDAT_IO_DISK_IDE_DISK0_NAME { display "Device name for disk 0 device" flavor data - default_value {"\"/dev/hda/\""} + default_value {"\"/dev/idedisk0/\""} } } cdl_component CYGVAR_DEVS_DISK_IDE_DISK1 { - display "Provide disk 1 device" + display "Provide disk 1 device" flavor bool default_value 0 description "IDE chanel 0:1 disk driver" @@ -76,12 +76,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE { cdl_option CYGDAT_IO_DISK_IDE_DISK1_NAME { display "Device name for disk 1 device" flavor data - default_value {"\"/dev/hdb/\""} + default_value {"\"/dev/idedisk1/\""} } } cdl_component CYGVAR_DEVS_DISK_IDE_DISK2 { - display "Provide disk 2 device" + display "Provide disk 2 device" flavor bool default_value 0 description "IDE chanel 1:0 disk driver" @@ -89,12 +89,12 @@ cdl_package CYGPKG_DEVS_DISK_IDE { cdl_option CYGDAT_IO_DISK_IDE_DISK2_NAME { display "Device name for disk 2 device" flavor data - default_value {"\"/dev/hdc/\""} + default_value {"\"/dev/idedisk2/\""} } } cdl_component CYGVAR_DEVS_DISK_IDE_DISK3 { - display "Provide disk 3 device" + display "Provide disk 3 device" flavor bool default_value 0 description "IDE chanel 1:1 disk driver" @@ -102,7 +102,7 @@ cdl_package CYGPKG_DEVS_DISK_IDE { cdl_option CYGDAT_IO_DISK_IDE_DISK3_NAME { display "Device name for disk 3 device" flavor data - default_value {"\"/dev/hdd/\""} + default_value {"\"/dev/idedisk3/\""} } } @@ -112,7 +112,35 @@ cdl_package CYGPKG_DEVS_DISK_IDE { default_value 512 description " This option controls the disk sector size (default=512)" - } + } + + cdl_option CYGDAT_DEVS_DISK_IDE_STARTUP_DELAY { + display "Startup delay (in ms)" + flavor data + default_value 0 + description " + The amount of time (in ms) to wait for the IDE drives to + initialize on startup. For hard drives, this can usually + be set to zero, but for Compact Flash and other solid + state media this could be up to 500ms. If drives are not + detected at power-up, try increasing this value. + " + } + + cdl_option CYGDAT_DEVS_DISK_IDE_8_BIT_DATA_PATH { + display "8-bit data path" + flavor bool + default_value false + description " + This allows the host to communicate with the IDE drives using an + 8-bit data, rather than 16-bits. It does so by requesting a \"Set + Feature\" on the drive for the 8-bit path. Note that this may + be ignored by most modern disk drives, but is supported by Compact + Flash drives. This is only used by proprietary boards, and should + be disabled for standard IDE controllers. + " + } + cdl_option CYGSEM_DEVS_DISK_IDE_VMWARE { display "Work with VMware virtual disks" @@ -121,7 +149,6 @@ cdl_package CYGPKG_DEVS_DISK_IDE { description " This option controls the disk driver behaviour at ide-init" } - } # EOF ide_disk.cdl
--- 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;
