Author: stepan
Date: 2009-03-11 04:07:08 +0100 (Wed, 11 Mar 2009)
New Revision: 86

Added:
   trunk/filo/drivers/hdreg.h
   trunk/filo/drivers/ide_new.c
   trunk/filo/drivers/ide_new.h
Modified:
   trunk/filo/Config.in
   trunk/filo/Makefile
   trunk/filo/drivers/Makefile.inc
   trunk/filo/drivers/ide.c
   trunk/filo/drivers/intel.c
   trunk/filo/fs/blockdev.c
   trunk/filo/include/fs.h
   trunk/filo/main/Makefile.inc
   trunk/filo/main/grub/builtins.c
Log:
* move openbios IDE driver over to filo. It works a lot more reliable than the
  old one. (Lacks PCI BAR reading though)
* some helper commands
* push version to 0.6.0 final


Modified: trunk/filo/Config.in
===================================================================
--- trunk/filo/Config.in        2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/Config.in        2009-03-11 03:07:08 UTC (rev 86)
@@ -118,15 +118,23 @@
          Use PCMCIA compact flash on Via Epia MII10000 and MII6000E
          This device is referred to as hde.
 
+config IDE_NEW_DISK
+       bool "New IDE driver"
+       default n
+       depends on !IDE_DISK
+       help
+         Jens Axboe's fine IDE driver
+
 config USB_NEW_DISK
-       bool "new USB Stack"
+       bool "USB Stack"
        default y
        help
          Driver for USB Storage
 
 config USB_DISK
-       bool "USB Stack (obsolete?)"
+       bool "Old USB Stack (obsolete?)"
        default n
+       depends on !USB_NEW_DISK
        help
          Driver for USB Storage
 

Modified: trunk/filo/Makefile
===================================================================
--- trunk/filo/Makefile 2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/Makefile 2009-03-11 03:07:08 UTC (rev 86)
@@ -17,7 +17,7 @@
 #
 
 export PROGRAM_NAME := FILO
-export PROGRAM_VERSION := 0.6.0rc1
+export PROGRAM_VERSION := 0.6.0
 
 export src := $(shell pwd)
 export srctree := $(src)

Modified: trunk/filo/drivers/Makefile.inc
===================================================================
--- trunk/filo/drivers/Makefile.inc     2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/Makefile.inc     2009-03-11 03:07:08 UTC (rev 86)
@@ -17,6 +17,7 @@
 #
 
 TARGETS-$(CONFIG_IDE_DISK) += drivers/ide.o
+TARGETS-$(CONFIG_IDE_NEW_DISK) += drivers/ide_new.o
 TARGETS-$(CONFIG_VIA_SOUND) += drivers/via-sound.o
 TARGETS-y += drivers/intel.o
 

Added: trunk/filo/drivers/hdreg.h
===================================================================
--- trunk/filo/drivers/hdreg.h                          (rev 0)
+++ trunk/filo/drivers/hdreg.h  2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,297 @@
+/*
+ * this header holds data structures as dictated by spec
+ */
+#ifndef HDREG_H
+#define HDREG_H
+#include <arch/types.h>
+//#include <misc.h>
+
+#define CONFIG_LITTLE_ENDIAN
+
+#define u8 uint8_t
+#define u16 uint16_t
+#define u32 uint32_t
+
+struct hd_driveid {
+       unsigned short  config;         /* lots of obsolete bit flags */
+       unsigned short  cyls;           /* Obsolete, "physical" cyls */
+       unsigned short  reserved2;      /* reserved (word 2) */
+       unsigned short  heads;          /* Obsolete, "physical" heads */
+       unsigned short  track_bytes;    /* unformatted bytes per track */
+       unsigned short  sector_bytes;   /* unformatted bytes per sector */
+       unsigned short  sectors;        /* Obsolete, "physical" sectors per 
track */
+       unsigned short  vendor0;        /* vendor unique */
+       unsigned short  vendor1;        /* vendor unique */
+       unsigned short  vendor2;        /* Retired vendor unique */
+       unsigned char   serial_no[20];  /* 0 = not_specified */
+       unsigned short  buf_type;       /* Retired */
+       unsigned short  buf_size;       /* Retired, 512 byte increments
+                                        * 0 = not_specified
+                                        */
+       unsigned short  ecc_bytes;      /* for r/w long cmds; 0 = not_specified 
*/
+       unsigned char   fw_rev[8];      /* 0 = not_specified */
+       unsigned char   model[40];      /* 0 = not_specified */
+       unsigned char   max_multsect;   /* 0=not_implemented */
+       unsigned char   vendor3;        /* vendor unique */
+       unsigned short  dword_io;       /* 0=not_implemented; 1=implemented */
+       unsigned char   vendor4;        /* vendor unique */
+       unsigned char   capability;     /* (upper byte of word 49)
+                                        *  3:  IORDYsup
+                                        *  2:  IORDYsw
+                                        *  1:  LBA
+                                        *  0:  DMA
+                                        */
+       unsigned short  reserved50;     /* reserved (word 50) */
+       unsigned char   vendor5;        /* Obsolete, vendor unique */
+       unsigned char   tPIO;           /* Obsolete, 0=slow, 1=medium, 2=fast */
+       unsigned char   vendor6;        /* Obsolete, vendor unique */
+       unsigned char   tDMA;           /* Obsolete, 0=slow, 1=medium, 2=fast */
+       unsigned short  field_valid;    /* (word 53)
+                                        *  2:  ultra_ok        word  88
+                                        *  1:  eide_ok         words 64-70
+                                        *  0:  cur_ok          words 54-58
+                                        */
+       unsigned short  cur_cyls;       /* Obsolete, logical cylinders */
+       unsigned short  cur_heads;      /* Obsolete, l heads */
+       unsigned short  cur_sectors;    /* Obsolete, l sectors per track */
+       unsigned short  cur_capacity0;  /* Obsolete, l total sectors on drive */
+       unsigned short  cur_capacity1;  /* Obsolete, (2 words, misaligned int)  
   */
+       unsigned char   multsect;       /* current multiple sector count */
+       unsigned char   multsect_valid; /* when (bit0==1) multsect is ok */
+       unsigned int    lba_capacity;   /* Obsolete, total number of sectors */
+       unsigned short  dma_1word;      /* Obsolete, single-word dma info */
+       unsigned short  dma_mword;      /* multiple-word dma info */
+       unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
+       unsigned short  eide_dma_min;   /* min mword dma cycle time (ns) */
+       unsigned short  eide_dma_time;  /* recommended mword dma cycle time 
(ns) */
+       unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
+       unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
+       unsigned short  words69_70[2];  /* reserved words 69-70
+                                        * future command overlap and queuing
+                                        */
+       /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */
+       unsigned short  words71_74[4];  /* reserved words 71-74
+                                        * for IDENTIFY PACKET DEVICE command
+                                        */
+       unsigned short  queue_depth;    /* (word 75)
+                                        * 15:5 reserved
+                                        *  4:0 Maximum queue depth -1
+                                        */
+       unsigned short  words76_79[4];  /* reserved words 76-79 */
+       unsigned short  major_rev_num;  /* (word 80) */
+       unsigned short  minor_rev_num;  /* (word 81) */
+       unsigned short  command_set_1;  /* (word 82) supported
+                                        * 15:  Obsolete
+                                        * 14:  NOP command
+                                        * 13:  READ_BUFFER
+                                        * 12:  WRITE_BUFFER
+                                        * 11:  Obsolete
+                                        * 10:  Host Protected Area
+                                        *  9:  DEVICE Reset
+                                        *  8:  SERVICE Interrupt
+                                        *  7:  Release Interrupt
+                                        *  6:  look-ahead
+                                        *  5:  write cache
+                                        *  4:  PACKET Command
+                                        *  3:  Power Management Feature Set
+                                        *  2:  Removable Feature Set
+                                        *  1:  Security Feature Set
+                                        *  0:  SMART Feature Set
+                                        */
+       unsigned short  command_set_2;  /* (word 83)
+                                        * 15:  Shall be ZERO
+                                        * 14:  Shall be ONE
+                                        * 13:  FLUSH CACHE EXT
+                                        * 12:  FLUSH CACHE
+                                        * 11:  Device Configuration Overlay
+                                        * 10:  48-bit Address Feature Set
+                                        *  9:  Automatic Acoustic Management
+                                        *  8:  SET MAX security
+                                        *  7:  reserved 1407DT PARTIES
+                                        *  6:  SetF sub-command Power-Up
+                                        *  5:  Power-Up in Standby Feature Set
+                                        *  4:  Removable Media Notification
+                                        *  3:  APM Feature Set
+                                        *  2:  CFA Feature Set
+                                        *  1:  READ/WRITE DMA QUEUED
+                                        *  0:  Download MicroCode
+                                        */
+       unsigned short  cfsse;          /* (word 84)
+                                        * cmd set-feature supported extensions
+                                        * 15:  Shall be ZERO
+                                        * 14:  Shall be ONE
+                                        * 13:6 reserved
+                                        *  5:  General Purpose Logging
+                                        *  4:  Streaming Feature Set
+                                        *  3:  Media Card Pass Through
+                                        *  2:  Media Serial Number Valid
+                                        *  1:  SMART selt-test supported
+                                        *  0:  SMART error logging
+                                        */
+       unsigned short  cfs_enable_1;   /* (word 85)
+                                        * command set-feature enabled
+                                        * 15:  Obsolete
+                                        * 14:  NOP command
+                                        * 13:  READ_BUFFER
+                                        * 12:  WRITE_BUFFER
+                                        * 11:  Obsolete
+                                        * 10:  Host Protected Area
+                                        *  9:  DEVICE Reset
+                                        *  8:  SERVICE Interrupt
+                                        *  7:  Release Interrupt
+                                        *  6:  look-ahead
+                                        *  5:  write cache
+                                        *  4:  PACKET Command
+                                        *  3:  Power Management Feature Set
+                                        *  2:  Removable Feature Set
+                                        *  1:  Security Feature Set
+                                        *  0:  SMART Feature Set
+                                        */
+       unsigned short  cfs_enable_2;   /* (word 86)
+                                        * command set-feature enabled
+                                        * 15:  Shall be ZERO
+                                        * 14:  Shall be ONE
+                                        * 13:  FLUSH CACHE EXT
+                                        * 12:  FLUSH CACHE
+                                        * 11:  Device Configuration Overlay
+                                        * 10:  48-bit Address Feature Set
+                                        *  9:  Automatic Acoustic Management
+                                        *  8:  SET MAX security
+                                        *  7:  reserved 1407DT PARTIES
+                                        *  6:  SetF sub-command Power-Up
+                                        *  5:  Power-Up in Standby Feature Set
+                                        *  4:  Removable Media Notification
+                                        *  3:  APM Feature Set
+                                        *  2:  CFA Feature Set
+                                        *  1:  READ/WRITE DMA QUEUED
+                                        *  0:  Download MicroCode
+                                        */
+       unsigned short  csf_default;    /* (word 87)
+                                        * command set-feature default
+                                        * 15:  Shall be ZERO
+                                        * 14:  Shall be ONE
+                                        * 13:6 reserved
+                                        *  5:  General Purpose Logging enabled
+                                        *  4:  Valid CONFIGURE STREAM executed
+                                        *  3:  Media Card Pass Through enabled
+                                        *  2:  Media Serial Number Valid
+                                        *  1:  SMART selt-test supported
+                                        *  0:  SMART error logging
+                                        */
+       unsigned short  dma_ultra;      /* (word 88) */
+       unsigned short  trseuc;         /* time required for security erase */
+       unsigned short  trsEuc;         /* time required for enhanced erase */
+       unsigned short  CurAPMvalues;   /* current APM values */
+       unsigned short  mprc;           /* master password revision code */
+       unsigned short  hw_config;      /* hardware config (word 93)
+                                        * 15:  Shall be ZERO
+                                        * 14:  Shall be ONE
+                                        * 13:
+                                        * 12:
+                                        * 11:
+                                        * 10:
+                                        *  9:
+                                        *  8:
+                                        *  7:
+                                        *  6:
+                                        *  5:
+                                        *  4:
+                                        *  3:
+                                        *  2:
+                                        *  1:
+                                        *  0:  Shall be ONE
+                                        */
+       unsigned short  acoustic;       /* (word 94)
+                                        * 15:8 Vendor's recommended value
+                                        *  7:0 current value
+                                        */
+       unsigned short  msrqs;          /* min stream request size */
+       unsigned short  sxfert;         /* stream transfer time */
+       unsigned short  sal;            /* stream access latency */
+       unsigned int    spg;            /* stream performance granularity */
+       unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
+       unsigned short  words104_125[22];/* reserved words 104-125 */
+       unsigned short  last_lun;       /* (word 126) */
+       unsigned short  word127;        /* (word 127) Feature Set
+                                        * Removable Media Notification
+                                        * 15:2 reserved
+                                        *  1:0 00 = not supported
+                                        *      01 = supported
+                                        *      10 = reserved
+                                        *      11 = reserved
+                                        */
+       unsigned short  dlf;            /* (word 128)
+                                        * device lock function
+                                        * 15:9 reserved
+                                        *  8   security level 1:max 0:high
+                                        *  7:6 reserved
+                                        *  5   enhanced erase
+                                        *  4   expire
+                                        *  3   frozen
+                                        *  2   locked
+                                        *  1   en/disabled
+                                        *  0   capability
+                                        */
+       unsigned short  csfo;           /*  (word 129)
+                                        * current set features options
+                                        * 15:4 reserved
+                                        *  3:  auto reassign
+                                        *  2:  reverting
+                                        *  1:  read-look-ahead
+                                        *  0:  write cache
+                                        */
+       unsigned short  words130_155[26];/* reserved vendor words 130-155 */
+       unsigned short  word156;        /* reserved vendor word 156 */
+       unsigned short  words157_159[3];/* reserved vendor words 157-159 */
+       unsigned short  cfa_power;      /* (word 160) CFA Power Mode
+                                        * 15 word 160 supported
+                                        * 14 reserved
+                                        * 13
+                                        * 12
+                                        * 11:0
+                                        */
+       unsigned short  words161_175[15];/* Reserved for CFA */
+       unsigned short  words176_205[30];/* Current Media Serial Number */
+       unsigned short  words206_254[49];/* reserved words 206-254 */
+       unsigned short  integrity_word; /* (word 255)
+                                        * 15:8 Checksum
+                                        *  7:0 Signature
+                                        */
+};
+
+struct request_sense {
+#if defined(CONFIG_BIG_ENDIAN)
+       u8 valid                : 1;
+       u8 error_code           : 7;
+#elif defined(CONFIG_LITTLE_ENDIAN)
+       u8 error_code           : 7;
+       u8 valid                : 1;
+#endif
+       u8 segment_number;
+#if defined(CONFIG_BIG_ENDIAN)
+       u8 reserved1            : 2;
+       u8 ili                  : 1;
+       u8 reserved2            : 1;
+       u8 sense_key            : 4;
+#elif defined(CONFIG_LITTLE_ENDIAN)
+       u8 sense_key            : 4;
+       u8 reserved2            : 1;
+       u8 ili                  : 1;
+       u8 reserved1            : 2;
+#endif
+       u8 information[4];
+       u8 add_sense_len;
+       u8 command_info[4];
+       u8 asc;
+       u8 ascq;
+       u8 fruc;
+       u8 sks[3];
+       u8 asb[46];
+};
+
+struct atapi_capacity {
+       u32 lba;
+       u32 block_size;
+};
+
+#endif

Modified: trunk/filo/drivers/ide.c
===================================================================
--- trunk/filo/drivers/ide.c    2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/ide.c    2009-03-11 03:07:08 UTC (rev 86)
@@ -1132,6 +1132,11 @@
                        if (hdr == HEADER_TYPE_BRIDGE || hdr == 
HEADER_TYPE_CARDBUS) {
                                unsigned int new_bus;
                                new_bus = (pci_read_config32(currdev, 
REG_PRIMARY_BUS) >> 8) & 0xff;
+                               if (new_bus == 0) {
+                                       debug("Misconfigured bridge at 
%02x:%02x.%02x skipped.\n",
+                                               bus, slot, func);
+                                       continue;
+                               }
                                if (pci_find_ata_device_on_bus(new_bus, dev, 
index, sata, pata))
                                        return 1;
                        }

Added: trunk/filo/drivers/ide_new.c
===================================================================
--- trunk/filo/drivers/ide_new.c                                (rev 0)
+++ trunk/filo/drivers/ide_new.c        2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,1302 @@
+/*
+ *   OpenBIOS polled ide driver
+ *   
+ *   Copyright (C) 2004 Jens Axboe <[email protected]>
+ *   Copyright (C) 2005 Stefan Reinauer <[email protected]>
+ *
+ *   Credit goes to Hale Landis for his excellent ata demo software
+ *   OF node handling and some fixes by Stefan Reinauer
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   version 2
+ *
+ */
+
+/*
+ * TODO:
+ *  - Really probe for interfaces, don't just rely on legacy
+ */
+
+#define GRUB
+
+#include <libpayload.h>
+#include <config.h>
+#include <arch/byteorder.h>
+
+#include <fs.h>
+#include <debug.h>
+#include "ide_new.h"
+#include "hdreg.h"
+
+#if 0
+#define dprintf printf
+#else
+#define dprintf(x...) 
+#endif
+
+/*
+ * define to 2 for the standard 2 channels only
+ */
+#ifndef CONFIG_IDE_NUM_CHANNELS
+#define IDE_NUM_CHANNELS 4
+#else
+#define IDE_NUM_CHANNELS CONFIG_IDE_NUM_CHANNELS
+#endif
+#define IDE_MAX_CHANNELS 4
+
+static struct ide_channel ob_ide_channels[IDE_MAX_CHANNELS];
+
+/*
+ * FIXME: probe, we just hardwire legacy ports for now
+ */
+static const int io_ports[IDE_MAX_CHANNELS] = { 0x1f0, 0x170, 0x1e8, 0x168 };
+static const int ctl_ports[IDE_MAX_CHANNELS] = { 0x3f6, 0x376, 0x3ee, 0x36e };
+
+/*
+ * don't be pedantic
+ */
+#undef ATA_PEDANTIC
+
+static void dump_drive(struct ide_drive *drive)
+{
+#ifdef CONFIG_DEBUG_IDE
+       printk("IDE DRIVE @%lx:\n", (unsigned long)drive);
+       printk("unit: %d\n",drive->unit);
+       printk("present: %d\n",drive->present);
+       printk("type: %d\n",drive->type);
+       printk("media: %d\n",drive->media);
+       printk("model: %s\n",drive->model);
+       printk("nr: %d\n",drive->nr);
+       printk("cyl: %d\n",drive->cyl);
+       printk("head: %d\n",drive->head);
+       printk("sect: %d\n",drive->sect);
+       printk("bs: %d\n",drive->bs);
+#endif
+}
+
+/*
+ * old style io port operations
+ */
+static unsigned char
+ob_ide_inb(unsigned long port)
+{
+       return inb(port);
+}
+
+static void
+ob_ide_outb(unsigned char data, unsigned long port)
+{
+       outb(data, port);
+}
+
+static void
+ob_ide_insw(unsigned long port, unsigned char *addr, unsigned int count)
+{
+       insw(port, addr, count);
+}
+
+static void
+ob_ide_outsw(unsigned long port, unsigned char *addr, unsigned int count)
+{
+       outsw(port, addr, count);
+}
+
+static inline unsigned char
+ob_ide_pio_readb(struct ide_drive *drive, unsigned int offset)
+{
+       struct ide_channel *chan = drive->channel;
+
+       return chan->obide_inb(chan->io_regs[offset]);
+}
+
+static inline void
+ob_ide_pio_writeb(struct ide_drive *drive, unsigned int offset,
+                 unsigned char data)
+{
+       struct ide_channel *chan = drive->channel;
+
+       chan->obide_outb(data, chan->io_regs[offset]);
+}
+
+static inline void
+ob_ide_pio_insw(struct ide_drive *drive, unsigned int offset,
+               unsigned char *addr, unsigned int len)
+{
+       struct ide_channel *chan = drive->channel;
+
+       if (len & 1) {
+               printf("%d: command not word aligned\n", drive->nr);
+               return;
+       }
+
+       chan->obide_insw(chan->io_regs[offset], addr, len / 2);
+}
+
+static inline void
+ob_ide_pio_outsw(struct ide_drive *drive, unsigned int offset,
+               unsigned char *addr, unsigned int len)
+{
+       struct ide_channel *chan = drive->channel;
+
+       if (len & 1) {
+               printf("%d: command not word aligned\n", drive->nr);
+               return;
+       }
+
+       chan->obide_outsw(chan->io_regs[offset], addr, len / 2);
+}
+
+static void
+ob_ide_400ns_delay(struct ide_drive *drive)
+{
+       (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+       (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+       (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+       (void) ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+
+       udelay(1);
+}
+
+static void
+ob_ide_error(struct ide_drive *drive, unsigned char stat, char *msg)
+{
+       struct ide_channel *chan = drive->channel;
+       unsigned char err;
+
+       if (!stat)
+               stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+
+       printf("ob_ide_error drive<%d>: %s:\n", drive->nr, msg);
+       printf("    cmd=%x, stat=%x", chan->ata_cmd.command, stat);
+
+       if ((stat & (BUSY_STAT | ERR_STAT)) == ERR_STAT) {
+               err = ob_ide_pio_readb(drive, IDEREG_ERROR);
+               printf(", err=%x", err);
+       }
+       printf("\n");
+
+       /*
+        * see if sense is valid and dump that
+        */
+       if (chan->ata_cmd.command == WIN_PACKET) {
+               struct atapi_command *cmd = &chan->atapi_cmd;
+               unsigned char old_cdb = cmd->cdb[0];
+
+               if (cmd->cdb[0] == ATAPI_REQ_SENSE) {
+                       old_cdb = cmd->old_cdb;
+
+                       printf("    atapi opcode=%02x", old_cdb);
+               } else {
+                       int i;
+
+                       printf("    cdb: ");
+                       for (i = 0; i < sizeof(cmd->cdb); i++)
+                               printf("%02x ", cmd->cdb[i]);
+               }
+               if (cmd->sense_valid)
+                       printf(", sense: %02x/%02x/%02x", cmd->sense.sense_key, 
cmd->sense.asc, cmd->sense.ascq);
+               else
+                       printf(", no sense");
+               printf("\n");
+       }
+}
+
+/*
+ * wait for 'stat' to be set. returns 1 if failed, 0 if succesful
+ */
+static int
+ob_ide_wait_stat(struct ide_drive *drive, unsigned char ok_stat,
+                unsigned char bad_stat, unsigned char *ret_stat)
+{
+       unsigned char stat;
+       int i;
+
+       ob_ide_400ns_delay(drive);
+
+       for (i = 0; i < 5000; i++) {
+               stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+               if (!(stat & BUSY_STAT))
+                       break;
+
+               udelay(1000);
+       }
+
+       if (ret_stat)
+               *ret_stat = stat;
+
+       if (stat & bad_stat)
+               return 1;
+
+       if ((stat & ok_stat) || !ok_stat)
+               return 0;
+
+       return 1;
+}
+
+static int
+ob_ide_select_drive(struct ide_drive *drive)
+{
+       struct ide_channel *chan = drive->channel;
+       unsigned char control = IDEHEAD_DEV0;
+
+       if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) {
+               printf("select_drive: timed out\n");
+               return 1;
+       }
+
+       /*
+        * don't select drive if already active. Note: we always
+        * wait for BUSY clear
+        */
+       if (drive->unit == chan->selected)
+               return 0;
+
+       if (drive->unit)
+               control = IDEHEAD_DEV1;
+
+       ob_ide_pio_writeb(drive, IDEREG_CURRENT, control);
+       ob_ide_400ns_delay(drive);
+
+       if (ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL)) {
+               printf("select_drive: timed out\n");
+               return 1;
+       }
+
+       chan->selected = drive->unit;
+       return 0;
+}
+
+static void
+ob_ide_write_tasklet(struct ide_drive *drive, struct ata_command *cmd)
+{
+       ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[1]);
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[3]);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[7]);
+       ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[8]);
+       ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[9]);
+
+       ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->task[0]);
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->task[2]);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->task[4]);
+       ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->task[5]);
+       ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->task[6]);
+
+       if (drive->unit)
+               cmd->device_head |= IDEHEAD_DEV1;
+
+       ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head);
+
+       ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command);
+       ob_ide_400ns_delay(drive);
+}
+
+static void
+ob_ide_write_registers(struct ide_drive *drive, struct ata_command *cmd)
+{
+       /*
+        * we are _always_ polled
+        */
+       ob_ide_pio_writeb(drive, IDEREG_CONTROL, cmd->control | IDECON_NIEN);
+
+       ob_ide_pio_writeb(drive, IDEREG_FEATURE, cmd->feature);
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, cmd->nsector);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, cmd->sector);
+       ob_ide_pio_writeb(drive, IDEREG_LCYL, cmd->lcyl);
+       ob_ide_pio_writeb(drive, IDEREG_HCYL, cmd->hcyl);
+
+       if (drive->unit)
+               cmd->device_head |= IDEHEAD_DEV1;
+
+       ob_ide_pio_writeb(drive, IDEREG_CURRENT, cmd->device_head);
+
+       ob_ide_pio_writeb(drive, IDEREG_COMMAND, cmd->command);
+       ob_ide_400ns_delay(drive);
+}
+
+/*
+ * execute given command with a pio data-in phase.
+ */
+static int
+ob_ide_pio_data_in(struct ide_drive *drive, struct ata_command *cmd)
+{
+       unsigned char stat;
+       unsigned int bytes, timeout;
+
+       if (ob_ide_select_drive(drive))
+               return 1;
+
+       /*
+        * ATA must set ready and seek stat, ATAPI need only clear busy
+        */
+       timeout = 0;
+       do {
+               stat = ob_ide_pio_readb(drive, IDEREG_STATUS);
+
+               if (drive->type == ide_type_ata) {
+                       /*
+                        * this is BIOS code, don't be too pedantic
+                        */
+#ifdef ATA_PEDANTIC
+                       if ((stat & (BUSY_STAT | READY_STAT | SEEK_STAT)) ==
+                           (READY_STAT | SEEK_STAT))
+                               break;
+#else
+                       if ((stat & (BUSY_STAT | READY_STAT)) == READY_STAT)
+                               break;
+#endif
+               } else {
+                       if (!(stat & BUSY_STAT))
+                               break;
+               }
+               ob_ide_400ns_delay(drive);
+       } while (timeout++ < 1000);
+
+       if (timeout >= 1000) {
+               ob_ide_error(drive, stat, "drive timed out");
+               cmd->stat = stat;
+               return 1;
+       }
+                               
+       ob_ide_write_registers(drive, cmd);
+
+       /*
+        * now read the data
+        */
+       bytes = cmd->buflen;
+       do {
+               unsigned count = cmd->buflen;
+
+               if (count > drive->bs)
+                       count = drive->bs;
+
+               /* delay 100ms for ATAPI? */
+
+               /*
+                * wait for BUSY clear
+                */
+               if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+                       ob_ide_error(drive, stat, "timed out waiting for BUSY 
clear");
+                       cmd->stat = stat;
+                       break;
+               }
+
+               /*
+                * transfer the data
+                */
+               if ((stat & (BUSY_STAT | DRQ_STAT)) == DRQ_STAT) {
+                       ob_ide_pio_insw(drive, IDEREG_DATA, cmd->buffer, count);
+                       cmd->bytes -= count;
+                       cmd->buffer += count;
+                       bytes -= count;
+
+                       ob_ide_400ns_delay(drive);
+               }
+
+               if (stat & (BUSY_STAT | WRERR_STAT | ERR_STAT)) {
+                       cmd->stat = stat;
+                       break;
+               }
+
+               if (!(stat & DRQ_STAT)) {
+                       cmd->stat = stat;
+                       break;
+               }
+       } while (bytes);
+
+       if (bytes)
+               printf("bytes=%d, stat=%x\n", bytes, stat);
+
+       return bytes ? 1 : 0;
+}
+
+/*
+ * execute ata command with pio packet protocol
+ */
+static int
+ob_ide_pio_packet(struct ide_drive *drive, struct atapi_command *cmd)
+{
+       unsigned char stat, reason, lcyl, hcyl;
+       struct ata_command *acmd = &drive->channel->ata_cmd;
+       unsigned char *buffer;
+       unsigned int bytes;
+
+       if (ob_ide_select_drive(drive))
+               return 1;
+
+       if (cmd->buflen && cmd->data_direction == atapi_ddir_none)
+               printf("non-zero buflen but no data direction\n");
+
+       memset(acmd, 0, sizeof(*acmd));
+       acmd->lcyl = cmd->buflen & 0xff;
+       acmd->hcyl = (cmd->buflen >> 8) & 0xff;
+       acmd->command = WIN_PACKET;
+       ob_ide_write_registers(drive, acmd);
+
+       /*
+        * BUSY must be set, _or_ DRQ | ERR
+        */
+       stat = ob_ide_pio_readb(drive, IDEREG_ASTATUS);
+       if ((stat & BUSY_STAT) == 0) {
+               if (!(stat & (DRQ_STAT | ERR_STAT))) {
+                       ob_ide_error(drive, stat, "bad stat in atapi cmd");
+                       cmd->stat = stat;
+                       return 1;
+               }
+       }
+
+       if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+               ob_ide_error(drive, stat, "timeout, ATAPI BUSY clear");
+               cmd->stat = stat;
+               return 1;
+       }
+
+       if ((stat & (BUSY_STAT | DRQ_STAT | ERR_STAT)) != DRQ_STAT) {
+               /*
+                * if command isn't request sense, then we have a problem. if
+                * we are doing a sense, ERR_STAT == CHECK_CONDITION
+                */
+               if (cmd->cdb[0] != ATAPI_REQ_SENSE) {
+                       printf("odd, drive didn't want to transfer %x\n", stat);
+                       return 1;
+               }
+       }
+
+       /*
+        * transfer cdb
+        */
+       ob_ide_pio_outsw(drive, IDEREG_DATA, cmd->cdb,sizeof(cmd->cdb));
+       ob_ide_400ns_delay(drive);
+
+       /*
+        * ok, cdb was sent to drive, now do data transfer (if any)
+        */
+       bytes = cmd->buflen;
+       buffer = cmd->buffer;
+       do {
+               unsigned int bc;
+
+               if (ob_ide_wait_stat(drive, 0, BUSY_STAT | ERR_STAT, &stat)) {
+                       ob_ide_error(drive, stat, "busy not clear after cdb");
+                       cmd->stat = stat;
+                       break;
+               }
+
+               /*
+                * transfer complete!
+                */
+               if ((stat & (BUSY_STAT | DRQ_STAT)) == 0)
+                       break;
+
+               if ((stat & (BUSY_STAT | DRQ_STAT)) != DRQ_STAT)
+                       break;
+
+               reason = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+               lcyl = ob_ide_pio_readb(drive, IDEREG_LCYL);
+               hcyl = ob_ide_pio_readb(drive, IDEREG_HCYL);
+
+               /*
+                * check if the drive wants to transfer data in the same
+                * direction as we do...
+                */
+               if ((reason & IREASON_CD) && cmd->data_direction != 
atapi_ddir_read) {
+                       ob_ide_error(drive, stat, "atapi, bad transfer ddir");
+                       break;
+               }
+
+               bc = (hcyl << 8) | lcyl;
+               if (!bc)
+                       break;
+
+               if (bc > bytes)
+                       bc = bytes;
+
+               if (cmd->data_direction == atapi_ddir_read)
+                       ob_ide_pio_insw(drive, IDEREG_DATA, buffer, bc);
+               else
+                       ob_ide_pio_outsw(drive, IDEREG_DATA, buffer, bc);
+
+               bytes -= bc;
+               buffer += bc;
+
+               ob_ide_400ns_delay(drive);
+       } while (bytes);
+
+       if (cmd->data_direction != atapi_ddir_none)
+               (void) ob_ide_wait_stat(drive, 0, BUSY_STAT, &stat);
+
+       if (bytes)
+               printf("cdb failed, bytes=%d, stat=%x\n", bytes, stat);
+
+       return (stat & ERR_STAT) || bytes;
+}
+
+/*
+ * execute a packet command, with retries if appropriate
+ */
+static int
+ob_ide_atapi_packet(struct ide_drive *drive, struct atapi_command *cmd)
+{
+       int retries = 5, ret;
+
+       if (drive->type != ide_type_atapi)
+               return 1;
+       if (cmd->buflen > 0xffff)
+               return 1;
+
+       /*
+        * retry loop
+        */
+       do {
+               ret = ob_ide_pio_packet(drive, cmd);
+               if (!ret)
+                       break;
+
+               /*
+                * request sense failed, bummer
+                */
+               if (cmd->cdb[0] == ATAPI_REQ_SENSE)
+                       break;
+
+               if (ob_ide_atapi_request_sense(drive))
+                       break;
+
+               /*
+                * we know sense is valid. retry if the drive isn't ready,
+                * otherwise don't bother.
+                */
+               if (cmd->sense.sense_key != ATAPI_SENSE_NOT_READY)
+                       break;
+               /*
+                * ... except 'medium not present'
+                */
+               if (cmd->sense.asc == 0x3a)
+                       break;
+
+               udelay(1000000);
+       } while (retries--);
+
+       if (ret)
+               ob_ide_error(drive, 0, "atapi command");
+
+       return ret;
+}
+
+static int
+ob_ide_atapi_request_sense(struct ide_drive *drive)
+{
+       struct atapi_command *cmd = &drive->channel->atapi_cmd;
+       unsigned char old_cdb;
+
+       /*
+        * save old cdb for debug error
+        */
+       old_cdb = cmd->cdb[0];
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->cdb[0] = ATAPI_REQ_SENSE;
+       cmd->cdb[4] = 18;
+       cmd->buffer = (unsigned char *) &cmd->sense;
+       cmd->buflen = 18;
+       cmd->data_direction = atapi_ddir_read;
+       cmd->old_cdb = old_cdb;
+
+       if (ob_ide_atapi_packet(drive, cmd))
+               return 1;
+
+       cmd->sense_valid = 1;
+       return 0;
+}
+
+/*
+ * make sure drive is ready and media loaded
+ */
+static int
+ob_ide_atapi_drive_ready(struct ide_drive *drive)
+{
+       struct atapi_command *cmd = &drive->channel->atapi_cmd;
+       struct atapi_capacity cap;
+
+       /*
+        * Test Unit Ready is like a ping
+        */
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->cdb[0] = ATAPI_TUR;
+
+       if (ob_ide_atapi_packet(drive, cmd)) {
+               printf("%d: TUR failed\n", drive->nr);
+               return 1;
+       }
+
+       /*
+        * don't force load of tray (bit 2 in byte 4 of cdb), it's
+        * annoying and we don't want to deal with errors from drives
+        * that cannot do it
+        */
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->cdb[0] = ATAPI_START_STOP_UNIT;
+       cmd->cdb[4] = 0x01;
+
+       if (ob_ide_atapi_packet(drive, cmd)) {
+               printf("%d: START_STOP unit failed\n", drive->nr);
+               return 1;
+       }
+
+       /*
+        * finally, get capacity and block size
+        */
+       memset(cmd, 0, sizeof(*cmd));
+       memset(&cap, 0, sizeof(cap));
+
+       cmd->cdb[0] = ATAPI_READ_CAPACITY;
+       cmd->buffer = (unsigned char *) &cap;
+       cmd->buflen = sizeof(cap);
+       cmd->data_direction = atapi_ddir_read;
+
+       if (ob_ide_atapi_packet(drive, cmd)) {
+               drive->sectors = 0x1fffff;
+               drive->bs = 2048;
+               return 1;
+       }
+
+       drive->sectors = __be32_to_cpu(cap.lba) + 1;
+       drive->bs = __be32_to_cpu(cap.block_size);
+       return 0;
+}
+
+/*
+ * read from an atapi device, using READ_10
+ */
+static int
+ob_ide_read_atapi(struct ide_drive *drive, unsigned long long block, char *buf,
+                 unsigned int sectors)
+{
+       struct atapi_command *cmd = &drive->channel->atapi_cmd;
+
+       if (ob_ide_atapi_drive_ready(drive))
+               return 1;
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       /*
+        * READ_10 should work on generally any atapi device
+        */
+       cmd->cdb[0] = ATAPI_READ_10;
+       cmd->cdb[2] = (block >> 24) & 0xff;
+       cmd->cdb[3] = (block >> 16) & 0xff;
+       cmd->cdb[4] = (block >>  8) & 0xff;
+       cmd->cdb[5] = block & 0xff;
+       cmd->cdb[7] = (sectors >> 8) & 0xff;
+       cmd->cdb[8] = sectors & 0xff;
+
+       cmd->buffer = buf;
+       cmd->buflen = sectors * 2048;
+       cmd->data_direction = atapi_ddir_read;
+
+       return ob_ide_atapi_packet(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_chs(struct ide_drive *drive, unsigned long long block,
+                   char *buf, unsigned int sectors)
+{
+       struct ata_command *cmd = &drive->channel->ata_cmd;
+       unsigned int track = (block / drive->sect);
+       unsigned int sect = (block % drive->sect) + 1;
+       unsigned int head = (track % drive->head);
+       unsigned int cyl = (track / drive->head);
+       struct ata_sector ata_sector;
+
+       /*
+        * fill in chs command to read from disk at given location
+        */
+       cmd->buffer = buf;
+       cmd->buflen = sectors * 512;
+
+       ata_sector.all = sectors;
+       cmd->nsector = ata_sector.low;
+       cmd->sector = sect;
+       cmd->lcyl = cyl;
+       cmd->hcyl = cyl >> 8;
+       cmd->device_head = head;
+
+       cmd->command = WIN_READ;
+
+       return ob_ide_pio_data_in(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_lba28(struct ide_drive *drive, unsigned long long block,
+                     char *buf, unsigned int sectors)
+{
+       struct ata_command *cmd = &drive->channel->ata_cmd;
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       /*
+        * fill in 28-bit lba command to read from disk at given location
+        */
+       cmd->buffer = buf;
+       cmd->buflen = sectors * 512;
+
+       cmd->nsector = sectors;
+       cmd->sector = block;
+       cmd->lcyl = block >>= 8;
+       cmd->hcyl = block >>= 8;
+       cmd->device_head = ((block >> 8) & 0x0f);
+       cmd->device_head |= (1 << 6);
+
+       cmd->command = WIN_READ;
+
+       return ob_ide_pio_data_in(drive, cmd);
+}
+
+static int
+ob_ide_read_ata_lba48(struct ide_drive *drive, unsigned long long block,
+                     char *buf, unsigned int sectors)
+{
+       struct ata_command *cmd = &drive->channel->ata_cmd;
+       struct ata_sector ata_sector;
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       cmd->buffer = buf;
+       cmd->buflen = sectors * 512;
+       ata_sector.all = sectors;
+
+       /*
+        * we are using tasklet addressing here
+        */
+       cmd->task[2] = ata_sector.low;
+       cmd->task[3] = ata_sector.high;
+       cmd->task[4] = block;
+       cmd->task[5] = block >>  8;
+       cmd->task[6] = block >> 16;
+       cmd->task[7] = block >> 24;
+       cmd->task[8] = (u64) block >> 32;
+       cmd->task[9] = (u64) block >> 40;
+
+       cmd->command = WIN_READ_EXT;
+
+       ob_ide_write_tasklet(drive, cmd);
+
+       return ob_ide_pio_data_in(drive, cmd);
+}
+/*
+ * read 'sectors' sectors from ata device
+ */
+static int
+ob_ide_read_ata(struct ide_drive *drive, unsigned long long block, char *buf,
+               unsigned int sectors)
+{
+       unsigned long long end_block = block + sectors;
+       const int need_lba48 = (end_block > (1ULL << 28)) || (sectors > 255);
+
+       if (end_block > drive->sectors)
+               return 1;
+       if (need_lba48 && drive->addressing != ide_lba48)
+               return 1;
+
+       /*
+        * use lba48 if we have to, otherwise use the faster lba28
+        */
+       if (need_lba48)
+               return ob_ide_read_ata_lba48(drive, block, buf, sectors);
+       else if (drive->addressing != ide_chs)
+               return ob_ide_read_ata_lba28(drive, block, buf, sectors);
+
+       return ob_ide_read_ata_chs(drive, block, buf, sectors);
+}
+
+static int
+ob_ide_read_sectors(struct ide_drive *drive, unsigned long long block,
+                   char *buf, unsigned int sectors)
+{
+       if (!sectors)
+               return 1;
+       if (block + sectors > drive->sectors)
+               return 1;
+
+#ifdef CONFIG_DEBUG_IDE
+               printf("ob_ide_read_sectors: block=%Ld sectors=%u\n", (unsigned 
long) block, sectors);
+#endif
+
+       if (drive->type == ide_type_ata)
+               return ob_ide_read_ata(drive, block, buf, sectors);
+       else
+               return ob_ide_read_atapi(drive, block, buf, sectors);
+}
+
+/*
+ * byte swap the string if necessay, and strip leading/trailing blanks
+ */
+static void
+ob_ide_fixup_string(unsigned char *s, unsigned int len)
+{
+       unsigned char *p = s, *end = &s[len & ~1];
+
+       /*
+        * if little endian arch, byte swap the string
+        */
+#ifdef CONFIG_LITTLE_ENDIAN
+       for (p = end ; p != s;) {
+               unsigned short *pp = (unsigned short *) (p -= 2);
+               *pp = __be16_to_cpu(*pp);
+       }
+#endif
+
+       while (s != end && *s == ' ')
+               ++s;
+       while (s != end && *s)
+               if (*s++ != ' ' || (s != end && *s && *s != ' '))
+                       *p++ = *(s-1);
+       while (p != end)
+               *p++ = '\0';
+}
+
+/*
+ * it's big endian, we need to swap (if on little endian) the items we use
+ */
+static int
+ob_ide_fixup_id(struct hd_driveid *id)
+{
+       ob_ide_fixup_string(id->model, 40);
+       id->config = __le16_to_cpu(id->config);
+       id->lba_capacity = __le32_to_cpu(id->lba_capacity);
+       id->cyls = __le16_to_cpu(id->cyls);
+       id->heads = __le16_to_cpu(id->heads);
+       id->sectors = __le16_to_cpu(id->sectors);
+       id->command_set_2 = __le16_to_cpu(id->command_set_2);
+       id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2);
+
+       return 0;
+}
+
+static int
+ob_ide_identify_drive(struct ide_drive *drive)
+{
+       struct ata_command *cmd = &drive->channel->ata_cmd;
+       struct hd_driveid id;
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->buffer = (unsigned char *) &id;
+       cmd->buflen = 512;
+
+       if (drive->type == ide_type_ata)
+               cmd->command = WIN_IDENTIFY;
+       else if (drive->type == ide_type_atapi)
+               cmd->command = WIN_IDENTIFY_PACKET;
+       else {
+               printf("%s: called with bad device type %d\n", __FUNCTION__, 
drive->type);
+               return 1;
+       }
+
+       if (ob_ide_pio_data_in(drive, cmd))
+               return 1;
+
+       ob_ide_fixup_id(&id);
+
+       if (drive->type == ide_type_atapi) {
+               drive->media = (id.config >> 8) & 0x1f;
+               drive->sectors = 0x7fffffff;
+               drive->bs = 2048;
+               drive->max_sectors = 31;
+       } else {
+               drive->media = ide_media_disk;
+               drive->sectors = id.lba_capacity;
+               drive->bs = 512;
+               drive->max_sectors = 255;
+
+#ifdef CONFIG_IDE_LBA48
+               if ((id.command_set_2 & 0x0400) && (id.cfs_enable_2 & 0x0400)) {
+                       drive->addressing = ide_lba48;
+                       drive->max_sectors = 65535;
+               } else
+#endif
+               if (id.capability & 2)
+                       drive->addressing = ide_lba28;
+               else {
+                       drive->addressing = ide_chs;
+               }
+
+               /* only set these in chs mode? */
+               drive->cyl = id.cyls;
+               drive->head = id.heads;
+               drive->sect = id.sectors;
+       }
+
+       strcpy(drive->model, id.model);
+       return 0;
+}
+
+/*
+ * identify type of devices on channel. must have already been probed.
+ */
+static void
+ob_ide_identify_drives(struct ide_channel *chan)
+{
+       struct ide_drive *drive;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               drive = &chan->drives[i];
+
+               if (!drive->present)
+                       continue;
+
+               ob_ide_identify_drive(drive);
+       }
+}
+
+/*
+ * software reset (ATA-4, section 8.3)
+ */
+static void
+ob_ide_software_reset(struct ide_drive *drive)
+{
+       struct ide_channel *chan = drive->channel;
+
+       ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN | IDECON_SRST);
+       ob_ide_400ns_delay(drive);
+       ob_ide_pio_writeb(drive, IDEREG_CONTROL, IDECON_NIEN);
+       ob_ide_400ns_delay(drive);
+
+       /*
+        * if master is present, wait for BUSY clear
+        */
+       if (chan->drives[0].present)
+               ob_ide_wait_stat(drive, 0, BUSY_STAT, NULL);
+
+       /*
+        * if slave is present, wait until it allows register access
+        */
+       if (chan->drives[1].present) {
+               unsigned char sectorn, sectorc;
+               int timeout = 1000;
+
+               do {
+                       /*
+                        * select it
+                        */
+                       ob_ide_pio_writeb(drive, IDEREG_CURRENT, IDEHEAD_DEV1);
+                       ob_ide_400ns_delay(drive);
+
+                       sectorn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+                       sectorc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+
+                       if (sectorc == 0x01 && sectorn == 0x01)
+                               break;
+
+               } while (--timeout);
+       }
+
+       /*
+        * reset done, reselect original device
+        */
+       drive->channel->selected = -1;
+       ob_ide_select_drive(drive);
+}
+
+/*
+ * this serves as both a device check, and also to verify that the drives
+ * we initially "found" are really there
+ */
+static void
+ob_ide_device_type_check(struct ide_drive *drive)
+{
+       unsigned char sc, sn, cl, ch, st;
+
+       if (ob_ide_select_drive(drive))
+               return;
+
+       sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+       sn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+
+       if (sc == 0x01 && sn == 0x01) {
+               /*
+                * read device signature
+                */
+               cl = ob_ide_pio_readb(drive, IDEREG_LCYL);
+               ch = ob_ide_pio_readb(drive, IDEREG_HCYL);
+               st = ob_ide_pio_readb(drive, IDEREG_STATUS);
+               if (cl == 0x14 && ch == 0xeb)
+                       drive->type = ide_type_atapi;
+               else if (cl == 0x00 && ch == 0x00 && st != 0x00)
+                       drive->type = ide_type_ata;
+               else
+                       drive->present = 0;
+       } else
+               drive->present = 0;
+}
+
+/*
+ * pure magic
+ */
+static void
+ob_ide_device_check(struct ide_drive *drive)
+{
+       unsigned char sc, sn;
+
+       /*
+        * non-existing io port should return 0xff, don't probe this
+        * channel at all then
+        */
+       if (ob_ide_pio_readb(drive, IDEREG_STATUS) == 0xff) {
+               drive->channel->present = 0;
+               return;
+       }
+
+       if (ob_ide_select_drive(drive))
+               return;
+
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa);
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0xaa);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0x55);
+       ob_ide_pio_writeb(drive, IDEREG_NSECTOR, 0x55);
+       ob_ide_pio_writeb(drive, IDEREG_SECTOR, 0xaa);
+
+       sc = ob_ide_pio_readb(drive, IDEREG_NSECTOR);
+       sn = ob_ide_pio_readb(drive, IDEREG_SECTOR);
+
+       /*
+        * we _think_ the device is there, we will make sure later
+        */
+       if (sc == 0x55 && sn == 0xaa) {
+               drive->present = 1;
+               drive->type = ide_type_unknown;
+       }
+}
+
+/*
+ * probe the legacy ide ports and find attached devices.
+ */
+static void
+ob_ide_probe(struct ide_channel *chan)
+{
+       struct ide_drive *drive;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               drive = &chan->drives[i];
+
+               ob_ide_device_check(drive);
+
+               /*
+                * no point in continuing
+                */
+               if (!chan->present)
+                       break;
+
+               if (!drive->present)
+                       continue;
+
+               /*
+                * select and reset device
+                */
+               if (ob_ide_select_drive(drive))
+                       continue;
+
+               ob_ide_software_reset(drive);
+
+               ob_ide_device_type_check(drive);
+       }
+}
+
+/*
+ * The following functions are interfacing with OpenBIOS. They
+ * are device node methods. Thus they have to do proper stack handling.
+ * 
+ */
+
+/*
+ * 255 sectors for ata lba28, 65535 for lba48, and 31 sectors for atapi
+ */
+static int
+ob_ide_max_transfer(int *idx)
+{
+       struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]];
+
+       return (drive->max_sectors * drive->bs);
+}
+
+int
+ob_ide_read_blocks(struct ide_drive *drive, int n, u32 blk, char* dest)
+{
+       int cnt = n;
+       while (n) {
+               int len = n;
+               if (len > drive->max_sectors)
+                       len = drive->max_sectors;
+                       
+               dprintf("reading %d sectors from blk %d\n",len, blk);
+               if (ob_ide_read_sectors(drive, blk, dest, len)) {
+                       return n-1;
+               }
+               dprintf("done\n");
+
+               dest += len * drive->bs;
+               n -= len;
+               blk += len;
+       }
+
+       return (cnt);
+}
+
+static int
+ob_ide_block_size(int *idx)
+{
+       struct ide_drive *drive=&ob_ide_channels[idx[1]].drives[idx[0]];
+       return(drive->bs);
+}
+
+//int ob_ide_init(int (*func)(struct ide_drive*))
+int ob_ide_init(void)
+{
+       int i, j;
+
+       for (i = 0; i < IDE_NUM_CHANNELS; i++) {
+               struct ide_channel *chan = &ob_ide_channels[i];
+
+               chan->mmio = 0;
+
+               for (j = 0; j < 8; j++)
+                       chan->io_regs[j] = io_ports[i] + j;
+
+               chan->io_regs[8] = ctl_ports[i];
+               chan->io_regs[9] = ctl_ports[i] + 1;
+
+               chan->obide_inb = ob_ide_inb;
+               chan->obide_insw = ob_ide_insw;
+               chan->obide_outb = ob_ide_outb;
+               chan->obide_outsw = ob_ide_outsw;
+
+               chan->selected = -1;
+
+               /*
+                * assume it's there, if not io port dead check will clear
+                */
+               chan->present = 1;
+
+               for (j = 0; j < 2; j++) {
+                       chan->drives[j].present = 0;
+                       chan->drives[j].unit = j;
+                       chan->drives[j].channel = chan;
+                       /* init with a decent value */
+                       chan->drives[j].bs = 512;
+
+                       chan->drives[j].nr = i * 2 + j;
+               }
+
+               ob_ide_probe(chan);
+
+               if (!chan->present)
+                       continue;
+
+               ob_ide_identify_drives(chan);
+
+               printf("ata-%d: [io ports 0x%x-0x%x,0x%x]\n", i,
+                               chan->io_regs[0], chan->io_regs[0] + 7,
+                               chan->io_regs[8]);
+
+               for (j = 0; j < 2; j++) {
+                       struct ide_drive *drive = &chan->drives[j];
+                       char *media = "UNKNOWN";
+                       if (!drive->present)
+                               continue;
+                       printf("    drive%d [ATA%s ", j, drive->type == 
ide_type_atapi ? "PI" : "");
+                       switch (drive->media) {
+                       case ide_media_floppy:
+                               media = "floppy";
+                               break;
+                       case ide_media_cdrom:
+                               media = "cdrom";
+                               break;
+                       case ide_media_optical:
+                               media = "mo";
+                               break;
+                       case ide_media_disk:
+                               media = "disk";
+                               break;
+                       }
+                       printf("%s]: %s\n", media, drive->model);
+               }
+
+       }
+
+       return 0;
+}
+
+static int inited=0;
+
+int ide_probe(int drive)
+{
+       struct ide_drive *curr_drive = & ob_ide_channels[drive / 
2].drives[drive % 2];
+       if (!inited) {
+               ob_ide_init();
+               inited = 1;
+       }
+
+       if (!curr_drive->present)
+               return -1;
+
+       return 0;
+       
+}
+
+int ide_probe_verbose(int drive)
+{
+       struct ide_drive *curr_drive = & ob_ide_channels[drive / 
2].drives[drive % 2];
+       char *media = "UNKNOWN";
+
+       if (!inited) {
+               ob_ide_init();
+               inited = 1;
+       }
+
+       if (!curr_drive->present) {
+               return -1;
+       }
+       printf("ata%d %s ", drive / 2, (drive % 2)?"slave ":"master");
+
+
+       printf("[ATA%s ", curr_drive->type == ide_type_atapi ? "PI" : "");
+       switch (curr_drive->media) {
+       case ide_media_floppy:
+               media = "Floppy";
+               break;
+       case ide_media_cdrom:
+               media = "CDROM/DVD";
+               break;
+       case ide_media_optical:
+               media = "MO";
+               break;
+       case ide_media_disk:
+               media = "DISK";
+               break;
+       }
+       printf("%s]: %s\n", media, curr_drive->model);
+
+       return 0;
+}
+
+int ide_read(int drive, sector_t sector, void *buffer)
+{
+       int ret;
+       ret = ob_ide_read_blocks(&ob_ide_channels[drive / 2].drives[drive % 2], 
1, sector, buffer);
+       if (ret!=1) { // right now only one block at a time.. bummer
+               return -1;
+       }
+       return 0;
+}
+
+int ide_read_blocks(int drive, sector_t sector, int count, void *buffer)
+{
+       int ret;
+       ret = ob_ide_read_blocks(&ob_ide_channels[drive / 2].drives[drive % 2],
+                       count, sector, buffer);
+       if (ret!=count) { // right now only one block at a time.. bummer
+               return -1;
+       }
+       return 0;
+}

Added: trunk/filo/drivers/ide_new.h
===================================================================
--- trunk/filo/drivers/ide_new.h                                (rev 0)
+++ trunk/filo/drivers/ide_new.h        2009-03-11 03:07:08 UTC (rev 86)
@@ -0,0 +1,233 @@
+#ifndef IDE_H
+#define IDE_H
+
+#include <arch/io.h>
+#include "hdreg.h"
+
+/*
+ * legacy ide ports
+ */
+#define IDEREG_DATA    0x00
+#define IDEREG_ERROR   0x01
+#define IDEREG_FEATURE IDEREG_ERROR
+#define IDEREG_NSECTOR 0x02
+#define IDEREG_SECTOR  0x03
+#define IDEREG_LCYL    0x04
+#define IDEREG_HCYL    0x05
+#define IDEREG_CURRENT 0x06
+#define IDEREG_STATUS  0x07
+#define IDEREG_COMMAND IDEREG_STATUS
+#define IDEREG_CONTROL 0x08
+#define IDEREG_ASTATUS IDEREG_CONTROL
+
+/*
+ * device control bits
+ */
+#define IDECON_NIEN    0x02
+#define IDECON_SRST    0x04
+
+/*
+ * device head bits
+ */
+#define IDEHEAD_LBA    0x40
+#define IDEHEAD_DEV0   0x00
+#define IDEHEAD_DEV1   0x10
+
+/*
+ * status bytes
+ */
+#define ERR_STAT       0x01
+#define DRQ_STAT       0x08
+#define SEEK_STAT      0x10
+#define WRERR_STAT     0x20
+#define READY_STAT     0x40
+#define BUSY_STAT      0x80
+
+#define IREASON_CD     0x01
+#define IREASON_IO     0x02
+
+/*
+ * ATA opcodes
+ */
+#define WIN_READ               0x20
+#define WIN_READ_EXT           0x24
+#define WIN_IDENTIFY           0xEC
+#define WIN_PACKET             0xA0
+#define WIN_IDENTIFY_PACKET    0xA1
+
+/*
+ * ATAPI opcodes
+ */
+#define ATAPI_TUR              0x00
+#define ATAPI_READ_10          0x28
+#define ATAPI_REQ_SENSE                0x03
+#define ATAPI_START_STOP_UNIT  0x1b
+#define ATAPI_READ_CAPACITY    0x25
+
+/*
+ * atapi sense keys
+ */
+#define ATAPI_SENSE_NOT_READY  0x02
+
+/*
+ * supported device types
+ */
+enum {
+       ide_type_unknown,
+       ide_type_ata,
+       ide_type_atapi,
+};
+
+enum {
+       ide_media_floppy = 0x00,
+       ide_media_cdrom = 0x05,
+       ide_media_optical = 0x07,
+       ide_media_disk = 0x20,
+};
+
+/*
+ * drive addressing
+ */
+enum {
+       ide_chs = 1,
+       ide_lba28,
+       ide_lba48,
+};
+
+/*
+ * simple ata command that works for everything (except 48-bit lba commands)
+ */
+struct ata_command {
+       char *buffer;
+       unsigned int buflen;
+
+       /*
+        * data register
+        */
+       unsigned char data;
+       unsigned char feature;
+       unsigned char nsector;
+       unsigned char sector;
+       unsigned char lcyl;
+       unsigned char hcyl;
+       unsigned char device_head;
+       unsigned char command;
+       unsigned char control;
+
+       /*
+        * or tasklet, just for lba48 for now (above could be scrapped)
+        */
+       unsigned char task[10];
+
+       /*
+        * output
+        */
+       unsigned char stat;
+       unsigned int bytes;
+};
+
+struct atapi_command {
+       unsigned char cdb[12];
+       unsigned char *buffer;
+       unsigned int buflen;
+       unsigned char data_direction;
+
+       unsigned char stat;
+       unsigned char sense_valid;
+       struct request_sense sense;
+       unsigned char old_cdb;
+};
+
+struct ide_channel;
+
+struct ide_drive {
+       char            unit;           /* 0: master, 1: slave */
+       char            present;        /* there or not */
+       char            type;           /* ata or atapi */
+       char            media;          /* disk, cdrom, etc */
+       char            addressing;     /* chs/lba28/lba48 */
+
+       char            model[40];      /* name */
+       int             nr;
+
+       unsigned long   sectors;
+
+       unsigned int    max_sectors;
+
+       /*
+        * for legacy chs crap
+        */
+       unsigned int    cyl;
+       unsigned int    head;
+       unsigned int    sect;
+
+       unsigned int bs;                /* block size */
+
+       struct ide_channel *channel;
+};
+
+struct ide_channel {
+       /*
+        * either mmio or io_regs is set to indicate mmio or not
+        */
+       int mmio;
+       int io_regs[10];
+
+       /*
+        * can be set to a mmio hook, default it legacy outb/inb
+        */
+       void (*obide_outb)(unsigned char addr, unsigned long port);
+       unsigned char (*obide_inb)(unsigned long port);
+       void (*obide_insw)(unsigned long port, unsigned char *addr, unsigned 
int count);
+       void (*obide_outsw)(unsigned long port, unsigned char *addr, unsigned 
int count);
+
+       struct ide_drive drives[2];
+       char selected;
+       char present;
+
+       /*
+        * only one can be busy per channel
+        */
+       struct ata_command ata_cmd;
+       struct atapi_command atapi_cmd;
+       
+};
+
+enum {
+       atapi_ddir_none,
+       atapi_ddir_read,
+       atapi_ddir_write,
+};
+
+struct ata_sector {
+       u16 all;
+       union {
+#ifdef CONFIG_BIG_ENDIAN
+               u8 high;
+               u8 low;
+#endif
+#ifdef CONFIG_LITTLE_ENDIAN
+               u8 low;
+               u8 high;
+#endif
+       };
+};
+
+int
+ob_ide_read_blocks(struct ide_drive *drive, int n, u32 blk, char* dest);
+static int
+ob_ide_atapi_request_sense(struct ide_drive *drive);
+//int ob_ide_init(int (*func)(struct ide_drive*));
+int ob_ide_init(void);
+
+
+/* FILO compat */
+#define CONFIG_LITTLE_ENDIAN
+#define CONFIG_IDE_LBA48
+
+#define __be32_to_cpu be32_to_cpu
+#define __be16_to_cpu be16_to_cpu
+#define __le32_to_cpu le32_to_cpu
+#define __le16_to_cpu le16_to_cpu
+
+#endif

Modified: trunk/filo/drivers/intel.c
===================================================================
--- trunk/filo/drivers/intel.c  2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/drivers/intel.c  2009-03-11 03:07:08 UTC (rev 86)
@@ -1,7 +1,7 @@
 /*
  * This file is part of FILO.
  *
- * Copyright (C) 2008 coresystems GmbH
+ * Copyright (C) 2008-2009 coresystems GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,8 +30,10 @@
 
 void platform_poweroff(void)
 {
-       int pmbase = 0x800;
+       int pmbase;
 
+       pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe;
+
        /* XXX The sequence is correct; It works fine under Linux. 
         * Yet, it does not power off the system in FILO. 
         * Some initialization is missing

Modified: trunk/filo/fs/blockdev.c
===================================================================
--- trunk/filo/fs/blockdev.c    2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/fs/blockdev.c    2009-03-11 03:07:08 UTC (rev 86)
@@ -247,7 +247,7 @@
        }
 
        switch (type) {
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK) || defined(CONFIG_IDE_NEW_DISK)
        case DISK_IDE:
                if (ide_probe(drive) != 0) {
                        debug("Failed to open IDE.\n");
@@ -384,12 +384,24 @@
        if (cache_sect[hash] != sector) {
                cache_sect[hash] = (unsigned long) -1;
                switch (dev_type) {
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK) 
                case DISK_IDE:
                        if (ide_read(dev_drive, sector, buf) != 0)
                                goto readerr;
                        break;
 #endif
+#if defined(CONFIG_IDE_NEW_DISK)
+               case DISK_IDE:
+               {
+                       int count = (NUM_CACHE-hash>8)?8:(NUM_CACHE-hash);
+                       if (ide_read_blocks(dev_drive, sector, count, buf) != 0)
+                               goto readerr;
+                       while (--count>0) {
+                               cache_sect[hash+count] = sector + count;
+                       }
+                       break;
+               }
+#endif
 #if defined(CONFIG_USB_NEW_DISK) && defined(CONFIG_USB)
                case DISK_NEW_USB:
                {

Modified: trunk/filo/include/fs.h
===================================================================
--- trunk/filo/include/fs.h     2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/include/fs.h     2009-03-11 03:07:08 UTC (rev 86)
@@ -27,11 +27,17 @@
 #define DEV_SECTOR_SIZE                (1<<9)
 #define DEV_SECTOR_MASK                (DEV_SECTOR_SIZE-1)
 
-#ifdef CONFIG_IDE_DISK
+#if defined(CONFIG_IDE_DISK)
 int ide_probe(int drive);
 int ide_read(int drive, sector_t sector, void *buffer);
 #endif
 
+#if defined(CONFIG_IDE_NEW_DISK)
+int ide_probe(int drive);
+int ide_probe_verbose(int drive);
+int ide_read_blocks(const int drive, const sector_t sector, const int size, 
void *buffer);
+#endif
+
 #ifdef CONFIG_USB_DISK
 int usb_probe(int drive);
 int usb_read(int drive, sector_t sector, void *buffer);

Modified: trunk/filo/main/Makefile.inc
===================================================================
--- trunk/filo/main/Makefile.inc        2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/main/Makefile.inc        2009-03-11 03:07:08 UTC (rev 86)
@@ -16,6 +16,7 @@
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 #
 
-TARGETS-y += main/filo.o main/elfload.o main/elfnote.o main/ipchecksum.o 
main/strtox.o
+TARGETS-y += main/filo.o main/strtox.o
+TARGETS-y += main/elfload.o main/elfnote.o main/ipchecksum.o 
 TARGETS-$(CONFIG_SUPPORT_SOUND) += main/sound.o
 

Modified: trunk/filo/main/grub/builtins.c
===================================================================
--- trunk/filo/main/grub/builtins.c     2008-12-20 11:23:33 UTC (rev 85)
+++ trunk/filo/main/grub/builtins.c     2009-03-11 03:07:08 UTC (rev 86)
@@ -319,6 +319,56 @@
 #endif
 };
 
+#if CONFIG_DEVELOPER_TOOLS
+/* default */
+static int dumppm_func(char *arg, int flags)
+{
+       u16 pmbase;
+
+       pmbase = pci_read_config16(PCI_DEV(0,0x1f, 0), 0x40) & 0xfffe;
+
+       grub_printf("pmbase+0x0000: 0x%04x     (PM1_STS)\n", 
inw(pmbase+0x0000));
+       grub_printf("pmbase+0x0002: 0x%04x     (PM1_EN)\n", inw(pmbase+0x0002));
+       grub_printf("pmbase+0x0004: 0x%08x (PM1_CNT)\n", inl(pmbase+0x0004));
+       grub_printf("pmbase+0x0008: 0x%08x (PM1_TMR)\n", inl(pmbase+0x0008));
+       grub_printf("pmbase+0x0010: 0x%08x (PROC_CNT)\n", inl(pmbase+0x0010));
+       grub_printf("pmbase+0x0020: 0x%08x (PM2_CNT)\n", inl(pmbase+0x0020));
+       grub_printf("pmbase+0x0028: 0x%08x (GPE0_STS)\n", inl(pmbase+0x0028));
+       grub_printf("pmbase+0x002c: 0x%08x (GPE0_EN)\n", inl(pmbase+0x002c));
+       grub_printf("pmbase+0x0030: 0x%08x (SMI_EN)\n", inl(pmbase+0x0030));
+       grub_printf("pmbase+0x0034: 0x%08x (SMI_STS)\n", inl(pmbase+0x0034));
+       grub_printf("pmbase+0x0038: 0x%04x     (ALT_GP_SMI_EN)\n", 
inw(pmbase+0x0038));
+       grub_printf("pmbase+0x003a: 0x%04x     (ALT_GP_SMI_STS)\n", 
inw(pmbase+0x003a));
+       grub_printf("pmbase+0x0042: 0x%02x       (GPE_CNTL)\n", 
inb(pmbase+0x0042));
+       grub_printf("pmbase+0x0044: 0x%04x     (DEVACT_STS)\n", 
inw(pmbase+0x0044));
+       grub_printf("pmbase+0x0050: 0x%02x       (SS_CNT)\n", 
inb(pmbase+0x0050));
+       grub_printf("pmbase+0x0054: 0x%08x (C3_RES)\n", inl(pmbase+0x0054));
+#if 0
+       // TCO
+       grub_printf("pmbase+0x0060: 0x%04x     (TCO_RLD)\n", 
inw(pmbase+0x0060));
+       grub_printf("pmbase+0x0062: 0x%02x       (TCO_DAT_IN)\n", 
inb(pmbase+0x0062));
+       grub_printf("pmbase+0x0063: 0x%02x       (TCO_DAT_OUT)\n", 
inb(pmbase+0x0063));
+       grub_printf("pmbase+0x0064: 0x%04x     (TCO1_STS)\n", 
inw(pmbase+0x0064));
+       grub_printf("pmbase+0x0066: 0x%04x     (TCO2_STS)\n", 
inw(pmbase+0x0066));
+       grub_printf("pmbase+0x0068: 0x%04x     (TCO1_CNT)\n", 
inw(pmbase+0x0068));
+       grub_printf("pmbase+0x006a: 0x%04x     (TCO2_CNT)\n", 
inw(pmbase+0x006a));
+       grub_printf("pmbase+0x006c: 0x%04x     (TCO_MESSAGE)\n", 
inw(pmbase+0x006c));
+       grub_printf("pmbase+0x006e: 0x%02x       (TCO_WDCNT)\n", 
inb(pmbase+0x006e));
+       grub_printf("pmbase+0x0070: 0x%02x       (TCO_SW_IRQ_GEN)\n", 
inb(pmbase+0x0070));
+       grub_printf("pmbase+0x0072: 0x%04x     (TCO_TMR)\n", 
inw(pmbase+0x0072));
+#endif
+       return 0;
+}
+
+static struct builtin builtin_dumppm = {
+       "dumppm",
+       dumppm_func,
+       BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+       "dumppm",
+       "Dump Powermanagement registers"
+};
+#endif
+
 #if CONFIG_EXPERIMENTAL
 #warning "FIND not implemented yet."
 /* find */
@@ -1059,11 +1109,16 @@
 #ifdef CONFIG_DEVELOPER_TOOLS
 static int probe_func(char *arg, int flags)
 {
-#if CONFIG_IDE_DISK
+#if CONFIG_IDE_DISK 
        int i;
 
        for (i=0; i<8; i++)
                ide_probe(i);
+#elif CONFIG_IDE_NEW_DISK
+       int i;
+
+       for (i=0; i<8; i++)
+               ide_probe_verbose(i);
 #else
        grub_printf("No IDE driver.\n");
 #endif
@@ -1566,14 +1621,52 @@
 #endif
 };
 
+static int cat_func(char *arg, int flags)
+{
+       char buf[4096];
+       int len;
 
+       temp_space[0]=0;
+       copy_path_to_filo_bootline(arg, temp_space, 1);
+       if (temp_space[0]==0) {
+               return help_func("cat",0);
+       }
+       if (!file_open(temp_space)) {
+               errnum = ERR_FILE_NOT_FOUND;
+               return 1;
+       }
+
+       while ((len = file_read(buf, sizeof(buf))) != 0) {
+               int cnt;
+               for (cnt = 0; cnt < len; cnt++) {
+                       grub_putchar(buf[cnt]);
+               }
+       }
+
+       file_close();
+
+       return 0;
+}
+
+static struct builtin builtin_cat = {
+       "cat",
+       cat_func,
+       BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+       "cat FILENAME",
+       "Print the content of FILENAME to the terminal."
+};
+
 /* README !!! XXX !!! This list has to be alphabetically ordered !!! */
 
 struct builtin *builtin_table[] = {
        &builtin_boot,
+       &builtin_cat,
        &builtin_color,
        &builtin_configfile,
        &builtin_default,
+#ifdef CONFIG_DEVELOPER_TOOLS
+       &builtin_dumppm,
+#endif
 #ifdef CONFIG_EXPERIMENTAL
        &builtin_find,
 #endif


--
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to