OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [orpmon/] [drivers/] [ata.c] - Diff between revs 1020 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1020 Rev 1765
/*
/*
    ata.c -- ATA driver
    ata.c -- ATA driver
    Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
    Copyright (C) 2002 Richard Herveille, rherveille@opencores.org
 
 
    This file is part of OpenRISC 1000 Reference Platform Monitor (ORPmon)
    This file is part of OpenRISC 1000 Reference Platform Monitor (ORPmon)
 
 
    This program is free software; you can redistribute it and/or modify
    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
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version
    (at your option) any later version
 
 
    This program is distributed in the hope that it will be useful,
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    GNU General Public License for more details.
 
 
    You should have received a copy of the GNU General Public License
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
 
 
#include <string.h>
#include <string.h>
 
 
/* get prototype for 'printf'
/* get prototype for 'printf'
   get IN_CLOCK (from 'board.h')
   get IN_CLOCK (from 'board.h')
*/
*/
#include "common.h"
#include "common.h"
#include "ata.h"
#include "ata.h"
 
 
 
 
/*
/*
  static constants (yuck, yuck, yuck)
  static constants (yuck, yuck, yuck)
*/
*/
static int usage[2] = {0, 0};
static int usage[2] = {0, 0};
static int hardsect_size[2] = {512, 512};
static int hardsect_size[2] = {512, 512};
static int current_pio_mode = 9999;
static int current_pio_mode = 9999;
 
 
/*
/*
  local defines
  local defines
*/
*/
#define TYPE(devid) (devid >> 4)
#define TYPE(devid) (devid >> 4)
#define REV(devid)  (devid & 0xf)
#define REV(devid)  (devid & 0xf)
 
 
#define BASE(inode)    ( (unsigned long) (MAJOR(inode->i_rdev) << 24) )
#define BASE(inode)    ( (unsigned long) (MAJOR(inode->i_rdev) << 24) )
#define DEVICE(inode)  ( MINOR(inode->i_rdev) )
#define DEVICE(inode)  ( MINOR(inode->i_rdev) )
 
 
#define IN_CLK_MHZ (IN_CLK / 1000000)
#define IN_CLK_MHZ (IN_CLK / 1000000)
#define TO_TICKS(time) ( ((time + (IN_CLK_MHZ >> 1)) / IN_CLK_MHZ) -1 )
#define TO_TICKS(time) ( ((time + (IN_CLK_MHZ >> 1)) / IN_CLK_MHZ) -1 )
 
 
 
 
/*
/*
       A T A _ O P E N
       A T A _ O P E N
 
 
       opens ata device;
       opens ata device;
       - identifies ata-device-id
       - identifies ata-device-id
       - programs ata-host
       - programs ata-host
 
 
       MAJOR: atahost identification (base address)
       MAJOR: atahost identification (base address)
       MINOR: atadevice identification (MSB=0: device0, MSB=1: device1)
       MINOR: atadevice identification (MSB=0: device0, MSB=1: device1)
*/
*/
int ata_open(struct inode *inode, struct file *filp)
int ata_open(struct inode *inode, struct file *filp)
{
{
  unsigned int atahost, device;
  unsigned int atahost, device;
  unsigned short buf[256];
  unsigned short buf[256];
  unsigned short dev_pio;
  unsigned short dev_pio;
  unsigned long sectors;
  unsigned long sectors;
 
 
  char txt[41];
  char txt[41];
 
 
printf( "Checking device-id\n" );
printf( "Checking device-id\n" );
  /* check device-id (MINOR number)                                   */
  /* check device-id (MINOR number)                                   */
  if ( (device = DEVICE(inode)) > 1 )
  if ( (device = DEVICE(inode)) > 1 )
      return EOPENIDEV;
      return EOPENIDEV;
 
 
printf( "Searching for hostcontroller: " );
printf( "Searching for hostcontroller: " );
  /* get atahost id                                                   */
  /* get atahost id                                                   */
  atahost = ata_ioctl(inode, filp, ATA_IOCTL_IDENTIFY_HOST, 0);
  atahost = ata_ioctl(inode, filp, ATA_IOCTL_IDENTIFY_HOST, 0);
  if (atahost)
  if (atahost)
  {
  {
    printf( "OCIDEC-%1d, revision 0x%02X found at 0x%08lX.\n", TYPE(atahost), REV(atahost), BASE(inode) );
    printf( "OCIDEC-%1d, revision 0x%02X found at 0x%08lX.\n", TYPE(atahost), REV(atahost), BASE(inode) );
  }
  }
  else
  else
  {
  {
    printf( "No OCIDEC device found.\n" );
    printf( "No OCIDEC device found.\n" );
    return EOPENIHOST;
    return EOPENIHOST;
  }
  }
 
 
 
 
  /* check if the host has been opened already                        */
  /* check if the host has been opened already                        */
  if (!usage[device]++)
  if (!usage[device]++)
  {
  {
printf( "Opening device for the first time\n" );
printf( "Opening device for the first time\n" );
      /* no, take device out of reset                                 */
      /* no, take device out of reset                                 */
      ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, CLR | ARG_HW_RST);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, CLR | ARG_HW_RST);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, CLR | ARG_SW_RST);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, CLR | ARG_SW_RST);
 
 
      /* program PIO timing registers (set to PIO mode 0)             */
      /* program PIO timing registers (set to PIO mode 0)             */
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO0);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO0);
 
 
      /* enable host controller (for old OCIDEC cores)                */
      /* enable host controller (for old OCIDEC cores)                */
      ata_ioctl(inode, filp, ATA_IOCTL_ENABLE_HOST, 0);
      ata_ioctl(inode, filp, ATA_IOCTL_ENABLE_HOST, 0);
  }
  }
 
 
  /* select requested device                                          */
  /* select requested device                                          */
  ata_ioctl(inode, filp, ATA_IOCTL_SELECT_DEVICE, 0);
  ata_ioctl(inode, filp, ATA_IOCTL_SELECT_DEVICE, 0);
 
 
printf( "Executing IdentifyDevice command\n" );
printf( "Executing IdentifyDevice command\n" );
  /* identify requested ata-devices                                   */
  /* identify requested ata-devices                                   */
  ata_ioctl(inode, filp, ATA_IOCTL_EXEC_CMD, IDENTIFY_DEVICE);
  ata_ioctl(inode, filp, ATA_IOCTL_EXEC_CMD, IDENTIFY_DEVICE);
 
 
  /* read block from ata-device                                 */
  /* read block from ata-device                                 */
  buf[0] = 256;
  buf[0] = 256;
  ata_ioctl(inode, filp, ATA_IOCTL_READ, (unsigned long) buf);
  ata_ioctl(inode, filp, ATA_IOCTL_READ, (unsigned long) buf);
 
 
  /* check if a valid device was found                                */
  /* check if a valid device was found                                */
  /* bit 15 in identify_device word0 must be '0',
  /* bit 15 in identify_device word0 must be '0',
     or be equal to 0x848a (CFA feature set)                          */
     or be equal to 0x848a (CFA feature set)                          */
  if ( (buf[0] & 0x8000) && (buf[0] != 0x848a) )
  if ( (buf[0] & 0x8000) && (buf[0] != 0x848a) )
  {
  {
    ata_release(inode, filp);
    ata_release(inode, filp);
    return EOPENNODEV;
    return EOPENNODEV;
  }
  }
 
 
  /* Then check specific configuration word                           */
  /* Then check specific configuration word                           */
  if (buf[0] == 0x848a)
  if (buf[0] == 0x848a)
    printf( "Found CompactFLASH device.\n" );
    printf( "Found CompactFLASH device.\n" );
  else
  else
    switch(buf[2]) {
    switch(buf[2]) {
       case 0x37c8:
       case 0x37c8:
           /* device does require SET_FEATURES
           /* device does require SET_FEATURES
              IDENTIFY_DEVICE response is incomplete                  */
              IDENTIFY_DEVICE response is incomplete                  */
       case 0x738c:
       case 0x738c:
           /* device does require SET_FEATURES
           /* device does require SET_FEATURES
              IDENTIFY_DEVICE response is complete                    */
              IDENTIFY_DEVICE response is complete                    */
           ata_ioctl(inode, filp, ATA_IOCTL_SET_FEATURES, 0); //FIXME
           ata_ioctl(inode, filp, ATA_IOCTL_SET_FEATURES, 0); //FIXME
           break;
           break;
       case 0x8c73:
       case 0x8c73:
           /* device does not require SET_FEATURES
           /* device does not require SET_FEATURES
              IDENTIFY_DEVICE response is incomplete                  */
              IDENTIFY_DEVICE response is incomplete                  */
       case 0xc837:
       case 0xc837:
           /* device does not require SET_FEATURES
           /* device does not require SET_FEATURES
              IDENTIFY_DEVICE response is complete                    */
              IDENTIFY_DEVICE response is complete                    */
           break;
           break;
 
 
       default:
       default:
           ata_release(inode, filp);
           ata_release(inode, filp);
           return EOPENNODEV;
           return EOPENNODEV;
     }
     }
 
 
  /* checks ok                                                        */
  /* checks ok                                                        */
 
 
  /* display device model, serialnumber, and firmware revision        */
  /* display device model, serialnumber, and firmware revision        */
  memcpy(txt, &buf[27], 40);
  memcpy(txt, &buf[27], 40);
  txt[40] = '\0';
  txt[40] = '\0';
  printf( "Model       : %s\n", txt );
  printf( "Model       : %s\n", txt );
 
 
  memcpy(txt, &buf[10], 20);
  memcpy(txt, &buf[10], 20);
  txt[20] = '\0';
  txt[20] = '\0';
  printf( "Serial      : %s\n", txt );
  printf( "Serial      : %s\n", txt );
 
 
  memcpy( txt, &buf[23], 8);
  memcpy( txt, &buf[23], 8);
  txt[8] = '\0';
  txt[8] = '\0';
  printf( "Firmware rev: %s\n", txt );
  printf( "Firmware rev: %s\n", txt );
 
 
  /* display size in MBytes                                           */
  /* display size in MBytes                                           */
  sectors = (buf[61] << 16) | buf[60];
  sectors = (buf[61] << 16) | buf[60];
  printf( "              %ld MBytes ", sectors >> 11 ); /* assuming 512bytes per sector */
  printf( "              %ld MBytes ", sectors >> 11 ); /* assuming 512bytes per sector */
 
 
  /* get supported pio modes                                          */
  /* get supported pio modes                                          */
  dev_pio = buf[64];
  dev_pio = buf[64];
 
 
  /* program ocidec timing registers to highest possible pio mode     */
  /* program ocidec timing registers to highest possible pio mode     */
  if (dev_pio & PIO4)
  if (dev_pio & PIO4)
  {
  {
      printf("PIO-4 supported\n");
      printf("PIO-4 supported\n");
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO4);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO4);
  }
  }
  else if (dev_pio & PIO3)
  else if (dev_pio & PIO3)
  {
  {
      printf("PIO-3 supported\n");
      printf("PIO-3 supported\n");
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO3);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO3);
  }
  }
  else
  else
  {
  {
      printf("PIO-2 supported\n");
      printf("PIO-2 supported\n");
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO2);
      ata_ioctl(inode, filp, ATA_IOCTL_SET_PIO, ARG_PIO2);
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
/*
/*
       A T A _ R E L E A S E
       A T A _ R E L E A S E
 
 
       closes ata device;
       closes ata device;
*/
*/
int ata_release(struct inode *inode, struct file *filp)
int ata_release(struct inode *inode, struct file *filp)
{
{
  /* decrease usage count */
  /* decrease usage count */
  if (!--usage[DEVICE(inode)])
  if (!--usage[DEVICE(inode)])
  {
  {
    /* reset atahost */
    /* reset atahost */
    ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, SET | ARG_HW_RST);
    ata_ioctl(inode, filp, ATA_IOCTL_SET_RST, SET | ARG_HW_RST);
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 
 
 
/*
/*
       A T A _ R E A D _ D P O R T
       A T A _ R E A D _ D P O R T
 
 
       closes ata device;
       closes ata device;
*/
*/
int ata_read_dport(unsigned long base)
int ata_read_dport(unsigned long base)
{
{
  /* device ready to transfer data ?? */
  /* device ready to transfer data ?? */
  while ( !ata_dev_datrdy(base) );
  while ( !ata_dev_datrdy(base) );
 
 
  return REG32(base + ATA_DR);
  return REG32(base + ATA_DR);
}
}
 
 
 
 
/*
/*
        A T A _ I O C T L
        A T A _ I O C T L
*/
*/
int ata_ioctl(struct inode *inode, struct file *filp, unsigned command, unsigned long argument)
int ata_ioctl(struct inode *inode, struct file *filp, unsigned command, unsigned long argument)
{
{
    unsigned long base = BASE(inode);
    unsigned long base = BASE(inode);
 
 
    switch (command)
    switch (command)
    {
    {
        case ATA_IOCTL_ENABLE_HOST:
        case ATA_IOCTL_ENABLE_HOST:
        /* enables the ATA host controller (sets IDE_EN bit)          */
        /* enables the ATA host controller (sets IDE_EN bit)          */
        {
        {
            REG32(base + ATA_CTRL) |= ATA_IDE_EN;
            REG32(base + ATA_CTRL) |= ATA_IDE_EN;
            return 0;
            return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_EXEC_CMD:
        case ATA_IOCTL_EXEC_CMD:
        /* sends a command to the ATA device                          */
        /* sends a command to the ATA device                          */
        {
        {
          while( ata_dev_busy(base) ); // wait for device ready
          while( ata_dev_busy(base) ); // wait for device ready
          ata_cmd(base) = argument & 0xff;
          ata_cmd(base) = argument & 0xff;
          return 0;
          return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_READ:
        case ATA_IOCTL_READ:
        {
        {
          unsigned short *buf_ptr = (short *)argument;
          unsigned short *buf_ptr = (short *)argument;
          int n, cnt;
          int n, cnt;
 
 
          cnt = buf_ptr[0];
          cnt = buf_ptr[0];
          for (n=0; n < cnt; n++)
          for (n=0; n < cnt; n++)
          {
          {
            while( !ata_dev_datrdy(base) );     // wait for data
            while( !ata_dev_datrdy(base) );     // wait for data
            *buf_ptr++ = ata_read_dport(base);  // read data
            *buf_ptr++ = ata_read_dport(base);  // read data
          }
          }
 
 
          return 0;
          return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_IDENTIFY_HOST:
        case ATA_IOCTL_IDENTIFY_HOST:
        /* reads OCIDEC status register configuration bits            */
        /* reads OCIDEC status register configuration bits            */
            return (REG32(base + ATA_STAT) >> 24);
            return (REG32(base + ATA_STAT) >> 24);
 
 
 
 
        case ATA_IOCTL_SELECT_DEVICE:
        case ATA_IOCTL_SELECT_DEVICE:
        /* selects ATA device                                         */
        /* selects ATA device                                         */
        {
        {
          while( ata_dev_busy(base) ); // wait for device ready
          while( ata_dev_busy(base) ); // wait for device ready
 
 
          /* sets the DEV bit in the device/head register             */
          /* sets the DEV bit in the device/head register             */
          if ( DEVICE(inode) )
          if ( DEVICE(inode) )
            REG32(base + ATA_DHR) |= ATA_DHR_DEV;  /* select device1  */
            REG32(base + ATA_DHR) |= ATA_DHR_DEV;  /* select device1  */
          else
          else
            REG32(base + ATA_DHR) &= ~ATA_DHR_DEV; /* select device0  */
            REG32(base + ATA_DHR) &= ~ATA_DHR_DEV; /* select device0  */
 
 
          return 0;
          return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_SET_FTE:
        case ATA_IOCTL_SET_FTE:
        {
        {
          /* set FTE bits                                             */
          /* set FTE bits                                             */
          if ( MINOR(inode->i_rdev) )
          if ( MINOR(inode->i_rdev) )
            if (argument)
            if (argument)
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE0;
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE0;
              else
              else
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE0;
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE0;
          else
          else
            if (argument)
            if (argument)
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
              else
              else
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
 
 
          return 0;
          return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_SET_PIO:
        case ATA_IOCTL_SET_PIO:
        /* programs the PIO timing registers                          */
        /* programs the PIO timing registers                          */
        {
        {
          unsigned long timing;
          unsigned long timing;
          unsigned short buf[256];
          unsigned short buf[256];
 
 
          /* do we need to read the identify_device block ??          */
          /* do we need to read the identify_device block ??          */
          if (argument & (ARG_PIO4 | ARG_PIO3) )
          if (argument & (ARG_PIO4 | ARG_PIO3) )
          {
          {
            /* identify requested ata-devices                         */
            /* identify requested ata-devices                         */
            ata_ioctl(inode, filp, ATA_IOCTL_EXEC_CMD, IDENTIFY_DEVICE);
            ata_ioctl(inode, filp, ATA_IOCTL_EXEC_CMD, IDENTIFY_DEVICE);
 
 
            /* read block from ata-device                             */
            /* read block from ata-device                             */
            buf[0] = 256;
            buf[0] = 256;
            ata_ioctl(inode, filp, ATA_IOCTL_READ, (unsigned long) buf);
            ata_ioctl(inode, filp, ATA_IOCTL_READ, (unsigned long) buf);
          }
          }
 
 
          /* program register transfer timing registers               */
          /* program register transfer timing registers               */
          /* set the slowest pio mode for register transfers          */
          /* set the slowest pio mode for register transfers          */
          if (argument < current_pio_mode)
          if (argument < current_pio_mode)
          {
          {
            switch (argument)
            switch (argument)
            {
            {
              case ARG_PIO4:
              case ARG_PIO4:
                if ( (buf[53] & 0x01) && buf[68] )
                if ( (buf[53] & 0x01) && buf[68] )
                  timing = ata_calc_pio_timing(buf[68], PIO4_RT1, PIO4_RT2, PIO4_RT4, PIO4_RT2I, PIO4_RT9);
                  timing = ata_calc_pio_timing(buf[68], PIO4_RT1, PIO4_RT2, PIO4_RT4, PIO4_RT2I, PIO4_RT9);
                else
                else
                  timing = ata_calc_pio_timing(PIO4_RT0, PIO4_RT1, PIO4_RT2, PIO4_RT4, PIO4_RT2I, PIO4_RT9);
                  timing = ata_calc_pio_timing(PIO4_RT0, PIO4_RT1, PIO4_RT2, PIO4_RT4, PIO4_RT2I, PIO4_RT9);
                break;
                break;
 
 
              case ARG_PIO3:
              case ARG_PIO3:
                if ( (buf[53] & 0x01) && buf[68] )
                if ( (buf[53] & 0x01) && buf[68] )
                  timing = ata_calc_pio_timing(buf[68], PIO3_RT1, PIO3_RT2, PIO3_RT4, PIO3_RT2I, PIO3_RT9);
                  timing = ata_calc_pio_timing(buf[68], PIO3_RT1, PIO3_RT2, PIO3_RT4, PIO3_RT2I, PIO3_RT9);
                else
                else
                  timing = ata_calc_pio_timing(PIO3_RT0, PIO3_RT1, PIO3_RT2, PIO3_RT4, PIO3_RT2I, PIO3_RT9);
                  timing = ata_calc_pio_timing(PIO3_RT0, PIO3_RT1, PIO3_RT2, PIO3_RT4, PIO3_RT2I, PIO3_RT9);
                break;
                break;
 
 
              case ARG_PIO2:
              case ARG_PIO2:
                timing = ata_calc_pio_timing(PIO2_RT0, PIO2_RT1, PIO2_RT2, PIO2_RT4, PIO2_RT2I, PIO2_RT9);
                timing = ata_calc_pio_timing(PIO2_RT0, PIO2_RT1, PIO2_RT2, PIO2_RT4, PIO2_RT2I, PIO2_RT9);
                break;
                break;
 
 
              case ARG_PIO1:
              case ARG_PIO1:
                timing = ata_calc_pio_timing(PIO1_RT0, PIO1_RT1, PIO1_RT2, PIO1_RT4, PIO1_RT2I, PIO1_RT9);
                timing = ata_calc_pio_timing(PIO1_RT0, PIO1_RT1, PIO1_RT2, PIO1_RT4, PIO1_RT2I, PIO1_RT9);
                break;
                break;
 
 
              default: /* PIO mode 0 */
              default: /* PIO mode 0 */
                timing = ata_calc_pio_timing(PIO0_RT0, PIO0_RT1, PIO0_RT2, PIO0_RT4, PIO0_RT2I, PIO0_RT9);
                timing = ata_calc_pio_timing(PIO0_RT0, PIO0_RT1, PIO0_RT2, PIO0_RT4, PIO0_RT2I, PIO0_RT9);
                break;
                break;
            }
            }
 
 
            /* program IORDY bit                                      */
            /* program IORDY bit                                      */
            if (argument & (ARG_PIO4 | ARG_PIO3) )
            if (argument & (ARG_PIO4 | ARG_PIO3) )
                REG32(base + ATA_CTRL) |= ATA_IORDY;
                REG32(base + ATA_CTRL) |= ATA_IORDY;
            else
            else
                REG32(base + ATA_CTRL) &= ~ATA_IORDY;
                REG32(base + ATA_CTRL) &= ~ATA_IORDY;
 
 
            /* program register transfer timing registers             */
            /* program register transfer timing registers             */
            REG32(base + ATA_PCTR) = timing;
            REG32(base + ATA_PCTR) = timing;
 
 
            current_pio_mode = argument;
            current_pio_mode = argument;
          }
          }
 
 
          /* Program data transfer timing registers                   */
          /* Program data transfer timing registers                   */
          if ( TYPE(ata_ioctl(inode, filp, ATA_IOCTL_IDENTIFY_HOST, 0)) > 1 )
          if ( TYPE(ata_ioctl(inode, filp, ATA_IOCTL_IDENTIFY_HOST, 0)) > 1 )
          {
          {
            switch (argument)
            switch (argument)
            {
            {
              case ARG_PIO4:
              case ARG_PIO4:
                if ( (buf[53] & 0x01) && buf[68] )
                if ( (buf[53] & 0x01) && buf[68] )
                  timing = ata_calc_pio_timing(buf[68], PIO4_DT1, PIO4_DT2, PIO4_DT4, PIO4_DT2I, PIO4_DT9);
                  timing = ata_calc_pio_timing(buf[68], PIO4_DT1, PIO4_DT2, PIO4_DT4, PIO4_DT2I, PIO4_DT9);
                else
                else
                  timing = ata_calc_pio_timing(PIO4_DT0, PIO4_DT1, PIO4_DT2, PIO4_DT4, PIO4_DT2I, PIO4_DT9);
                  timing = ata_calc_pio_timing(PIO4_DT0, PIO4_DT1, PIO4_DT2, PIO4_DT4, PIO4_DT2I, PIO4_DT9);
                break;
                break;
 
 
              case ARG_PIO3:
              case ARG_PIO3:
                if ( (buf[53] & 0x01) && buf[68] )
                if ( (buf[53] & 0x01) && buf[68] )
                  timing = ata_calc_pio_timing(buf[68], PIO3_DT1, PIO3_DT2, PIO3_DT4, PIO3_DT2I, PIO3_DT9);
                  timing = ata_calc_pio_timing(buf[68], PIO3_DT1, PIO3_DT2, PIO3_DT4, PIO3_DT2I, PIO3_DT9);
                else
                else
                  timing = ata_calc_pio_timing(PIO3_DT0, PIO3_DT1, PIO3_DT2, PIO3_DT4, PIO3_DT2I, PIO3_DT9);
                  timing = ata_calc_pio_timing(PIO3_DT0, PIO3_DT1, PIO3_DT2, PIO3_DT4, PIO3_DT2I, PIO3_DT9);
                break;
                break;
 
 
              case ARG_PIO2:
              case ARG_PIO2:
                timing = ata_calc_pio_timing(PIO2_DT0, PIO2_DT1, PIO2_DT2, PIO2_DT4, PIO2_DT2I, PIO2_DT9);
                timing = ata_calc_pio_timing(PIO2_DT0, PIO2_DT1, PIO2_DT2, PIO2_DT4, PIO2_DT2I, PIO2_DT9);
                break;
                break;
 
 
              case ARG_PIO1:
              case ARG_PIO1:
                timing = ata_calc_pio_timing(PIO1_DT0, PIO1_DT1, PIO1_DT2, PIO1_DT4, PIO1_DT2I, PIO1_DT9);
                timing = ata_calc_pio_timing(PIO1_DT0, PIO1_DT1, PIO1_DT2, PIO1_DT4, PIO1_DT2I, PIO1_DT9);
                break;
                break;
 
 
              default: /* PIO mode 0 */
              default: /* PIO mode 0 */
                timing = ata_calc_pio_timing(PIO0_DT0, PIO0_DT1, PIO0_DT2, PIO0_DT4, PIO0_DT2I, PIO0_DT9);
                timing = ata_calc_pio_timing(PIO0_DT0, PIO0_DT1, PIO0_DT2, PIO0_DT4, PIO0_DT2I, PIO0_DT9);
                break;
                break;
            }
            }
 
 
            /* program data transfer timing registers, set IORDY bit  */
            /* program data transfer timing registers, set IORDY bit  */
            if ( MINOR(inode->i_rdev) )
            if ( MINOR(inode->i_rdev) )
            {
            {
              REG32(base + ATA_PFTR1) = timing;
              REG32(base + ATA_PFTR1) = timing;
 
 
              /* program IORDY bit                                    */
              /* program IORDY bit                                    */
              if ( argument & (ARG_PIO4 | ARG_PIO3) )
              if ( argument & (ARG_PIO4 | ARG_PIO3) )
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
              else
              else
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
            }
            }
            else
            else
            {
            {
              REG32(base + ATA_PFTR0) = timing;
              REG32(base + ATA_PFTR0) = timing;
 
 
              /* program IORDY bit                                    */
              /* program IORDY bit                                    */
              if ( argument & (ARG_PIO4 | ARG_PIO3) )
              if ( argument & (ARG_PIO4 | ARG_PIO3) )
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) |= ATA_IORDY_FTE1;
              else
              else
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
                REG32(base + ATA_CTRL) &= ~ATA_IORDY_FTE1;
            }
            }
 
 
            /* enable data transfer timing                            */
            /* enable data transfer timing                            */
            ata_ioctl(inode, filp, ATA_IOCTL_SET_FTE, 1);
            ata_ioctl(inode, filp, ATA_IOCTL_SET_FTE, 1);
          }
          }
 
 
          return 0;
          return 0;
        }
        }
 
 
 
 
        case ATA_IOCTL_SET_RST:
        case ATA_IOCTL_SET_RST:
        /* sets or clears reset bits                                  */
        /* sets or clears reset bits                                  */
          if (argument & SET)
          if (argument & SET)
            switch (argument & ~SET) {
            switch (argument & ~SET) {
                case ARG_HW_RST:  /* ata hardware reset               */
                case ARG_HW_RST:  /* ata hardware reset               */
                    REG32(base + ATA_CTRL) |= ATA_RST;
                    REG32(base + ATA_CTRL) |= ATA_RST;
                    return 0;
                    return 0;
 
 
                case ARG_SW_RST:  /* ata software reset               */
                case ARG_SW_RST:  /* ata software reset               */
                    REG32(base + ATA_DCR) |= ATA_DCR_RST;
                    REG32(base + ATA_DCR) |= ATA_DCR_RST;
                    return 0;
                    return 0;
 
 
                case ARG_DEV_RST: /* ata device reset                 */
                case ARG_DEV_RST: /* ata device reset                 */
                    REG32(base + ATA_CR) = DEVICE_RESET;
                    REG32(base + ATA_CR) = DEVICE_RESET;
                    return 0;
                    return 0;
 
 
                default:
                default:
                    return EIOCTLIARG;
                    return EIOCTLIARG;
            }
            }
          else
          else
          {
          {
            switch(argument & ~SET) {
            switch(argument & ~SET) {
                case ARG_HW_RST:  /* ata hardware reset               */
                case ARG_HW_RST:  /* ata hardware reset               */
                    REG32(base + ATA_CTRL) &= ~ATA_RST;
                    REG32(base + ATA_CTRL) &= ~ATA_RST;
                    return 0;
                    return 0;
 
 
                case ARG_SW_RST:  /* ata software reset               */
                case ARG_SW_RST:  /* ata software reset               */
                    REG32(base + ATA_DCR) &= ~ATA_DCR_RST;
                    REG32(base + ATA_DCR) &= ~ATA_DCR_RST;
                    return 0;
                    return 0;
 
 
                case ARG_DEV_RST: /* ata device reset                 */
                case ARG_DEV_RST: /* ata device reset                 */
                    return 0;
                    return 0;
 
 
                default:
                default:
                    return EIOCTLIARG;
                    return EIOCTLIARG;
            }
            }
          }
          }
 
 
 
 
        default:
        default:
            printf( "FIXME: Unsupported IOCTL call %1d\n", command );
            printf( "FIXME: Unsupported IOCTL call %1d\n", command );
            return EINVAL;
            return EINVAL;
    }
    }
}
}
 
 
 
 
unsigned long ata_calc_pio_timing(short t0, short t1, short t2, short t4, short t2i, short t9)
unsigned long ata_calc_pio_timing(short t0, short t1, short t2, short t4, short t2i, short t9)
{
{
    int teoc;
    int teoc;
 
 
    teoc = t0 - t1 - t2;
    teoc = t0 - t1 - t2;
 
 
    if (teoc < 0)
    if (teoc < 0)
      teoc = 0;
      teoc = 0;
 
 
    if (t9 > teoc)
    if (t9 > teoc)
      teoc = t9;
      teoc = t9;
 
 
    if (t2i > teoc)
    if (t2i > teoc)
      teoc = t2i;
      teoc = t2i;
 
 
    t1   = TO_TICKS(t1);
    t1   = TO_TICKS(t1);
    t2   = TO_TICKS(t2);
    t2   = TO_TICKS(t2);
    t4   = TO_TICKS(t4);
    t4   = TO_TICKS(t4);
    teoc = TO_TICKS(teoc);
    teoc = TO_TICKS(teoc);
 
 
    return (teoc << ATA_TEOC) | (t4 << ATA_T4) | (t2 << ATA_T2) | (t1 << ATA_T1);
    return (teoc << ATA_TEOC) | (t4 << ATA_T4) | (t2 << ATA_T2) | (t1 << ATA_T1);
}
}
 
 
 
 
/*
/*
        A T A _ R E Q U E S T
        A T A _ R E Q U E S T
*/
*/
int ata_request(struct inode *inode, struct file *filp, struct request *request)
int ata_request(struct inode *inode, struct file *filp, struct request *request)
{
{
  unsigned int device = MINOR(inode->i_rdev);
  unsigned int device = MINOR(inode->i_rdev);
  unsigned long base = BASE(inode);
  unsigned long base = BASE(inode);
  unsigned int sector_size;
  unsigned int sector_size;
 
 
  /* get the sector size for the current device                       */
  /* get the sector size for the current device                       */
  sector_size = hardsect_size[device] >> 1;
  sector_size = hardsect_size[device] >> 1;
 
 
  /* set the device                                                   */
  /* set the device                                                   */
  ata_ioctl(inode, filp, ATA_IOCTL_SELECT_DEVICE, device);
  ata_ioctl(inode, filp, ATA_IOCTL_SELECT_DEVICE, device);
 
 
  /* get the base address                                             */
  /* get the base address                                             */
  base = BASE(inode);
  base = BASE(inode);
 
 
  switch (request->cmd) {
  switch (request->cmd) {
    case READ:
    case READ:
        {
        {
            register unsigned long i, n;
            register unsigned long i, n;
            register unsigned short rd_data;
            register unsigned short rd_data;
            register char *buf_ptr;
            register char *buf_ptr;
 
 
            /* program ata-device registers                           */
            /* program ata-device registers                           */
            REG32(base + ATA_DHR) = ((request->sector >> 24) & ATA_DHR_H) | ATA_DHR_LBA;
            REG32(base + ATA_DHR) = ((request->sector >> 24) & ATA_DHR_H) | ATA_DHR_LBA;
            REG32(base + ATA_CHR) = (request->sector >> 16) & 0xff;
            REG32(base + ATA_CHR) = (request->sector >> 16) & 0xff;
            REG32(base + ATA_CLR) = (request->sector >> 8) & 0xff;
            REG32(base + ATA_CLR) = (request->sector >> 8) & 0xff;
            REG32(base + ATA_SNR) = request->sector & 0xff;
            REG32(base + ATA_SNR) = request->sector & 0xff;
 
 
            REG32(base + ATA_SCR) = request->nr_sectors;
            REG32(base + ATA_SCR) = request->nr_sectors;
 
 
            /* send 'read_sector(s)' command                          */
            /* send 'read_sector(s)' command                          */
            REG32(base + ATA_CR) = READ_SECTORS;
            REG32(base + ATA_CR) = READ_SECTORS;
 
 
            /* check status & error registers                         */
            /* check status & error registers                         */
            if ( ata_astatus(base) & ATA_SR_ERR)
            if ( ata_astatus(base) & ATA_SR_ERR)
                return -1;
                return -1;
 
 
            /* read data from devices and store it in the buffer      */
            /* read data from devices and store it in the buffer      */
            buf_ptr = request->buffer;
            buf_ptr = request->buffer;
 
 
            for (n=0; n < request->nr_sectors; n++)
            for (n=0; n < request->nr_sectors; n++)
            for (i=0; i < sector_size; i++)
            for (i=0; i < sector_size; i++)
            {
            {
                rd_data = ata_read_dport(base);
                rd_data = ata_read_dport(base);
 
 
                /* the data is byte reversed, swap high & low bytes   */
                /* the data is byte reversed, swap high & low bytes   */
                *buf_ptr++ = rd_data;
                *buf_ptr++ = rd_data;
                *buf_ptr++ = rd_data >> 8;
                *buf_ptr++ = rd_data >> 8;
            }
            }
 
 
            return 0;
            return 0;
    }
    }
 
 
 
 
    case WRITE:
    case WRITE:
        /* check if device may be written to                          */
        /* check if device may be written to                          */
        if (filp->f_mode & FMODE_WRITE)
        if (filp->f_mode & FMODE_WRITE)
        {
        {
          /* do the write stuff */
          /* do the write stuff */
        }
        }
        else
        else
          return EINVAL;
          return EINVAL;
 
 
 
 
    default:
    default:
       return EINVAL;
       return EINVAL;
  }
  }
 
 
  return 0;
  return 0;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.