1 //==========================================================================
5 // IDE polled mode disk driver
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Red Hat, Inc.
12 // Copyright (C) 2004 eCosCentric, Ltd.
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //==========================================================================
40 //#####DESCRIPTIONBEGIN####
46 //####DESCRIPTIONEND####
48 //==========================================================================
50 #include <pkgconf/devs_disk_ide.h>
52 #include <cyg/infra/cyg_type.h>
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/diag.h>
55 #include <cyg/hal/hal_arch.h>
56 #include <cyg/hal/hal_io.h>
57 #include <cyg/hal/hal_if.h> // delays
58 #include <cyg/hal/drv_api.h>
59 #include <cyg/io/io.h>
60 #include <cyg/io/devtab.h>
61 #include <cyg/io/disk.h>
65 // ----------------------------------------------------------------------------
70 # define D(fmt,args...) diag_printf(fmt, ## args)
72 # define D(fmt,args...)
75 // ----------------------------------------------------------------------------
77 #ifdef CYGVAR_DEVS_DISK_IDE_DISK0
78 IDE_DISK_INSTANCE(0, 0, 0, true, CYGDAT_IO_DISK_IDE_DISK0_NAME);
81 #ifdef CYGVAR_DEVS_DISK_IDE_DISK1
82 IDE_DISK_INSTANCE(1, 0, 1, true, CYGDAT_IO_DISK_IDE_DISK1_NAME);
85 #ifdef CYGVAR_DEVS_DISK_IDE_DISK2
86 IDE_DISK_INSTANCE(2, 1, 0, true, CYGDAT_IO_DISK_IDE_DISK2_NAME);
89 #ifdef CYGVAR_DEVS_DISK_IDE_DISK3
90 IDE_DISK_INSTANCE(3, 1, 1, true, CYGDAT_IO_DISK_IDE_DISK3_NAME);
93 // ----------------------------------------------------------------------------
96 id_strcpy(char *dest, cyg_uint16 *src, cyg_uint16 size)
100 for (i = 0; i < size; i+=2)
102 *dest++ = (char)(*src >> 8);
103 *dest++ = (char)(*src & 0x00FF);
109 // ----------------------------------------------------------------------------
112 __wait_for_ready(int ctlr)
116 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
117 } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
120 // Wait while the device is busy with the last command
122 __wait_busy(int ctlr)
127 for (tries=0; tries < 1000000; tries++) {
128 CYGACC_CALL_IF_DELAY_US(10);
129 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
130 if ((status & IDE_STAT_BSY) == 0)
137 __wait_for_drq(int ctlr)
142 for (tries=0; tries<1000000; tries++) {
143 CYGACC_CALL_IF_DELAY_US(10);
144 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
145 if (!(status & IDE_STAT_BSY)) {
146 if (status & IDE_STAT_DRQ)
155 // Return true if any devices attached to controller
157 ide_presence_detect(int ctlr)
162 for (i = 0; i < 2; i++) {
163 sel = (i << 4) | 0xA0;
164 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
165 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
166 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
167 HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
169 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
171 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, 0);
186 // VMware virtual IDE device handler obviously expects that
187 // the reset and setup functions were already done
188 // by it's bios and complains if one uses reset here...
190 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
191 HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted
192 CYGACC_CALL_IF_DELAY_US(5000);
193 HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared
194 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
197 // wait 30 seconds max for not busy and drive ready
198 for (delay = 0; delay < 300; ++delay) {
199 CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
200 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
201 if (!(status & IDE_STAT_BSY)) {
202 if (status & IDE_STAT_DRDY) {
211 ide_ident(int ctlr, int dev, cyg_uint16 *buf)
215 if (!__wait_busy(ctlr)) {
219 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
220 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEC);
221 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
223 if (!__wait_for_drq(ctlr)) {
227 for (i = 0; i < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
229 HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
235 ide_read_sector(int ctlr, int dev, cyg_uint32 start,
236 cyg_uint8 *buf, cyg_uint32 len)
242 if(!__wait_busy(ctlr)) {
246 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1
247 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
248 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
249 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
250 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
251 ((start >> 24) & 0xf) | (dev << 4) | 0x40);
252 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
254 if (!__wait_for_drq(ctlr))
257 // It would be fine if all buffers were word aligned,
260 for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
262 HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, p);
263 if (c++<len) *b++=p&0xff;
264 if (c++<len) *b++=(p>>8)&0xff;
270 ide_write_sector(int ctlr, int dev, cyg_uint32 start,
271 cyg_uint8 *buf, cyg_uint32 len)
277 if(!__wait_busy(ctlr)) {
281 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1
282 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
283 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
284 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
285 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
286 ((start >> 24) & 0xf) | (dev << 4) | 0x40);
287 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x30);
289 if (!__wait_for_drq(ctlr))
292 // It would be fine if all buffers were word aligned,
295 for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
297 p = (c++<len) ? *b++ : 0;
298 p |= (c++<len) ? (*b++<<8) : 0;
299 HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, p);
304 // ----------------------------------------------------------------------------
307 ide_disk_init(struct cyg_devtab_entry *tab)
309 disk_channel *chan = (disk_channel *) tab->priv;
310 ide_disk_info_t *info = (ide_disk_info_t *) chan->dev_priv;
311 cyg_uint32 id_buf[CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE/sizeof(cyg_uint32)];
312 static int num_controllers;
313 static int ide_present[4], ide_reset_done[4];
314 cyg_disk_identify_t ident;
315 ide_identify_data_t *ide_idData=(ide_identify_data_t*)id_buf;
320 D("IDE(%d:%d) hw init\n", info->port, info->chan);
322 if (!num_controllers) num_controllers=HAL_IDE_INIT();
323 if (info->chan>=num_controllers) {
324 D("No IDE controller for channel %d:%d\n", info->port, info->chan);
327 if (!ide_present[info->port]) {
328 ide_present[info->port]=ide_presence_detect(info->port);
329 if (!ide_present[info->port]) {
330 diag_printf("No devices on IDE controller #%d\n",info->port);
334 if (!ide_reset_done[info->port]) {
335 ide_reset_done[info->port]=ide_reset(info->port);
336 if (!ide_reset_done[info->port]) {
337 D("Controller #%d reset failure\n",info->port);
342 D("IDE %d:%d identify drive\n", info->port, info->chan);
344 if (!ide_ident(info->port, info->chan, (cyg_uint16 *)id_buf)) {
345 diag_printf("IDE %d:%d ident DRQ error\n", info->port, info->chan);
349 id_strcpy(ident.serial, ide_idData->serial, 20);
350 id_strcpy(ident.firmware_rev, ide_idData->firmware_rev, 8);
351 id_strcpy(ident.model_num, ide_idData->model_num, 40);
353 ident.cylinders_num = ide_idData->num_cylinders;
354 ident.heads_num = ide_idData->num_heads;
355 ident.sectors_num = ide_idData->num_sectors;
356 ident.lba_sectors_num = ide_idData->lba_total_sectors[1] << 16 |
357 ide_idData->lba_total_sectors[0];
359 D("\tSerial : %s\n", ident.serial);
360 D("\tFirmware rev. : %s\n", ident.firmware_rev);
361 D("\tModel : %s\n", ident.model_num);
362 D("\tC/H/S : %d/%d/%d\n", ident.cylinders_num,
363 ident.heads_num, ident.sectors_num);
364 D("\tKind : %x\n", (ide_idData->general_conf>>8)&0x1f);
366 if (((ide_idData->general_conf>>8)&0x1f)!=2) {
367 diag_printf("IDE device %d:%d is not a hard disk!\n",
368 info->port, info->chan);
371 if (!(chan->callbacks->disk_init)(tab))
374 if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
380 // ----------------------------------------------------------------------------
383 ide_disk_lookup(struct cyg_devtab_entry **tab,
384 struct cyg_devtab_entry *sub_tab,
387 disk_channel *chan = (disk_channel *) (*tab)->priv;
388 return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
391 // ----------------------------------------------------------------------------
394 ide_disk_read(disk_channel *chan,
397 cyg_uint32 block_num)
399 ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
401 D("IDE %d:%d read block %d\n", info->port, info->chan, block_num);
403 if (!ide_read_sector(info->port, info->chan, block_num,
404 (cyg_uint8 *)buf, len)) {
405 diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
412 // ----------------------------------------------------------------------------
415 ide_disk_write(disk_channel *chan,
418 cyg_uint32 block_num)
420 ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
422 D("IDE %d:%d write block %d\n", info->port, info->chan, block_num);
424 if (!ide_write_sector(info->port, info->chan, block_num,
425 (cyg_uint8 *)buf, len)) {
426 diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
433 // ----------------------------------------------------------------------------
436 ide_disk_get_config(disk_channel *chan,
444 // ----------------------------------------------------------------------------
447 ide_disk_set_config(disk_channel *chan,