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, 2006 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 // No h/w controller structure is needed in this driver, but the address of the
78 // second argument is taken anyway.
79 DISK_CONTROLLER(ide_disk_controller, ide_disk_controller);
81 #ifdef CYGVAR_DEVS_DISK_IDE_DISK0
82 IDE_DISK_INSTANCE(0, 0, 0, true, CYGDAT_IO_DISK_IDE_DISK0_NAME);
85 #ifdef CYGVAR_DEVS_DISK_IDE_DISK1
86 IDE_DISK_INSTANCE(1, 0, 1, true, CYGDAT_IO_DISK_IDE_DISK1_NAME);
89 #ifdef CYGVAR_DEVS_DISK_IDE_DISK2
90 IDE_DISK_INSTANCE(2, 1, 0, true, CYGDAT_IO_DISK_IDE_DISK2_NAME);
93 #ifdef CYGVAR_DEVS_DISK_IDE_DISK3
94 IDE_DISK_INSTANCE(3, 1, 1, true, CYGDAT_IO_DISK_IDE_DISK3_NAME);
97 // ----------------------------------------------------------------------------
100 id_strcpy(char *dest, cyg_uint16 *src, cyg_uint16 size)
104 for (i = 0; i < size; i+=2)
106 *dest++ = (char)(*src >> 8);
107 *dest++ = (char)(*src & 0x00FF);
113 // ----------------------------------------------------------------------------
116 __wait_for_ready(int ctlr)
120 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
121 } while (status & (IDE_STAT_BSY | IDE_STAT_DRQ));
124 // Wait while the device is busy with the last command
126 __wait_busy(int ctlr)
131 for (tries=0; tries < 1000000; tries++) {
132 CYGACC_CALL_IF_DELAY_US(10);
133 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
134 if ((status & IDE_STAT_BSY) == 0)
141 __wait_for_drq(int ctlr)
146 for (tries=0; tries<1000000; tries++) {
147 CYGACC_CALL_IF_DELAY_US(10);
148 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
149 if (!(status & IDE_STAT_BSY)) {
150 if (status & IDE_STAT_DRQ)
159 // Return true if any devices attached to controller
161 ide_presence_detect(int ctlr)
166 for (i = 0; i < 2; i++) {
167 sel = (i << 4) | 0xA0;
168 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
169 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, sel);
170 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
171 HAL_IDE_READ_UINT8(ctlr, IDE_REG_DEVICE, val);
173 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
175 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, 0);
190 // VMware virtual IDE device handler obviously expects that
191 // the reset and setup functions were already done
192 // by it's bios and complains if one uses reset here...
194 #ifndef CYGSEM_DEVS_DISK_IDE_VMWARE
195 HAL_IDE_WRITE_CONTROL(ctlr, 6); // polled mode, reset asserted
196 CYGACC_CALL_IF_DELAY_US(5000);
197 HAL_IDE_WRITE_CONTROL(ctlr, 2); // polled mode, reset cleared
198 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
201 // wait 30 seconds max for not busy and drive ready
202 for (delay = 0; delay < 300; ++delay) {
203 CYGACC_CALL_IF_DELAY_US((cyg_uint32)100000);
204 HAL_IDE_READ_UINT8(ctlr, IDE_REG_STATUS, status);
205 if (!(status & IDE_STAT_BSY)) {
206 if (status & IDE_STAT_DRDY) {
215 ide_ident(int ctlr, int dev, cyg_uint16 *buf)
219 if (!__wait_busy(ctlr)) {
223 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE, dev << 4);
224 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0xEC);
225 CYGACC_CALL_IF_DELAY_US((cyg_uint32)50000);
227 if (!__wait_for_drq(ctlr)) {
231 for (i = 0; i < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
233 HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, *buf);
239 ide_read_sector(int ctlr, int dev, cyg_uint32 start,
240 cyg_uint8 *buf, cyg_uint32 len)
246 if(!__wait_busy(ctlr)) {
250 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1
251 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
252 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
253 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
254 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
255 ((start >> 24) & 0xf) | (dev << 4) | 0x40);
256 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x20);
258 if (!__wait_for_drq(ctlr))
261 // It would be fine if all buffers were word aligned,
264 for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
266 HAL_IDE_READ_UINT16(ctlr, IDE_REG_DATA, p);
267 if (c++<(len*512)) *b++=p&0xff;
268 if (c++<(len*512)) *b++=(p>>8)&0xff;
274 ide_write_sector(int ctlr, int dev, cyg_uint32 start,
275 cyg_uint8 *buf, cyg_uint32 len)
281 if(!__wait_busy(ctlr)) {
285 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COUNT, 1); // count =1
286 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBALOW, start & 0xff);
287 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAMID, (start >> 8) & 0xff);
288 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_LBAHI, (start >> 16) & 0xff);
289 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_DEVICE,
290 ((start >> 24) & 0xf) | (dev << 4) | 0x40);
291 HAL_IDE_WRITE_UINT8(ctlr, IDE_REG_COMMAND, 0x30);
293 if (!__wait_for_drq(ctlr))
296 // It would be fine if all buffers were word aligned,
299 for (j = 0, c=0 ; j < (CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE / sizeof(cyg_uint16));
301 p = (c++<(len*512)) ? *b++ : 0;
302 p |= (c++<(len*512)) ? (*b++<<8) : 0;
303 HAL_IDE_WRITE_UINT16(ctlr, IDE_REG_DATA, p);
308 // ----------------------------------------------------------------------------
311 ide_disk_init(struct cyg_devtab_entry *tab)
313 disk_channel *chan = (disk_channel *) tab->priv;
314 ide_disk_info_t *info = (ide_disk_info_t *) chan->dev_priv;
315 cyg_uint32 id_buf[CYGDAT_DEVS_DISK_IDE_SECTOR_SIZE/sizeof(cyg_uint32)];
316 static int num_controllers;
317 static int ide_present[4], ide_reset_done[4];
318 cyg_disk_identify_t ident;
319 ide_identify_data_t *ide_idData=(ide_identify_data_t*)id_buf;
324 D("IDE(%d:%d) hw init\n", info->port, info->chan);
326 if (!num_controllers) num_controllers=HAL_IDE_INIT();
327 if (info->chan>=num_controllers) {
328 D("No IDE controller for channel %d:%d\n", info->port, info->chan);
331 if (!ide_present[info->port]) {
332 ide_present[info->port]=ide_presence_detect(info->port);
333 if (!ide_present[info->port]) {
334 diag_printf("No devices on IDE controller #%d\n",info->port);
338 if (!ide_reset_done[info->port]) {
339 ide_reset_done[info->port]=ide_reset(info->port);
340 if (!ide_reset_done[info->port]) {
341 D("Controller #%d reset failure\n",info->port);
346 D("IDE %d:%d identify drive\n", info->port, info->chan);
348 if (!ide_ident(info->port, info->chan, (cyg_uint16 *)id_buf)) {
349 diag_printf("IDE %d:%d ident DRQ error\n", info->port, info->chan);
353 id_strcpy(ident.serial, ide_idData->serial, 20);
354 id_strcpy(ident.firmware_rev, ide_idData->firmware_rev, 8);
355 id_strcpy(ident.model_num, ide_idData->model_num, 40);
357 ident.cylinders_num = ide_idData->num_cylinders;
358 ident.heads_num = ide_idData->num_heads;
359 ident.sectors_num = ide_idData->num_sectors;
360 ident.lba_sectors_num = ide_idData->lba_total_sectors[1] << 16 |
361 ide_idData->lba_total_sectors[0];
362 ident.phys_block_size = 1;
363 ident.max_transfer = 512;
365 D("\tSerial : %s\n", ident.serial);
366 D("\tFirmware rev. : %s\n", ident.firmware_rev);
367 D("\tModel : %s\n", ident.model_num);
368 D("\tC/H/S : %d/%d/%d\n", ident.cylinders_num,
369 ident.heads_num, ident.sectors_num);
370 D("\tKind : %x\n", (ide_idData->general_conf>>8)&0x1f);
372 if (((ide_idData->general_conf>>8)&0x1f)!=2) {
373 diag_printf("IDE device %d:%d is not a hard disk!\n",
374 info->port, info->chan);
377 if (!(chan->callbacks->disk_init)(tab))
380 if (ENOERR != (chan->callbacks->disk_connected)(tab, &ident))
386 // ----------------------------------------------------------------------------
389 ide_disk_lookup(struct cyg_devtab_entry **tab,
390 struct cyg_devtab_entry *sub_tab,
393 disk_channel *chan = (disk_channel *) (*tab)->priv;
394 return (chan->callbacks->disk_lookup)(tab, sub_tab, name);
397 // ----------------------------------------------------------------------------
400 ide_disk_read(disk_channel *chan,
403 cyg_uint32 block_num)
405 ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
407 D("IDE %d:%d read block %d\n", info->port, info->chan, block_num);
409 if (!ide_read_sector(info->port, info->chan, block_num,
410 (cyg_uint8 *)buf, len)) {
411 diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
418 // ----------------------------------------------------------------------------
421 ide_disk_write(disk_channel *chan,
424 cyg_uint32 block_num)
426 ide_disk_info_t *info = (ide_disk_info_t *)chan->dev_priv;
428 D("IDE %d:%d write block %d\n", info->port, info->chan, block_num);
430 if (!ide_write_sector(info->port, info->chan, block_num,
431 (cyg_uint8 *)buf, len)) {
432 diag_printf("IDE %d:%d read DRQ error\n", info->port, info->chan);
439 // ----------------------------------------------------------------------------
442 ide_disk_get_config(disk_channel *chan,
450 // ----------------------------------------------------------------------------
453 ide_disk_set_config(disk_channel *chan,