ide: Remove last ide fragments.
* Missed in previous commit.
This commit is contained in:
@@ -1,200 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2005-2007, Axel Dörfler, [email protected]. All rights reserved.
|
|
||||||
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
|
|
||||||
*
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
#ifndef _IDE_PCI_H
|
|
||||||
#define _IDE_PCI_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
IDE adapter library
|
|
||||||
|
|
||||||
Module to simplify writing an IDE adapter driver.
|
|
||||||
|
|
||||||
The interface is not very abstract, i.e. the actual driver is
|
|
||||||
free to access any controller or channel data of this library.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <bus/PCI.h>
|
|
||||||
#include <bus/IDE.h>
|
|
||||||
#include <ide_types.h>
|
|
||||||
#include <device_manager.h>
|
|
||||||
|
|
||||||
|
|
||||||
// one Physical Region Descriptor (PRD)
|
|
||||||
// (one region must not cross 64K boundary;
|
|
||||||
// the PRD table must not cross a 64K boundary)
|
|
||||||
typedef struct prd_entry {
|
|
||||||
uint32 address; // physical address of block (must be even)
|
|
||||||
uint16 count; // size of block, 0 stands for 65536 (must be even)
|
|
||||||
uint8 res6;
|
|
||||||
LBITFIELD8_2(
|
|
||||||
res7_0 : 7,
|
|
||||||
EOT : 1 // 1 for last entry
|
|
||||||
);
|
|
||||||
} prd_entry;
|
|
||||||
|
|
||||||
// IDE bus master command register
|
|
||||||
#define IDE_BM_COMMAND_START_STOP 0x01
|
|
||||||
#define IDE_BM_COMMAND_READ_FROM_DEVICE 0x08
|
|
||||||
|
|
||||||
// IDE bus master status register
|
|
||||||
#define IDE_BM_STATUS_ACTIVE 0x01
|
|
||||||
#define IDE_BM_STATUS_ERROR 0x02
|
|
||||||
#define IDE_BM_STATUS_INTERRUPT 0x04
|
|
||||||
#define IDE_BM_STATUS_MASTER_DMA 0x20
|
|
||||||
#define IDE_BM_STATUS_SLAVE_DMA 0x40
|
|
||||||
#define IDE_BM_STATUS_SIMPLEX_DMA 0x80
|
|
||||||
|
|
||||||
// offset of bus master registers
|
|
||||||
enum {
|
|
||||||
IDE_BM_COMMAND_REG = 0,
|
|
||||||
IDE_BM_STATUS_REG = 2,
|
|
||||||
IDE_BM_PRDT_ADDRESS = 4
|
|
||||||
// offset of PRDT register; content must be dword-aligned
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// (maximum) size of S/G table
|
|
||||||
// there are so many restrictions that we want to keep it inside one page
|
|
||||||
// to be sure that we fulfill them all
|
|
||||||
#define IDE_ADAPTER_MAX_SG_COUNT (B_PAGE_SIZE / sizeof( prd_entry ))
|
|
||||||
|
|
||||||
|
|
||||||
// channel node items
|
|
||||||
// io address of command block (uint16)
|
|
||||||
#define IDE_ADAPTER_COMMAND_BLOCK_BASE "ide_adapter/command_block_base"
|
|
||||||
// io address of control block (uint16)
|
|
||||||
#define IDE_ADAPTER_CONTROL_BLOCK_BASE "ide_adapter/control_block_base"
|
|
||||||
// interrupt number (uint8)
|
|
||||||
// can also be defined in controller node if both channels use same IRQ!
|
|
||||||
#define IDE_ADAPTER_INTNUM "ide_adapter/irq"
|
|
||||||
// 0 if primary channel, 1 if secondary channel, 2 if tertiary, ... (uint8)
|
|
||||||
#define IDE_ADAPTER_CHANNEL_INDEX "ide_adapter/channel_index"
|
|
||||||
|
|
||||||
// controller node items
|
|
||||||
// io address of bus master registers (uint16)
|
|
||||||
#define IDE_ADAPTER_BUS_MASTER_BASE "ide_adapter/bus_master_base"
|
|
||||||
|
|
||||||
|
|
||||||
// info about one channel
|
|
||||||
typedef struct ide_adapter_channel_info {
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
|
|
||||||
uint16 command_block_base; // io address command block
|
|
||||||
uint16 control_block_base; // io address control block
|
|
||||||
uint16 bus_master_base;
|
|
||||||
int intnum; // interrupt number
|
|
||||||
|
|
||||||
uint32 lost; // != 0 if device got removed, i.e. if it must not
|
|
||||||
// be accessed anymore
|
|
||||||
|
|
||||||
ide_channel ideChannel;
|
|
||||||
device_node *node;
|
|
||||||
|
|
||||||
int32 (*inthand)( void *arg );
|
|
||||||
|
|
||||||
area_id prd_area;
|
|
||||||
prd_entry *prdt;
|
|
||||||
uint32 prdt_phys;
|
|
||||||
uint32 dmaing;
|
|
||||||
} ide_adapter_channel_info;
|
|
||||||
|
|
||||||
|
|
||||||
// info about controller
|
|
||||||
typedef struct ide_adapter_controller_info {
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
|
|
||||||
uint16 bus_master_base;
|
|
||||||
|
|
||||||
uint32 lost; // != 0 if device got removed, i.e. if it must not
|
|
||||||
// be accessed anymore
|
|
||||||
|
|
||||||
device_node *node;
|
|
||||||
} ide_adapter_controller_info;
|
|
||||||
|
|
||||||
|
|
||||||
// interface of IDE adapter library
|
|
||||||
typedef struct {
|
|
||||||
module_info info;
|
|
||||||
|
|
||||||
void (*set_channel)(ide_adapter_channel_info *channel,
|
|
||||||
ide_channel ideChannel);
|
|
||||||
|
|
||||||
// function calls that can be forwarded from actual driver
|
|
||||||
status_t (*write_command_block_regs)(ide_adapter_channel_info *channel,
|
|
||||||
ide_task_file *tf, ide_reg_mask mask);
|
|
||||||
status_t (*read_command_block_regs)(ide_adapter_channel_info *channel,
|
|
||||||
ide_task_file *tf, ide_reg_mask mask);
|
|
||||||
|
|
||||||
uint8 (*get_altstatus) (ide_adapter_channel_info *channel);
|
|
||||||
status_t (*write_device_control) (ide_adapter_channel_info *channel, uint8 val);
|
|
||||||
|
|
||||||
status_t (*write_pio)(ide_adapter_channel_info *channel, uint16 *data, int count, bool force_16bit);
|
|
||||||
status_t (*read_pio)(ide_adapter_channel_info *channel, uint16 *data, int count, bool force_16bit);
|
|
||||||
|
|
||||||
status_t (*prepare_dma)(ide_adapter_channel_info *channel, const physical_entry *sg_list,
|
|
||||||
size_t sg_list_count, bool to_device);
|
|
||||||
status_t (*start_dma)(ide_adapter_channel_info *channel);
|
|
||||||
status_t (*finish_dma)(ide_adapter_channel_info *channel);
|
|
||||||
|
|
||||||
// default functions that should be replaced by a more specific version
|
|
||||||
// (copy them from source code of this library and modify them at will)
|
|
||||||
int32 (*inthand)(void *arg);
|
|
||||||
|
|
||||||
// functions that must be called by init/uninit etc. of channel driver
|
|
||||||
status_t (*init_channel)(device_node *node,
|
|
||||||
ide_adapter_channel_info **cookie, size_t total_data_size,
|
|
||||||
int32 (*inthand)(void *arg));
|
|
||||||
void (*uninit_channel)(ide_adapter_channel_info *channel);
|
|
||||||
void (*channel_removed)(ide_adapter_channel_info *channel);
|
|
||||||
|
|
||||||
// publish channel node
|
|
||||||
status_t (*publish_channel)(device_node *controller_node,
|
|
||||||
const char *channel_module_name, uint16 command_block_base,
|
|
||||||
uint16 control_block_base, uint8 intnum, bool can_dma,
|
|
||||||
uint8 channel_index, const char *name,
|
|
||||||
const io_resource *resources, device_node **node);
|
|
||||||
// verify channel configuration and publish node on success
|
|
||||||
status_t (*detect_channel)(pci_device_module_info *pci, pci_device *pciDevice,
|
|
||||||
device_node *controller_node, const char *channel_module_name,
|
|
||||||
bool controller_can_dma, uint16 command_block_base,
|
|
||||||
uint16 control_block_base, uint16 bus_master_base,
|
|
||||||
uint8 intnum, uint8 channel_index, const char *name,
|
|
||||||
device_node **node, bool supports_compatibility_mode);
|
|
||||||
|
|
||||||
// functions that must be called by init/uninit etc. of controller driver
|
|
||||||
status_t (*init_controller)(device_node *node,
|
|
||||||
ide_adapter_controller_info **cookie, size_t total_data_size);
|
|
||||||
void (*uninit_controller)(ide_adapter_controller_info *controller);
|
|
||||||
void (*controller_removed)(ide_adapter_controller_info *controller);
|
|
||||||
|
|
||||||
// publish controller node
|
|
||||||
status_t (*publish_controller)(device_node *parent, uint16 bus_master_base,
|
|
||||||
io_resource *resources, const char *controller_driver,
|
|
||||||
const char *controller_driver_type, const char *controller_name,
|
|
||||||
bool can_dma, bool can_cq, uint32 dma_alignment, uint32 dma_boundary,
|
|
||||||
uint32 max_sg_block_size, device_node **node);
|
|
||||||
// verify controller configuration and publish node on success
|
|
||||||
status_t (*detect_controller)(pci_device_module_info *pci, pci_device *pciDevice,
|
|
||||||
device_node *parent, uint16 bus_master_base,
|
|
||||||
const char *controller_driver, const char *controller_driver_type,
|
|
||||||
const char *controller_name, bool can_dma, bool can_cq,
|
|
||||||
uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
|
|
||||||
device_node **node);
|
|
||||||
// standard master probe for controller that registers controller and channel nodes
|
|
||||||
status_t (*probe_controller)(device_node *parent, const char *controller_driver,
|
|
||||||
const char *controller_driver_type, const char *controller_name,
|
|
||||||
const char *channel_module_name, bool can_dma, bool can_cq,
|
|
||||||
uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
|
|
||||||
bool supports_compatibility_mode);
|
|
||||||
} ide_adapter_interface;
|
|
||||||
|
|
||||||
|
|
||||||
#define IDE_ADAPTER_MODULE_NAME "generic/ide_adapter/v1"
|
|
||||||
|
|
||||||
#endif /* _IDE_PCI_H */
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
#ifndef __IDE_TYPES_H__
|
|
||||||
#define __IDE_TYPES_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include <iovec.h>
|
|
||||||
#include <lendian_bitfield.h>
|
|
||||||
|
|
||||||
|
|
||||||
// IDE task file.
|
|
||||||
// contains the command block interpreted under different conditions with
|
|
||||||
// first byte being first command register, second byte second command register
|
|
||||||
// etc.; for lba48, registers must be written twice, therefore there
|
|
||||||
// are twice as many bytes as registers - the first eight bytes are those
|
|
||||||
// that must be written first, the second eight bytes are those that
|
|
||||||
// must be written second.
|
|
||||||
union ide_task_file {
|
|
||||||
struct {
|
|
||||||
uint8 features;
|
|
||||||
uint8 sector_count;
|
|
||||||
uint8 sector_number;
|
|
||||||
uint8 cylinder_0_7;
|
|
||||||
uint8 cylinder_8_15;
|
|
||||||
LBITFIELD8_3(
|
|
||||||
head : 4,
|
|
||||||
device : 1,
|
|
||||||
mode : 3
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
} chs;
|
|
||||||
struct {
|
|
||||||
uint8 features;
|
|
||||||
uint8 sector_count;
|
|
||||||
uint8 lba_0_7;
|
|
||||||
uint8 lba_8_15;
|
|
||||||
uint8 lba_16_23;
|
|
||||||
LBITFIELD8_3(
|
|
||||||
lba_24_27 : 4,
|
|
||||||
device : 1,
|
|
||||||
mode : 3
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
} lba;
|
|
||||||
struct {
|
|
||||||
LBITFIELD8_3(
|
|
||||||
dma : 1,
|
|
||||||
ovl : 1,
|
|
||||||
_0_res2 : 6
|
|
||||||
);
|
|
||||||
LBITFIELD8_2(
|
|
||||||
_1_res0 : 3,
|
|
||||||
tag : 5
|
|
||||||
);
|
|
||||||
uint8 _2_res;
|
|
||||||
uint8 byte_count_0_7;
|
|
||||||
uint8 byte_count_8_15;
|
|
||||||
LBITFIELD8_6(
|
|
||||||
lun : 3,
|
|
||||||
_5_res3 : 1,
|
|
||||||
device : 1,
|
|
||||||
_5_one5 : 1,
|
|
||||||
_5_res6 : 1,
|
|
||||||
_5_one7 : 1
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
} packet;
|
|
||||||
struct {
|
|
||||||
LBITFIELD8_5(
|
|
||||||
ili : 1,
|
|
||||||
eom : 1,
|
|
||||||
abrt : 1,
|
|
||||||
_0_res3 : 1,
|
|
||||||
sense_key : 4
|
|
||||||
);
|
|
||||||
LBITFIELD8_4(
|
|
||||||
cmd_or_data : 1, // 1 - cmd, 0 - data
|
|
||||||
input_or_output : 1, // 0 - input (to device), 1 - output
|
|
||||||
release : 1,
|
|
||||||
tag : 5
|
|
||||||
);
|
|
||||||
uint8 _2_res;
|
|
||||||
uint8 byte_count_0_7;
|
|
||||||
uint8 byte_count_8_15;
|
|
||||||
LBITFIELD8_5(
|
|
||||||
_4_res0 : 4,
|
|
||||||
device : 1,
|
|
||||||
_4_obs5 : 1,
|
|
||||||
_4_res6 : 1,
|
|
||||||
_4_obs7 : 1
|
|
||||||
);
|
|
||||||
LBITFIELD8_7(
|
|
||||||
chk : 1,
|
|
||||||
_7_res1 : 2,
|
|
||||||
drq : 1,
|
|
||||||
serv : 1,
|
|
||||||
dmrd : 1,
|
|
||||||
drdy : 1,
|
|
||||||
bsy : 1
|
|
||||||
);
|
|
||||||
} packet_res;
|
|
||||||
struct {
|
|
||||||
uint8 sector_count;
|
|
||||||
LBITFIELD8_4( // only <tag> is defined for write
|
|
||||||
cmd_or_data : 1, // 1 - cmd, 0 - data
|
|
||||||
input_or_output : 1, // 0 - input (to device), 1 - output
|
|
||||||
release : 1,
|
|
||||||
tag : 5
|
|
||||||
);
|
|
||||||
uint8 lba_0_7;
|
|
||||||
uint8 lba_8_15;
|
|
||||||
uint8 lba_16_23;
|
|
||||||
LBITFIELD8_3(
|
|
||||||
lba_24_27 : 4,
|
|
||||||
device : 1,
|
|
||||||
mode : 3
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
} queued;
|
|
||||||
struct {
|
|
||||||
// low order bytes
|
|
||||||
uint8 features;
|
|
||||||
uint8 sector_count_0_7;
|
|
||||||
uint8 lba_0_7;
|
|
||||||
uint8 lba_8_15;
|
|
||||||
uint8 lba_16_23;
|
|
||||||
LBITFIELD8_3(
|
|
||||||
_5low_res0 : 4,
|
|
||||||
device : 1,
|
|
||||||
mode : 3
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
|
|
||||||
// high order bytes
|
|
||||||
uint8 _0high_res;
|
|
||||||
uint8 sector_count_8_15;
|
|
||||||
uint8 lba_24_31;
|
|
||||||
uint8 lba_32_39;
|
|
||||||
uint8 lba_40_47;
|
|
||||||
} lba48;
|
|
||||||
struct {
|
|
||||||
// low order bytes
|
|
||||||
uint8 sector_count_0_7;
|
|
||||||
LBITFIELD8_4(
|
|
||||||
cmd_or_data : 1, // 1 - cmd, 0 - data
|
|
||||||
input_or_output : 1, // 0 - input (to device), 1 - output
|
|
||||||
release : 1,
|
|
||||||
tag : 5
|
|
||||||
);
|
|
||||||
uint8 lba_0_7;
|
|
||||||
uint8 lba_8_15;
|
|
||||||
uint8 lba_16_23;
|
|
||||||
LBITFIELD8_3(
|
|
||||||
_5low_res0 : 4,
|
|
||||||
device : 1,
|
|
||||||
mode : 3
|
|
||||||
);
|
|
||||||
uint8 command;
|
|
||||||
|
|
||||||
// high order bytes
|
|
||||||
uint8 sector_count_8_15;
|
|
||||||
uint8 _1high_res;
|
|
||||||
uint8 lba_24_31;
|
|
||||||
uint8 lba_32_39;
|
|
||||||
uint8 lba_40_47;
|
|
||||||
} queued48;
|
|
||||||
struct {
|
|
||||||
uint8 _0_res[3];
|
|
||||||
uint8 ver; // RMSN version
|
|
||||||
LBITFIELD8_3(
|
|
||||||
pena : 1, // previously enabled
|
|
||||||
lock : 1, // capable of locking
|
|
||||||
pej : 1 // can physically eject
|
|
||||||
);
|
|
||||||
} set_MSN_res;
|
|
||||||
struct {
|
|
||||||
uint8 r[7+5];
|
|
||||||
} raw;
|
|
||||||
struct {
|
|
||||||
uint8 features;
|
|
||||||
uint8 sector_count;
|
|
||||||
uint8 sector_number;
|
|
||||||
uint8 cylinder_low;
|
|
||||||
uint8 cylinder_high;
|
|
||||||
uint8 device_head;
|
|
||||||
uint8 command;
|
|
||||||
} write;
|
|
||||||
struct {
|
|
||||||
uint8 error;
|
|
||||||
uint8 sector_count;
|
|
||||||
uint8 sector_number;
|
|
||||||
uint8 cylinder_low;
|
|
||||||
uint8 cylinder_high;
|
|
||||||
uint8 device_head;
|
|
||||||
uint8 status;
|
|
||||||
} read;
|
|
||||||
};
|
|
||||||
typedef union ide_task_file ide_task_file;
|
|
||||||
|
|
||||||
// content of "mode" field
|
|
||||||
enum {
|
|
||||||
ide_mode_chs = 5,
|
|
||||||
ide_mode_lba = 7
|
|
||||||
};
|
|
||||||
|
|
||||||
// mask for ide_task_file fields to be written
|
|
||||||
enum {
|
|
||||||
ide_mask_features = 0x01,
|
|
||||||
ide_mask_sector_count = 0x02,
|
|
||||||
|
|
||||||
// CHS
|
|
||||||
ide_mask_sector_number = 0x04,
|
|
||||||
ide_mask_cylinder_low = 0x08,
|
|
||||||
ide_mask_cylinder_high = 0x10,
|
|
||||||
|
|
||||||
// LBA
|
|
||||||
ide_mask_LBA_low = 0x04,
|
|
||||||
ide_mask_LBA_mid = 0x08,
|
|
||||||
ide_mask_LBA_high = 0x10,
|
|
||||||
|
|
||||||
// packet
|
|
||||||
ide_mask_byte_count = 0x18,
|
|
||||||
|
|
||||||
// packet and dma queued result
|
|
||||||
ide_mask_error = 0x01,
|
|
||||||
ide_mask_ireason = 0x02,
|
|
||||||
|
|
||||||
ide_mask_device_head = 0x20,
|
|
||||||
ide_mask_command = 0x40,
|
|
||||||
|
|
||||||
ide_mask_status = 0x40,
|
|
||||||
|
|
||||||
// for 48 bits, the following flags tell which registers to load twice
|
|
||||||
ide_mask_features_48 = 0x80 | ide_mask_features,
|
|
||||||
ide_mask_sector_count_48 = 0x100 | ide_mask_sector_count,
|
|
||||||
ide_mask_LBA_low_48 = 0x200 | ide_mask_LBA_low,
|
|
||||||
ide_mask_LBA_mid_48 = 0x400 | ide_mask_LBA_mid,
|
|
||||||
ide_mask_LBA_high_48 = 0x800 | ide_mask_LBA_high,
|
|
||||||
|
|
||||||
ide_mask_HOB = 0xf80
|
|
||||||
}; // ide_reg_mask
|
|
||||||
|
|
||||||
// status register
|
|
||||||
enum {
|
|
||||||
ide_status_err = 0x01, // error
|
|
||||||
ide_status_index = 0x02, // obsolete
|
|
||||||
ide_status_corr = 0x04, // obsolete
|
|
||||||
ide_status_drq = 0x08, // data request
|
|
||||||
ide_status_dsc = 0x10, // reserved
|
|
||||||
ide_status_service = 0x10, // ready to service device
|
|
||||||
ide_status_dwf = 0x20, // reserved
|
|
||||||
ide_status_dma = 0x20, // reserved
|
|
||||||
ide_status_dmrd = 0x20, // packet: DMA ready
|
|
||||||
ide_status_df = 0x20, // packet: disk failure
|
|
||||||
ide_status_drdy = 0x40, // device ready
|
|
||||||
ide_status_bsy = 0x80 // busy
|
|
||||||
}; // ide_status_mask
|
|
||||||
|
|
||||||
// device control register
|
|
||||||
enum {
|
|
||||||
// bit 0 must be zero
|
|
||||||
ide_devctrl_nien = 0x02, // disable INTRQ
|
|
||||||
ide_devctrl_srst = 0x04, // software device reset
|
|
||||||
ide_devctrl_bit3 = 0x08, // don't know, but must be set
|
|
||||||
// bits inbetween are reserved
|
|
||||||
ide_devctrl_hob = 0x80 // read high order byte (for 48-bit lba)
|
|
||||||
}; // ide_devcntrl_mask
|
|
||||||
|
|
||||||
// error register - most bits are command specific
|
|
||||||
enum {
|
|
||||||
// always used
|
|
||||||
ide_error_abrt = 0x04, // command aborted
|
|
||||||
|
|
||||||
// used for Ultra DMA modes
|
|
||||||
ide_error_icrc = 0x80, // interface CRC error
|
|
||||||
|
|
||||||
// used by reading data transfers
|
|
||||||
ide_error_unc = 0x40, // uncorrectable data error
|
|
||||||
// used by writing data transfers
|
|
||||||
ide_error_wp = 0x40, // media write protect
|
|
||||||
|
|
||||||
// used by all data transfer commands
|
|
||||||
ide_error_mc = 0x20, // medium changed
|
|
||||||
ide_error_idnf = 0x10, // CHS translation not init./ invalid CHS address
|
|
||||||
ide_error_mcr = 0x08, // media change requested
|
|
||||||
ide_error_nm = 0x02, // no media (for removable media devices)
|
|
||||||
}; // ide_error_mask
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct ide_channel_info *ide_channel_cookie;
|
|
||||||
|
|
||||||
#endif /* __IDE_H__ */
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide ;
|
|
||||||
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide generic_ide_pci ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide ide_isa ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide it8211 ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide promise_tx2 ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide silicon_image_3112 ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel busses ide legacy_sata ;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide generic_ide_pci ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
KernelAddon generic_ide_pci :
|
|
||||||
generic_ide_pci.c
|
|
||||||
;
|
|
||||||
@@ -1,247 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*! Generic PCI bus mastering IDE driver. */
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <ide_adapter.h>
|
|
||||||
|
|
||||||
#define GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME "busses/ide/generic_ide_pci/driver_v1"
|
|
||||||
#define GENERIC_IDE_PCI_CHANNEL_MODULE_NAME "busses/ide/generic_ide_pci/channel/v1"
|
|
||||||
|
|
||||||
#define IDE_PCI_CONTROLLER_TYPE_NAME "ide pci controller"
|
|
||||||
|
|
||||||
ide_for_controller_interface *ide;
|
|
||||||
static ide_adapter_interface *ide_adapter;
|
|
||||||
device_manager_info *pnp;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_channel(void *cookie, ide_channel channel)
|
|
||||||
{
|
|
||||||
ide_adapter->set_channel((ide_adapter_channel_info *)cookie, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_command_block_regs(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_command_block_regs((ide_adapter_channel_info *)channel_cookie, tf, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_command_block_regs(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_command_block_regs((ide_adapter_channel_info *)channel_cookie, tf, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
get_altstatus(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->get_altstatus((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_device_control(void *channel_cookie, uint8 val)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_device_control((ide_adapter_channel_info *)channel_cookie, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_pio((ide_adapter_channel_info *)channel_cookie, data, count, force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_pio((ide_adapter_channel_info *)channel_cookie, data, count, force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
prepare_dma(void *channel_cookie,
|
|
||||||
const physical_entry *sg_list, size_t sg_list_count,
|
|
||||||
bool to_device)
|
|
||||||
{
|
|
||||||
return ide_adapter->prepare_dma((ide_adapter_channel_info *)channel_cookie, sg_list, sg_list_count, to_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
start_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->start_dma((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
finish_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->finish_dma((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_channel(device_node *node, void **channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_channel(node,
|
|
||||||
(ide_adapter_channel_info **)channel_cookie,
|
|
||||||
sizeof(ide_adapter_channel_info), ide_adapter->inthand);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninit_channel(void *channel_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->uninit_channel((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_removed(void *channel_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->channel_removed((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_controller(device_node *node, ide_adapter_controller_info **cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_controller(node, cookie,
|
|
||||||
sizeof( ide_adapter_controller_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninit_controller(ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
ide_adapter->uninit_controller(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_removed(ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
return ide_adapter->controller_removed(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
probe_controller(device_node *parent)
|
|
||||||
{
|
|
||||||
return ide_adapter->probe_controller(parent,
|
|
||||||
GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME, "generic_ide_pci",
|
|
||||||
"Generic IDE PCI Controller",
|
|
||||||
GENERIC_IDE_PCI_CHANNEL_MODULE_NAME,
|
|
||||||
true,
|
|
||||||
true, // assume that command queuing works
|
|
||||||
1, // assume 16 bit alignment is enough
|
|
||||||
0xffff, // boundary is on 64k according to spec
|
|
||||||
0x10000, // up to 64k per S/G block according to spec
|
|
||||||
true); // by default, compatibility mode is used
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
supports_device(device_node *parent)
|
|
||||||
{
|
|
||||||
const char *bus;
|
|
||||||
uint16 baseClass, subClass;
|
|
||||||
|
|
||||||
// make sure parent is an PCI IDE mass storage host adapter device node
|
|
||||||
if (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint16(parent, B_DEVICE_TYPE, &baseClass, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subClass, false) != B_OK)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (strcmp(bus, "pci") || baseClass != PCI_mass_storage)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
if (subClass == PCI_ide)
|
|
||||||
return 0.3f;
|
|
||||||
|
|
||||||
// vendor 105a: Promise Technology, Inc.; device 4d69: 20269 (Ultra133TX2)
|
|
||||||
// has subClass set to PCI_mass_storage_other, and there are others as well.
|
|
||||||
if (subClass == PCI_mass_storage_other)
|
|
||||||
return 0.3f;
|
|
||||||
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// exported interface
|
|
||||||
static ide_controller_interface channel_interface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
GENERIC_IDE_PCI_CHANNEL_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
NULL, // supports device
|
|
||||||
NULL, // register device
|
|
||||||
init_channel,
|
|
||||||
uninit_channel,
|
|
||||||
NULL, // register child devices
|
|
||||||
NULL, // rescan
|
|
||||||
channel_removed,
|
|
||||||
},
|
|
||||||
|
|
||||||
&set_channel,
|
|
||||||
|
|
||||||
&write_command_block_regs,
|
|
||||||
&read_command_block_regs,
|
|
||||||
|
|
||||||
&get_altstatus,
|
|
||||||
&write_device_control,
|
|
||||||
|
|
||||||
&write_pio,
|
|
||||||
&read_pio,
|
|
||||||
|
|
||||||
&prepare_dma,
|
|
||||||
&start_dma,
|
|
||||||
&finish_dma,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static driver_module_info controller_interface = {
|
|
||||||
{
|
|
||||||
GENERIC_IDE_PCI_CONTROLLER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
supports_device,
|
|
||||||
probe_controller,
|
|
||||||
(status_t (*)(device_node *, void **)) init_controller,
|
|
||||||
(void (*)(void *)) uninit_controller,
|
|
||||||
NULL, // register child devices
|
|
||||||
NULL, // rescan
|
|
||||||
(void (*)(void *)) controller_removed,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&controller_interface,
|
|
||||||
(module_info *)&channel_interface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide ide_isa ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
# disable debug output, if debugging is disabled
|
|
||||||
if $(DEBUG) = 0 {
|
|
||||||
SubDirCcFlags [ FDefines DEBUG_MAX_LEVEL_FLOW=0 DEBUG_MAX_LEVEL_INFO=0 ] ;
|
|
||||||
}
|
|
||||||
|
|
||||||
KernelAddon ide_isa :
|
|
||||||
ide_isa.c
|
|
||||||
;
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002/03, Thomas Kurschel. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
IDE ISA controller driver
|
|
||||||
|
|
||||||
This is a testing-only driver. In reality, you want to use
|
|
||||||
the IDE PCI controller driver, but at least under Bochs, there's not
|
|
||||||
much choice as PCI support is very limited there.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <bus/ISA.h>
|
|
||||||
#include <bus/IDE.h>
|
|
||||||
#include <ide_types.h>
|
|
||||||
#include <device_manager.h>
|
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_IDE_ISA
|
|
||||||
#ifdef TRACE_IDE_ISA
|
|
||||||
# define TRACE(x...) dprintf("ide_isa: " x)
|
|
||||||
#else
|
|
||||||
# define TRACE(x...) ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define IDE_ISA_MODULE_NAME "busses/ide/ide_isa/driver_v1"
|
|
||||||
|
|
||||||
// private node item:
|
|
||||||
// io address of command block
|
|
||||||
#define IDE_ISA_COMMAND_BLOCK_BASE "ide_isa/command_block_base"
|
|
||||||
// io address of control block
|
|
||||||
#define IDE_ISA_CONTROL_BLOCK_BASE "ide_isa/control_block_base"
|
|
||||||
// interrupt number
|
|
||||||
#define IDE_ISA_INTNUM "ide_isa/irq"
|
|
||||||
|
|
||||||
|
|
||||||
ide_for_controller_interface *ide;
|
|
||||||
device_manager_info *pnp;
|
|
||||||
|
|
||||||
|
|
||||||
// info about one channel
|
|
||||||
typedef struct channel_info {
|
|
||||||
isa2_module_info *isa;
|
|
||||||
uint16 command_block_base; // io address command block
|
|
||||||
uint16 control_block_base; // io address control block
|
|
||||||
int intnum; // interrupt number
|
|
||||||
|
|
||||||
uint32 lost; // != 0 if device got removed, i.e. if it must not
|
|
||||||
// be accessed anymore
|
|
||||||
|
|
||||||
ide_channel ide_channel;
|
|
||||||
device_node *node;
|
|
||||||
} channel_info;
|
|
||||||
|
|
||||||
|
|
||||||
/*! publish node of an ide channel */
|
|
||||||
static status_t
|
|
||||||
publish_channel(device_node *parent, uint16 command_block_base,
|
|
||||||
uint16 control_block_base, uint8 intnum, const char *name)
|
|
||||||
{
|
|
||||||
device_attr attrs[] = {
|
|
||||||
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
|
||||||
|
|
||||||
// properties of this controller for ide bus manager
|
|
||||||
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: 0 }},
|
|
||||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: name }},
|
|
||||||
|
|
||||||
// DMA properties; the 16 bit alignment is not necessary as
|
|
||||||
// the ide bus manager handles that very efficiently, but why
|
|
||||||
// not use the block device manager for doing that?
|
|
||||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1 }},
|
|
||||||
{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
|
|
||||||
|
|
||||||
// private data to identify device
|
|
||||||
{ IDE_ISA_COMMAND_BLOCK_BASE, B_UINT16_TYPE, { ui16: command_block_base }},
|
|
||||||
{ IDE_ISA_CONTROL_BLOCK_BASE, B_UINT16_TYPE, { ui16: control_block_base }},
|
|
||||||
{ IDE_ISA_INTNUM, B_UINT8_TYPE, { ui8: intnum }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
io_resource resources[3] = {
|
|
||||||
{ B_IO_PORT, command_block_base, 8 },
|
|
||||||
{ B_IO_PORT, control_block_base, 1 },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
TRACE("publishing %s, resources %#x %#x %d\n",
|
|
||||||
name, command_block_base, control_block_base, intnum);
|
|
||||||
|
|
||||||
return pnp->register_node(parent, IDE_ISA_MODULE_NAME, attrs, resources,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_channel(void *cookie, ide_channel ideChannel)
|
|
||||||
{
|
|
||||||
channel_info *channel = cookie;
|
|
||||||
channel->ide_channel = ideChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_command_block_regs(void *channel_cookie, ide_task_file *tf,
|
|
||||||
ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
if (((1 << (i + 7)) & mask) != 0) {
|
|
||||||
TRACE("write_command_block_regs(): %x->HI(%x)\n",
|
|
||||||
tf->raw.r[i + 7], i);
|
|
||||||
channel->isa->write_io_8(ioaddr + 1 + i, tf->raw.r[i + 7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((1 << i) & mask) != 0 ) {
|
|
||||||
TRACE("write_comamnd_block_regs(): %x->LO(%x)\n", tf->raw.r[i], i);
|
|
||||||
channel->isa->write_io_8(ioaddr + 1 + i, tf->raw.r[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_command_block_regs(void *channel_cookie, ide_task_file *tf,
|
|
||||||
ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
if (((1 << i) & mask) != 0) {
|
|
||||||
tf->raw.r[i] = channel->isa->read_io_8(ioaddr + 1 + i);
|
|
||||||
TRACE("read_command_block_regs(%x): %x\n", i, (int)tf->raw.r[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
get_altstatus(void *channel_cookie)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 altstatusaddr = channel->control_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
return channel->isa->read_io_8(altstatusaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_device_control(void *channel_cookie, uint8 val)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 device_control_addr = channel->control_block_base;
|
|
||||||
|
|
||||||
TRACE("write_device_control(%x)\n", (int)val);
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
channel->isa->write_io_8(device_control_addr, val);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_pio_16(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
// Bochs doesn't support 32 bit accesses;
|
|
||||||
// no real performance impact as this driver is for Bochs only anyway
|
|
||||||
force_16bit = true;
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
for (; count > 0; --count)
|
|
||||||
channel->isa->write_io_16(ioaddr, *(data++));
|
|
||||||
} else {
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for (; count > 0; count -= 2)
|
|
||||||
channel->isa->write_io_32(ioaddr, *(cur_data++));
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_pio_16(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
force_16bit = true;
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
for (; count > 0; --count)
|
|
||||||
*(data++) = channel->isa->read_io_16(ioaddr);
|
|
||||||
} else {
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for (; count > 0; count -= 2)
|
|
||||||
*(cur_data++) = channel->isa->read_io_32(ioaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
inthand(void *arg)
|
|
||||||
{
|
|
||||||
channel_info *channel = (channel_info *)arg;
|
|
||||||
uint8 status;
|
|
||||||
|
|
||||||
TRACE("interrupt handler()\n");
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
// acknowledge IRQ
|
|
||||||
status = channel->isa->read_io_8(channel->command_block_base + 7);
|
|
||||||
|
|
||||||
return ide->irq_handler(channel->ide_channel, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
prepare_dma(void *channel_cookie, const physical_entry *sg_list,
|
|
||||||
size_t sg_list_count, bool write)
|
|
||||||
{
|
|
||||||
return B_NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
start_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return B_NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
finish_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return B_NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
supports_device(device_node *parent)
|
|
||||||
{
|
|
||||||
const char *bus;
|
|
||||||
|
|
||||||
// make sure parent is really the ISA bus manager
|
|
||||||
if (pnp->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if (strcmp(bus, "isa"))
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
// we assume that every modern PC has an IDE controller, so no
|
|
||||||
// further testing is done (well - I don't really know how to detect the
|
|
||||||
// controller, but who cares ;)
|
|
||||||
|
|
||||||
return 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_channel(device_node *node, void **_cookie)
|
|
||||||
{
|
|
||||||
channel_info *channel;
|
|
||||||
device_node *parent;
|
|
||||||
isa2_module_info *isa;
|
|
||||||
uint16 command_block_base, control_block_base;
|
|
||||||
uint8 irq;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
TRACE("ISA-IDE: channel init\n");
|
|
||||||
|
|
||||||
// get device data
|
|
||||||
if (pnp->get_attr_uint16(node, IDE_ISA_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint16(node, IDE_ISA_CONTROL_BLOCK_BASE, &control_block_base, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint8(node, IDE_ISA_INTNUM, &irq, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
parent = pnp->get_parent_node(node);
|
|
||||||
pnp->get_driver(parent, (driver_module_info **)&isa, NULL);
|
|
||||||
pnp->put_node(parent);
|
|
||||||
|
|
||||||
channel = (channel_info *)malloc(sizeof(channel_info));
|
|
||||||
if (channel == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
TRACE("ISA-IDE: channel init, resources %#x %#x %d\n",
|
|
||||||
command_block_base, control_block_base, irq);
|
|
||||||
|
|
||||||
channel->isa = isa;
|
|
||||||
channel->node = node;
|
|
||||||
channel->lost = false;
|
|
||||||
channel->command_block_base = command_block_base;
|
|
||||||
channel->control_block_base = control_block_base;
|
|
||||||
channel->intnum = irq;
|
|
||||||
channel->ide_channel = NULL;
|
|
||||||
|
|
||||||
res = install_io_interrupt_handler(channel->intnum,
|
|
||||||
inthand, channel, 0);
|
|
||||||
|
|
||||||
if (res < 0) {
|
|
||||||
TRACE("ISA-IDE: couldn't install irq handler for int %d\n", irq);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable interrupts so the channel is ready to run
|
|
||||||
write_device_control(channel, ide_devctrl_bit3);
|
|
||||||
|
|
||||||
*_cookie = channel;
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
free(channel);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninit_channel(void *channel_cookie)
|
|
||||||
{
|
|
||||||
channel_info *channel = channel_cookie;
|
|
||||||
|
|
||||||
TRACE("ISA-IDE: channel uninit\n");
|
|
||||||
|
|
||||||
// disable IRQs
|
|
||||||
write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien);
|
|
||||||
|
|
||||||
// catch spurious interrupt
|
|
||||||
// (some controllers generate an IRQ when you _disable_ interrupts,
|
|
||||||
// they are delayed by less then 40 µs, so 1 ms is safe)
|
|
||||||
snooze(1000);
|
|
||||||
|
|
||||||
remove_io_interrupt_handler(channel->intnum, inthand, channel);
|
|
||||||
|
|
||||||
free(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
register_device(device_node *parent)
|
|
||||||
{
|
|
||||||
status_t primaryStatus;
|
|
||||||
status_t secondaryStatus;
|
|
||||||
TRACE("register_device()\n");
|
|
||||||
|
|
||||||
// our parent device is the isa bus and all device drivers are Universal,
|
|
||||||
// so the pnp_manager tries each ISA driver in turn
|
|
||||||
primaryStatus = publish_channel(parent, 0x1f0, 0x3f6, 14,
|
|
||||||
"primary IDE channel");
|
|
||||||
secondaryStatus = publish_channel(parent, 0x170, 0x376, 15,
|
|
||||||
"secondary IDE channel");
|
|
||||||
|
|
||||||
if (primaryStatus == B_OK || secondaryStatus == B_OK)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
return primaryStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_removed(void *cookie)
|
|
||||||
{
|
|
||||||
channel_info *channel = cookie;
|
|
||||||
TRACE("channel_removed()\n");
|
|
||||||
|
|
||||||
// disable access instantly
|
|
||||||
atomic_or(&channel->lost, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
// exported interface
|
|
||||||
static ide_controller_interface sISAControllerInterface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
IDE_ISA_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
supports_device,
|
|
||||||
register_device,
|
|
||||||
init_channel,
|
|
||||||
uninit_channel,
|
|
||||||
NULL, // register child devices
|
|
||||||
NULL, // rescan
|
|
||||||
channel_removed,
|
|
||||||
},
|
|
||||||
|
|
||||||
&set_channel,
|
|
||||||
|
|
||||||
&write_command_block_regs,
|
|
||||||
&read_command_block_regs,
|
|
||||||
|
|
||||||
&get_altstatus,
|
|
||||||
&write_device_control,
|
|
||||||
|
|
||||||
&write_pio_16,
|
|
||||||
&read_pio_16,
|
|
||||||
|
|
||||||
&prepare_dma,
|
|
||||||
&start_dma,
|
|
||||||
&finish_dma,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&sISAControllerInterface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide it8211 ;
|
|
||||||
|
|
||||||
UsePrivateHeaders kernel ;
|
|
||||||
UsePrivateHeaders drivers ;
|
|
||||||
|
|
||||||
KernelAddon it8211 :
|
|
||||||
it8211.c
|
|
||||||
;
|
|
||||||
@@ -1,242 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008, Michael Lotz. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <ide_adapter.h>
|
|
||||||
|
|
||||||
#define IT8211_CONTROLLER_MODULE_NAME "busses/ide/it8211/driver_v1"
|
|
||||||
#define IT8211_CHANNEL_MODULE_NAME "busses/ide/it8211/channel/v1"
|
|
||||||
|
|
||||||
#define PCI_VENDOR_ITE 0x1283
|
|
||||||
#define PCI_DEVICE_ITE_IT8211 0x8211
|
|
||||||
|
|
||||||
static ide_adapter_interface *sIDEAdapter;
|
|
||||||
static device_manager_info *sDeviceManager;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
it8211_set_channel(void *channelCookie, ide_channel channel)
|
|
||||||
{
|
|
||||||
sIDEAdapter->set_channel((ide_adapter_channel_info *)channelCookie,
|
|
||||||
channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_write_command_block_regs(void *channelCookie, ide_task_file *taskFile,
|
|
||||||
ide_reg_mask registerMask)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->write_command_block_regs(
|
|
||||||
(ide_adapter_channel_info *)channelCookie, taskFile, registerMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_read_command_block_regs(void *channelCookie, ide_task_file *taskFile,
|
|
||||||
ide_reg_mask registerMask)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->read_command_block_regs(
|
|
||||||
(ide_adapter_channel_info *)channelCookie, taskFile, registerMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
it8211_get_altstatus(void *channelCookie)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->get_altstatus((ide_adapter_channel_info *)channelCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_write_device_control(void *channelCookie, uint8 value)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->write_device_control(
|
|
||||||
(ide_adapter_channel_info *)channelCookie, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_write_pio(void *channelCookie, uint16 *data, int count, bool force16bit)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->write_pio(
|
|
||||||
(ide_adapter_channel_info *)channelCookie, data, count, force16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_read_pio(void *channelCookie, uint16 *data, int count, bool force16bit)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->read_pio(
|
|
||||||
(ide_adapter_channel_info *)channelCookie, data, count, force16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_prepare_dma(void *channelCookie, const physical_entry *sgList,
|
|
||||||
size_t sgListCount, bool toDevice)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->prepare_dma((ide_adapter_channel_info *)channelCookie,
|
|
||||||
sgList, sgListCount, toDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_start_dma(void *channelCookie)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->start_dma((ide_adapter_channel_info *)channelCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
it8211_finish_dma(void *channelCookie)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->finish_dma((ide_adapter_channel_info *)channelCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_channel(device_node *node, void **channelCookie)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->init_channel(node,
|
|
||||||
(ide_adapter_channel_info **)channelCookie,
|
|
||||||
sizeof(ide_adapter_channel_info), sIDEAdapter->inthand);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninit_channel(void *channelCookie)
|
|
||||||
{
|
|
||||||
sIDEAdapter->uninit_channel((ide_adapter_channel_info *)channelCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_removed(void *channelCookie)
|
|
||||||
{
|
|
||||||
sIDEAdapter->channel_removed((ide_adapter_channel_info *)channelCookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_controller(device_node *node, void **cookie)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->init_controller(node,
|
|
||||||
(ide_adapter_controller_info **)cookie,
|
|
||||||
sizeof(ide_adapter_controller_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
uninit_controller(void *cookie)
|
|
||||||
{
|
|
||||||
sIDEAdapter->uninit_controller((ide_adapter_controller_info *)cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_removed(void *cookie)
|
|
||||||
{
|
|
||||||
sIDEAdapter->controller_removed((ide_adapter_controller_info *)cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
probe_controller(device_node *parent)
|
|
||||||
{
|
|
||||||
return sIDEAdapter->probe_controller(parent,
|
|
||||||
IT8211_CONTROLLER_MODULE_NAME, "it8211",
|
|
||||||
"ITE IT8211", IT8211_CHANNEL_MODULE_NAME,
|
|
||||||
true, /* DMA */
|
|
||||||
true, /* command queuing */
|
|
||||||
1, /* 16 bit alignment */
|
|
||||||
0xffff, /* 64k boundary */
|
|
||||||
0x10000, /* up to 64k per scatter/gather block */
|
|
||||||
false); /* no compatibility mode */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
supports_device(device_node *parent)
|
|
||||||
{
|
|
||||||
const char *bus;
|
|
||||||
uint16 vendorID;
|
|
||||||
uint16 deviceID;
|
|
||||||
|
|
||||||
if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
|
|
||||||
|| sDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendorID, false) != B_OK
|
|
||||||
|| sDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, false) != B_OK) {
|
|
||||||
return -1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(bus, "pci") != 0 || vendorID != PCI_VENDOR_ITE
|
|
||||||
|| deviceID != PCI_DEVICE_ITE_IT8211)
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
|
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&sIDEAdapter },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// exported interface
|
|
||||||
static ide_controller_interface sChannelInterface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
IT8211_CHANNEL_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
NULL, // supports device
|
|
||||||
NULL, // register device
|
|
||||||
&init_channel,
|
|
||||||
&uninit_channel,
|
|
||||||
NULL, // register child devices
|
|
||||||
NULL, // rescan
|
|
||||||
&channel_removed
|
|
||||||
},
|
|
||||||
|
|
||||||
&it8211_set_channel,
|
|
||||||
&it8211_write_command_block_regs,
|
|
||||||
&it8211_read_command_block_regs,
|
|
||||||
&it8211_get_altstatus,
|
|
||||||
&it8211_write_device_control,
|
|
||||||
&it8211_write_pio,
|
|
||||||
&it8211_read_pio,
|
|
||||||
&it8211_prepare_dma,
|
|
||||||
&it8211_start_dma,
|
|
||||||
&it8211_finish_dma
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static driver_module_info sControllerInterface = {
|
|
||||||
{
|
|
||||||
IT8211_CONTROLLER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
&supports_device,
|
|
||||||
&probe_controller,
|
|
||||||
&init_controller,
|
|
||||||
&uninit_controller,
|
|
||||||
NULL, // register child devices
|
|
||||||
NULL, // rescan
|
|
||||||
&controller_removed
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&sControllerInterface,
|
|
||||||
(module_info *)&sChannelInterface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide legacy_sata ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
KernelAddon legacy_sata :
|
|
||||||
legacy_sata.c
|
|
||||||
;
|
|
||||||
|
|
||||||
@@ -1,403 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2007, Ithamar R. Adema. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <device_manager.h>
|
|
||||||
#include <bus/IDE.h>
|
|
||||||
#include <ide_adapter.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define DRIVER_PRETTY_NAME "Legacy SATA"
|
|
||||||
#define CONTROLLER_NAME DRIVER_PRETTY_NAME
|
|
||||||
#define CONTROLLER_MODULE_NAME "busses/ide/legacy_sata/driver_v1"
|
|
||||||
#define CHANNEL_MODULE_NAME "busses/ide/legacy_sata/channel/v1"
|
|
||||||
|
|
||||||
#define TRACE(a...) dprintf(DRIVER_PRETTY_NAME ": " a)
|
|
||||||
#define FLOW(a...) dprintf(DRIVER_PRETTY_NAME ": " a)
|
|
||||||
|
|
||||||
#define PCI_vendor_VIA 0x1106
|
|
||||||
#define PCI_device_VIA6420 0x3149
|
|
||||||
#define PCI_device_VIA6421 0x3249
|
|
||||||
#define PCI_device_VIA8237A 0x0591
|
|
||||||
|
|
||||||
#define PCI_vendor_ALI 0x10b9
|
|
||||||
#define PCI_device_ALI5289 0x5289
|
|
||||||
#define PCI_device_ALI5287 0x5287
|
|
||||||
#define PCI_device_ALI5281 0x5281
|
|
||||||
|
|
||||||
#define PCI_vendor_NVIDIA 0x10de
|
|
||||||
#define PCI_device_NF2PROS1 0x008e
|
|
||||||
#define PCI_device_NF3PROS1 0x00e3
|
|
||||||
#define PCI_device_NF3PROS2 0x00ee
|
|
||||||
#define PCI_device_MCP4S1 0x0036
|
|
||||||
#define PCI_device_MCP4S2 0x003e
|
|
||||||
#define PCI_device_CK804S1 0x0054
|
|
||||||
#define PCI_device_CK804S2 0x0055
|
|
||||||
#define PCI_device_MCP51S1 0x0266
|
|
||||||
#define PCI_device_MCP51S2 0x0267
|
|
||||||
#define PCI_device_MCP55S1 0x037e
|
|
||||||
#define PCI_device_MCP55S2 0x037f
|
|
||||||
#define PCI_device_MCP61S1 0x03e7
|
|
||||||
#define PCI_device_MCP61S2 0x03f6
|
|
||||||
#define PCI_device_MCP61S3 0x03f7
|
|
||||||
|
|
||||||
#define ID(v,d) (((v)<< 16) | (d))
|
|
||||||
|
|
||||||
/* XXX: To be moved to PCI.h */
|
|
||||||
#define PCI_command_interrupt 0x400
|
|
||||||
|
|
||||||
static const char * const kChannelNames[] = {
|
|
||||||
"Primary Channel", "Secondary Channel",
|
|
||||||
"Tertiary Channel", "Quaternary Channel"
|
|
||||||
};
|
|
||||||
|
|
||||||
static ide_for_controller_interface* ide;
|
|
||||||
static ide_adapter_interface* ide_adapter;
|
|
||||||
static device_manager_info* dm;
|
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
controller_supports(device_node *parent)
|
|
||||||
{
|
|
||||||
uint16 vendor_id;
|
|
||||||
uint16 device_id;
|
|
||||||
status_t res;
|
|
||||||
const char *bus = NULL;
|
|
||||||
|
|
||||||
// get the bus (should be PCI)
|
|
||||||
if (dm->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
if (strcmp(bus, "pci") != 0) {
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get vendor and device ID
|
|
||||||
if ((res=dm->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendor_id, false)) != B_OK
|
|
||||||
|| (res=dm->get_attr_uint16(parent, B_DEVICE_ID, &device_id, false)) != B_OK) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ID(vendor_id, device_id)) {
|
|
||||||
/* VIA SATA chipsets */
|
|
||||||
case ID(PCI_vendor_VIA, PCI_device_VIA6420):
|
|
||||||
case ID(PCI_vendor_VIA, PCI_device_VIA6421):
|
|
||||||
case ID(PCI_vendor_VIA, PCI_device_VIA8237A):
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* ALI SATA chipsets */
|
|
||||||
case ID(PCI_vendor_ALI, PCI_device_ALI5281):
|
|
||||||
case ID(PCI_vendor_ALI, PCI_device_ALI5287):
|
|
||||||
case ID(PCI_vendor_ALI, PCI_device_ALI5289):
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* NVidia NForce chipsets */
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_NF2PROS1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_NF3PROS1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_NF3PROS2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP4S1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP4S2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_CK804S1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_CK804S2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP51S1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP51S2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP55S1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP55S2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S1):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S2):
|
|
||||||
case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S3):
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("controller found! vendor 0x%04x, device 0x%04x\n", vendor_id, device_id);
|
|
||||||
|
|
||||||
return 0.8f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
controller_probe(device_node *parent)
|
|
||||||
{
|
|
||||||
device_node *controller_node;
|
|
||||||
device_node *channels[4];
|
|
||||||
uint16 command_block_base[4];
|
|
||||||
uint16 control_block_base[4];
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
uint8 num_channels = 2;
|
|
||||||
uint32 bus_master_base;
|
|
||||||
pci_device *device = NULL;
|
|
||||||
uint16 device_id;
|
|
||||||
uint16 vendor_id;
|
|
||||||
uint8 int_num;
|
|
||||||
status_t res;
|
|
||||||
uint8 index;
|
|
||||||
|
|
||||||
TRACE("controller_probe\n");
|
|
||||||
|
|
||||||
dm->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
|
|
||||||
|
|
||||||
device_id = pci->read_pci_config(device, PCI_device_id, 2);
|
|
||||||
vendor_id = pci->read_pci_config(device, PCI_vendor_id, 2);
|
|
||||||
int_num = pci->read_pci_config(device, PCI_interrupt_line, 1);
|
|
||||||
bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 4);
|
|
||||||
|
|
||||||
/* Default PCI assigments */
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 0, 4);
|
|
||||||
control_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 4, 4);
|
|
||||||
command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 8, 4);
|
|
||||||
control_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 12, 4);
|
|
||||||
|
|
||||||
/* enable PCI interrupt */
|
|
||||||
pci->write_pci_config(device, PCI_command, 2,
|
|
||||||
pci->read_pci_config(device, PCI_command, 2) & ~PCI_command_interrupt);
|
|
||||||
|
|
||||||
if (vendor_id == PCI_vendor_NVIDIA) {
|
|
||||||
/* enable control access */
|
|
||||||
pci->write_pci_config(device, 0x50, 1,
|
|
||||||
pci->read_pci_config(device, 0x50, 1) | 0x04);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ID(vendor_id, device_id)) {
|
|
||||||
case ID(PCI_vendor_VIA,PCI_device_VIA6421):
|
|
||||||
/* newer SATA chips has resources in one BAR for each channel */
|
|
||||||
num_channels = 4;
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 0, 4);
|
|
||||||
control_block_base[0] = command_block_base[0] + 8;
|
|
||||||
command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 4, 4);
|
|
||||||
control_block_base[1] = command_block_base[1] + 8;
|
|
||||||
command_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 8, 4);
|
|
||||||
control_block_base[2] = command_block_base[2] + 8;
|
|
||||||
command_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 12, 4);
|
|
||||||
control_block_base[3] = command_block_base[3] + 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ID(PCI_vendor_ALI, PCI_device_ALI5287):
|
|
||||||
num_channels = 4;
|
|
||||||
command_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 0, 4) + 8;
|
|
||||||
control_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 4, 4) + 4;
|
|
||||||
command_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 8, 4) + 8;
|
|
||||||
control_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 12, 4) + 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bus_master_base &= PCI_address_io_mask;
|
|
||||||
for (index = 0; index < num_channels; index++) {
|
|
||||||
command_block_base[index] &= PCI_address_io_mask;
|
|
||||||
control_block_base[index] &= PCI_address_io_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = ide_adapter->detect_controller(pci, device, parent, bus_master_base,
|
|
||||||
CONTROLLER_MODULE_NAME, "" /* XXX: unused: controller_driver_type*/, CONTROLLER_NAME, true,
|
|
||||||
true, 1, 0xffff, 0x10000, &controller_node);
|
|
||||||
// don't register if controller is already registered!
|
|
||||||
// (happens during rescan; registering new channels would kick out old channels)
|
|
||||||
if (res != B_OK)
|
|
||||||
goto err;
|
|
||||||
if (controller_node == NULL) {
|
|
||||||
res = B_IO_ERROR;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore errors during registration of channels - could be a simple rescan collision
|
|
||||||
|
|
||||||
for (index = 0; index < num_channels; index++) {
|
|
||||||
res = ide_adapter->detect_channel(pci, device, controller_node, CHANNEL_MODULE_NAME,
|
|
||||||
true, command_block_base[index], control_block_base[index], bus_master_base,
|
|
||||||
int_num, index, kChannelNames[index], &channels[index], false);
|
|
||||||
|
|
||||||
dprintf("%s: %s\n", kChannelNames[index], strerror(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TRACE("controller_probe success\n");
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
TRACE("controller_probe failed (%s)\n", strerror(res));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
controller_init(device_node *node, void **controller_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_controller(
|
|
||||||
node, (ide_adapter_controller_info**)controller_cookie,
|
|
||||||
sizeof(ide_adapter_controller_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_uninit(void *controller_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->uninit_controller(controller_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_removed(void *controller_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->controller_removed(
|
|
||||||
(ide_adapter_controller_info*)controller_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
channel_init(device_node *node, void **channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_channel(node,
|
|
||||||
(ide_adapter_channel_info**)channel_cookie,
|
|
||||||
sizeof(ide_adapter_channel_info),
|
|
||||||
ide_adapter->inthand);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_uninit(void *channel_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->uninit_channel(channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_removed(void *channel_cookie)
|
|
||||||
{
|
|
||||||
ide_adapter->channel_removed(channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_set(void *cookie, ide_channel channel)
|
|
||||||
{
|
|
||||||
ide_adapter->set_channel((ide_adapter_channel_info *)cookie, channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
task_file_write(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_command_block_regs(channel_cookie,tf,mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
task_file_read(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_command_block_regs(channel_cookie,tf,mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
altstatus_read(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->get_altstatus(channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
device_control_write(void *channel_cookie, uint8 val)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_device_control(channel_cookie,val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
pio_write(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_pio(channel_cookie,data,count,force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
pio_read(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_pio(channel_cookie,data,count,force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_prepare(void *channel_cookie, const physical_entry *sg_list, size_t sg_list_count, bool write)
|
|
||||||
{
|
|
||||||
return ide_adapter->prepare_dma(channel_cookie,sg_list,sg_list_count,write);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_start(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->start_dma(channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_finish(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->finish_dma(channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&dm },
|
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
static ide_controller_interface sChannelInterface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
CHANNEL_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
channel_init,
|
|
||||||
channel_uninit,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
channel_removed,
|
|
||||||
},
|
|
||||||
|
|
||||||
channel_set,
|
|
||||||
|
|
||||||
task_file_write,
|
|
||||||
task_file_read,
|
|
||||||
|
|
||||||
altstatus_read,
|
|
||||||
device_control_write,
|
|
||||||
|
|
||||||
pio_write,
|
|
||||||
pio_read,
|
|
||||||
|
|
||||||
dma_prepare,
|
|
||||||
dma_start,
|
|
||||||
dma_finish,
|
|
||||||
};
|
|
||||||
|
|
||||||
static driver_module_info sControllerInterface = {
|
|
||||||
{
|
|
||||||
CONTROLLER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
.init_driver = &controller_init,
|
|
||||||
.uninit_driver = &controller_uninit,
|
|
||||||
.supports_device = &controller_supports,
|
|
||||||
.register_device = &controller_probe,
|
|
||||||
.device_removed = &controller_removed,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&sControllerInterface,
|
|
||||||
(module_info *)&sChannelInterface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide promise_tx2 ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
KernelAddon promise_tx2 :
|
|
||||||
promise_tx2.c
|
|
||||||
;
|
|
||||||
@@ -1,378 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Promise TX2 series IDE controller driver
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <bus/ide/ide_adapter.h>
|
|
||||||
|
|
||||||
#define debug_level_flow 0
|
|
||||||
#define debug_level_error 3
|
|
||||||
#define debug_level_info 3
|
|
||||||
|
|
||||||
#define DEBUG_MSG_PREFIX "PROMISE TX2 -- "
|
|
||||||
|
|
||||||
#include "wrapper.h"
|
|
||||||
|
|
||||||
#define PROMISE_TX2_CONTROLLER_MODULE_NAME "busses/ide/promise_tx2/device_v1"
|
|
||||||
#define PROMISE_TX2_CHANNEL_MODULE_NAME "busses/ide/promise_tx2/channel/v1"
|
|
||||||
|
|
||||||
|
|
||||||
static ide_for_controller_interface *ide;
|
|
||||||
static ide_adapter_interface *ide_adapter;
|
|
||||||
static device_manager_info *pnp;
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_command_block_regs(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_command_block_regs((ide_adapter_channel_info *)channel_cookie, tf, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_command_block_regs(void *channel_cookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_command_block_regs((ide_adapter_channel_info *)channel_cookie, tf, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
get_altstatus(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->get_altstatus((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_device_control(void *channel_cookie, uint8 val)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_device_control((ide_adapter_channel_info *)channel_cookie, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
write_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->write_pio((ide_adapter_channel_info *)channel_cookie, data, count, force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
read_pio(void *channel_cookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
return ide_adapter->read_pio((ide_adapter_channel_info *)channel_cookie, data, count, force_16bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
inthand(void *arg)
|
|
||||||
{
|
|
||||||
ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg;
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device device = channel->device;
|
|
||||||
ide_bm_status bm_status;
|
|
||||||
uint8 status;
|
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
// the controller always tells us whether it generated the IRQ, so ask it first
|
|
||||||
pci->write_io_8(device, channel->bus_master_base + 1, 0x0b);
|
|
||||||
if ((pci->read_io_8(device, channel->bus_master_base + 3) & 0x20) == 0)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
if (channel->dmaing) {
|
|
||||||
// in DMA mode, there is a safe test
|
|
||||||
// in PIO mode, this doesn't work
|
|
||||||
*(uint8 *)&bm_status = pci->read_io_8( device,
|
|
||||||
channel->bus_master_base + ide_bm_status_reg );
|
|
||||||
|
|
||||||
if (!bm_status.interrupt)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// acknowledge IRQ
|
|
||||||
status = pci->read_io_8(device, channel->command_block_base + 7);
|
|
||||||
|
|
||||||
return ide->irq_handler(channel->ide_channel, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
prepare_dma(void *channel_cookie, const physical_entry *sg_list,
|
|
||||||
size_t sg_list_count, bool to_device)
|
|
||||||
{
|
|
||||||
return ide_adapter->prepare_dma((ide_adapter_channel_info *)channel_cookie, sg_list, sg_list_count, to_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
start_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->start_dma((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
finish_dma(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->finish_dma((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_channel(device_node_handle node, ide_channel ide_channel,
|
|
||||||
void **channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_channel(node, ide_channel, (ide_adapter_channel_info **)channel_cookie,
|
|
||||||
sizeof(ide_adapter_channel_info), inthand);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
uninit_channel(void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->uninit_channel((ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void channel_removed(device_node_handle node, void *channel_cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->channel_removed(node, (ide_adapter_channel_info *)channel_cookie);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
init_controller(device_node_handle node, void *user_cookie,
|
|
||||||
ide_adapter_controller_info **cookie)
|
|
||||||
{
|
|
||||||
return ide_adapter->init_controller(node, user_cookie, cookie,
|
|
||||||
sizeof(ide_adapter_controller_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
uninit_controller(ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
return ide_adapter->uninit_controller(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_removed(device_node_handle node, ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
return ide_adapter->controller_removed(node, controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// publish node of ide controller
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
publish_controller(device_node_handle parent, uint16 bus_master_base, uint8 intnum,
|
|
||||||
io_resource_handle *resources, device_node_handle *node)
|
|
||||||
{
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// info about ourself and our consumer
|
|
||||||
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PROMISE_TX2_CONTROLLER_MODULE_NAME }},
|
|
||||||
|
|
||||||
// properties of this controller for ide bus manager
|
|
||||||
// there are always max. 2 devices
|
|
||||||
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
|
|
||||||
// of course we can DMA
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
// command queuing always works
|
|
||||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: 1 }},
|
|
||||||
// choose any name here
|
|
||||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: "Promise TX2" }},
|
|
||||||
|
|
||||||
// DMA properties
|
|
||||||
// some say it must be dword-aligned, others that it can be byte-aligned;
|
|
||||||
// stay on the safe side
|
|
||||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 3 }},
|
|
||||||
// one S/G block must not cross 64K boundary
|
|
||||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
|
||||||
// size of S/G block is 16 bits with zero being 64K
|
|
||||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
|
||||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
|
||||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
|
||||||
{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
|
|
||||||
|
|
||||||
// private data to find controller
|
|
||||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
|
||||||
// store interrupt in controller node
|
|
||||||
{ IDE_ADAPTER_INTNUM, B_UINT8_TYPE, { ui8: intnum }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0(2, "");
|
|
||||||
|
|
||||||
return pnp->register_device(parent, attrs, resources, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// detect pure IDE controller, i.e. without channels
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
detect_controller(pci_device_module_info *pci, pci_device pci_device,
|
|
||||||
device_node_handle parent, uint16 bus_master_base, int8 intnum,
|
|
||||||
device_node_handle *node)
|
|
||||||
{
|
|
||||||
io_resource_handle resource_handles[2];
|
|
||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
|
||||||
|
|
||||||
if ((bus_master_base & PCI_address_space) != 1)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
bus_master_base &= ~PCI_address_space;
|
|
||||||
|
|
||||||
{
|
|
||||||
io_resource resources[2] = {
|
|
||||||
{ IO_PORT, bus_master_base, 16 },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (pnp->acquire_io_resources(resources, resource_handles) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return publish_controller(parent, bus_master_base, intnum, resource_handles, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
probe_controller(device_node_handle parent)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device device;
|
|
||||||
uint16 command_block_base[2];
|
|
||||||
uint16 control_block_base[2];
|
|
||||||
uint16 bus_master_base;
|
|
||||||
device_node_handle controller_node, channels[2];
|
|
||||||
uint8 intnum;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
|
||||||
|
|
||||||
if (pnp->init_driver(parent, NULL, (driver_module_info **)&pci, (void **)&device) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4);
|
|
||||||
control_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 4, 4);
|
|
||||||
command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 8, 4);
|
|
||||||
control_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 12, 4);
|
|
||||||
bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 4);
|
|
||||||
intnum = pci->read_pci_config(device, PCI_interrupt_line, 1);
|
|
||||||
|
|
||||||
command_block_base[0] &= PCI_address_io_mask;
|
|
||||||
control_block_base[0] &= PCI_address_io_mask;
|
|
||||||
command_block_base[1] &= PCI_address_io_mask;
|
|
||||||
control_block_base[1] &= PCI_address_io_mask;
|
|
||||||
bus_master_base &= PCI_address_io_mask;
|
|
||||||
|
|
||||||
res = detect_controller(pci, device, parent, bus_master_base, intnum, &controller_node);
|
|
||||||
if (res != B_OK || controller_node == NULL)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ide_adapter->detect_channel(pci, device, controller_node,
|
|
||||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
|
||||||
command_block_base[0], control_block_base[0], bus_master_base, intnum,
|
|
||||||
0, "Primary Channel", &channels[0], false);
|
|
||||||
|
|
||||||
ide_adapter->detect_channel(pci, device, controller_node,
|
|
||||||
PROMISE_TX2_CHANNEL_MODULE_NAME, true,
|
|
||||||
command_block_base[1], control_block_base[1], bus_master_base, intnum,
|
|
||||||
1, "Secondary Channel", &channels[1], false);
|
|
||||||
|
|
||||||
pnp->uninit_driver(parent);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
pnp->uninit_driver(parent);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
std_ops(int32 op, ...)
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
case B_MODULE_INIT:
|
|
||||||
case B_MODULE_UNINIT:
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// exported interface
|
|
||||||
static ide_controller_interface channel_interface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
PROMISE_TX2_CHANNEL_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
std_ops
|
|
||||||
},
|
|
||||||
|
|
||||||
NULL, // supported devices
|
|
||||||
NULL,
|
|
||||||
(status_t (*)( device_node_handle , void *, void ** )) init_channel,
|
|
||||||
uninit_channel,
|
|
||||||
channel_removed
|
|
||||||
},
|
|
||||||
|
|
||||||
&write_command_block_regs,
|
|
||||||
&read_command_block_regs,
|
|
||||||
|
|
||||||
&get_altstatus,
|
|
||||||
&write_device_control,
|
|
||||||
|
|
||||||
&write_pio,
|
|
||||||
&read_pio,
|
|
||||||
|
|
||||||
&prepare_dma,
|
|
||||||
&start_dma,
|
|
||||||
&finish_dma,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static driver_module_info controller_interface = {
|
|
||||||
{
|
|
||||||
PROMISE_TX2_CONTROLLER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
std_ops
|
|
||||||
},
|
|
||||||
|
|
||||||
NULL,
|
|
||||||
probe_controller,
|
|
||||||
(status_t (*)(device_node_handle, void *, void **)) init_controller,
|
|
||||||
(status_t (*)(void *)) uninit_controller,
|
|
||||||
(void (*)(device_node_handle, void *)) controller_removed
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&controller_interface,
|
|
||||||
(module_info *)&channel_interface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#ifndef _WRAPPER_H
|
|
||||||
#define _WRAPPER_H
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <lock.h>
|
|
||||||
|
|
||||||
|
|
||||||
// benaphores
|
|
||||||
|
|
||||||
#define INIT_BEN(x, prefix) (mutex_init_etc(x, prefix, MUTEX_FLAG_CLONE_NAME), \
|
|
||||||
B_OK)
|
|
||||||
#define DELETE_BEN(x) mutex_destroy(x)
|
|
||||||
#define ACQUIRE_BEN(x) mutex_lock(x)
|
|
||||||
#define RELEASE_BEN(x) mutex_unlock(x)
|
|
||||||
|
|
||||||
// debug output
|
|
||||||
|
|
||||||
#ifdef DEBUG_WAIT_ON_MSG
|
|
||||||
# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG );
|
|
||||||
#else
|
|
||||||
# define DEBUG_WAIT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_WAIT_ON_ERROR
|
|
||||||
# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR );
|
|
||||||
#else
|
|
||||||
# define DEBUG_WAIT_ERROR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_FLOW
|
|
||||||
# define DEBUG_MAX_LEVEL_FLOW 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_INFO
|
|
||||||
# define DEBUG_MAX_LEVEL_INFO 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_ERROR
|
|
||||||
# define DEBUG_MAX_LEVEL_ERROR 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MSG_PREFIX
|
|
||||||
# define DEBUG_MSG_PREFIX ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_flow
|
|
||||||
# define debug_level_flow 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_info
|
|
||||||
# define debug_level_info 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_error
|
|
||||||
# define debug_level_error 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FUNC_NAME DEBUG_MSG_PREFIX __FUNCTION__ ": "
|
|
||||||
|
|
||||||
#define SHOW_FLOW(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_FLOW0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_INFO(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_INFO0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_ERROR(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_ERROR0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
|
||||||
dprintf( "%s"##format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#endif /* _BENAPHORE_H */
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel busses ide silicon_image_3112 ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
KernelAddon silicon_image_3112 :
|
|
||||||
silicon_image_3112.c
|
|
||||||
;
|
|
||||||
@@ -1,898 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006, Marcus Overhagen. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <device_manager.h>
|
|
||||||
#include <bus/IDE.h>
|
|
||||||
|
|
||||||
#include <ide_adapter.h>
|
|
||||||
|
|
||||||
#define TRACE(x...) dprintf("si-3112: " x)
|
|
||||||
//#define FLOW(x...) dprintf("si-3112: " x)
|
|
||||||
#define FLOW(x...)
|
|
||||||
|
|
||||||
|
|
||||||
#define DRIVER_PRETTY_NAME "Silicon Image SATA"
|
|
||||||
#define CONTROLLER_NAME DRIVER_PRETTY_NAME
|
|
||||||
#define CONTROLLER_MODULE_NAME "busses/ide/silicon_image_3112/driver_v1"
|
|
||||||
#define CHANNEL_MODULE_NAME "busses/ide/silicon_image_3112/channel/v1"
|
|
||||||
|
|
||||||
enum asic_type {
|
|
||||||
ASIC_SI3112 = 0,
|
|
||||||
ASIC_SI3114 = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static const char *adapter_asic_names[] = {
|
|
||||||
"si3112",
|
|
||||||
"si3114",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
uint16 channel_count;
|
|
||||||
uint32 mmio_bar_size;
|
|
||||||
} kASICData[2] = {
|
|
||||||
{ 2, 0x200 },
|
|
||||||
{ 4, 0x400 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
uint16 cmd;
|
|
||||||
uint16 ctl;
|
|
||||||
uint16 bmdma;
|
|
||||||
uint16 sien;
|
|
||||||
uint16 stat;
|
|
||||||
const char *name;
|
|
||||||
} kControllerChannelData[] = {
|
|
||||||
{ 0x80, 0x8A, 0x00, 0x148, 0xA0, "Primary Channel" },
|
|
||||||
{ 0xC0, 0xCA, 0x08, 0x1C8, 0xE0, "Secondary Channel" },
|
|
||||||
{ 0x280, 0x28A, 0x200, 0x348, 0x2A0, "Tertiary Channel" },
|
|
||||||
{ 0x2C0, 0x2CA, 0x208, 0x3C8, 0x2E0, "Quaternary Channel" },
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SI_SYSCFG 0x48
|
|
||||||
#define SI_BMDMA2 0x200
|
|
||||||
#define SI_INT_STEERING 0x02
|
|
||||||
#define SI_MASK_2PORT ((1 << 22) | (1 << 23))
|
|
||||||
#define SI_MASK_4PORT ((1 << 22) | (1 << 23) | (1 << 24) | (1 << 25))
|
|
||||||
|
|
||||||
struct channel_data;
|
|
||||||
|
|
||||||
typedef struct controller_data {
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
|
|
||||||
device_node *node;
|
|
||||||
|
|
||||||
struct channel_data *channel[4]; // XXX only for interrupt workaround
|
|
||||||
int channel_count; // XXX only for interrupt workaround
|
|
||||||
|
|
||||||
uint32 asic_index;
|
|
||||||
uint32 int_num;
|
|
||||||
|
|
||||||
area_id mmio_area;
|
|
||||||
uint32 mmio_addr;
|
|
||||||
|
|
||||||
uint32 lost; // != 0 if device got removed, i.e. if it must not
|
|
||||||
// be accessed anymore
|
|
||||||
} controller_data;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct channel_data {
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
device_node * node;
|
|
||||||
pci_device * device;
|
|
||||||
ide_channel ide_channel;
|
|
||||||
|
|
||||||
volatile uint8 * task_file;
|
|
||||||
volatile uint8 * control_block;
|
|
||||||
volatile uint8 * command_block;
|
|
||||||
volatile uint8 * dev_ctrl;
|
|
||||||
volatile uint8 * bm_status_reg;
|
|
||||||
volatile uint8 * bm_command_reg;
|
|
||||||
volatile uint32 * bm_prdt_address;
|
|
||||||
|
|
||||||
volatile uint32 * stat;
|
|
||||||
|
|
||||||
area_id prd_area;
|
|
||||||
prd_entry * prdt;
|
|
||||||
phys_addr_t prdt_phys;
|
|
||||||
uint32 dma_active;
|
|
||||||
uint32 lost;
|
|
||||||
} channel_data;
|
|
||||||
|
|
||||||
|
|
||||||
static ide_for_controller_interface * ide;
|
|
||||||
static ide_adapter_interface * ide_adapter;
|
|
||||||
static device_manager_info * dm;
|
|
||||||
|
|
||||||
static status_t device_control_write(void *channel_cookie, uint8 val);
|
|
||||||
static int32 handle_interrupt(void *arg);
|
|
||||||
|
|
||||||
|
|
||||||
static float
|
|
||||||
controller_supports(device_node *parent)
|
|
||||||
{
|
|
||||||
const char *bus;
|
|
||||||
uint16 vendorID;
|
|
||||||
uint16 deviceID;
|
|
||||||
|
|
||||||
// get the bus (should be PCI)
|
|
||||||
if (dm->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
|
|
||||||
|| strcmp(bus, "pci") != 0)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
// get vendor and device ID
|
|
||||||
if (dm->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendorID, false) != B_OK
|
|
||||||
|| dm->get_attr_uint16(parent, B_DEVICE_ID, &deviceID, false) != B_OK) {
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ID(v, d) (((v) << 16) | (d))
|
|
||||||
switch (ID(vendorID, deviceID)) {
|
|
||||||
case ID(0x1095, 0x0240):
|
|
||||||
case ID(0x1095, 0x3112):
|
|
||||||
case ID(0x1095, 0x3114):
|
|
||||||
case ID(0x1095, 0x3512):
|
|
||||||
case ID(0x1002, 0x436e): // ATI
|
|
||||||
case ID(0x1002, 0x4379): // ATI
|
|
||||||
case ID(0x1002, 0x437a): // ATI
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("controller found! vendor 0x%04x, device 0x%04x\n", vendorID, deviceID);
|
|
||||||
|
|
||||||
return 0.8f;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
controller_probe(device_node *parent)
|
|
||||||
{
|
|
||||||
pci_device *device;
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
uint32 mmioBase;
|
|
||||||
uint16 deviceID;
|
|
||||||
uint16 vendorID;
|
|
||||||
uint8 interruptNumber;
|
|
||||||
int asicIndex;
|
|
||||||
|
|
||||||
TRACE("controller_probe\n");
|
|
||||||
|
|
||||||
dm->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
|
|
||||||
|
|
||||||
deviceID = pci->read_pci_config(device, PCI_device_id, 2);
|
|
||||||
vendorID = pci->read_pci_config(device, PCI_vendor_id, 2);
|
|
||||||
interruptNumber = pci->read_pci_config(device, PCI_interrupt_line, 1);
|
|
||||||
mmioBase = pci->read_pci_config(device, PCI_base_registers + 20, 4)
|
|
||||||
& PCI_address_io_mask;
|
|
||||||
|
|
||||||
switch (ID(vendorID, deviceID)) {
|
|
||||||
case ID(0x1095, 0x0240):
|
|
||||||
case ID(0x1095, 0x3112):
|
|
||||||
case ID(0x1095, 0x3512):
|
|
||||||
case ID(0x1002, 0x436e): // ATI
|
|
||||||
case ID(0x1002, 0x4379): // ATI
|
|
||||||
case ID(0x1002, 0x437a): // ATI
|
|
||||||
asicIndex = ASIC_SI3112;
|
|
||||||
break;
|
|
||||||
case ID(0x1095, 0x3114):
|
|
||||||
asicIndex = ASIC_SI3114;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
TRACE("unsupported asic\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mmioBase) {
|
|
||||||
TRACE("mmio not configured\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interruptNumber == 0 || interruptNumber == 0xff) {
|
|
||||||
TRACE("irq not configured\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
io_resource resources[2] = {
|
|
||||||
{ B_IO_MEMORY, mmioBase, kASICData[asicIndex].mmio_bar_size },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// properties of this controller for ide bus manager
|
|
||||||
// there are always max. 2 devices
|
|
||||||
// (unless this is a Compact Flash Card with a built-in IDE controller,
|
|
||||||
// which has exactly 1 device)
|
|
||||||
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: kASICData[asicIndex].channel_count }},
|
|
||||||
// of course we can DMA
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }},
|
|
||||||
// command queuing always works
|
|
||||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: true }},
|
|
||||||
// choose any name here
|
|
||||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE, { string: CONTROLLER_NAME }},
|
|
||||||
|
|
||||||
// DMA properties
|
|
||||||
// data must be word-aligned;
|
|
||||||
// warning: some controllers are more picky!
|
|
||||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: 1}},
|
|
||||||
// one S/G block must not cross 64K boundary
|
|
||||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: 0xffff }},
|
|
||||||
// max size of S/G block is 16 bits with zero being 64K
|
|
||||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { ui32: 0x10000 }},
|
|
||||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
|
||||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
|
||||||
{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
|
|
||||||
|
|
||||||
// private data to find controller
|
|
||||||
{ "silicon_image_3112/asic_index", B_UINT32_TYPE, { ui32: asicIndex }},
|
|
||||||
{ "silicon_image_3112/mmio_base", B_UINT32_TYPE, { ui32: mmioBase }},
|
|
||||||
{ "silicon_image_3112/int_num", B_UINT32_TYPE, { ui32: interruptNumber }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
TRACE("publishing controller\n");
|
|
||||||
|
|
||||||
return dm->register_node(parent, CONTROLLER_MODULE_NAME, attrs,
|
|
||||||
resources, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
controller_init(device_node *node, void **_controllerCookie)
|
|
||||||
{
|
|
||||||
controller_data *controller;
|
|
||||||
device_node *parent;
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
uint32 asicIndex;
|
|
||||||
uint32 mmioBase;
|
|
||||||
uint32 mmioAddr;
|
|
||||||
area_id mmioArea;
|
|
||||||
uint32 interruptNumber;
|
|
||||||
status_t res;
|
|
||||||
uint32 temp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
TRACE("controller_init\n");
|
|
||||||
|
|
||||||
if (dm->get_attr_uint32(node, "silicon_image_3112/asic_index", &asicIndex, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
if (dm->get_attr_uint32(node, "silicon_image_3112/mmio_base", &mmioBase, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
if (dm->get_attr_uint32(node, "silicon_image_3112/int_num", &interruptNumber, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
controller = malloc(sizeof(controller_data));
|
|
||||||
if (!controller)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
FLOW("controller %p\n", controller);
|
|
||||||
|
|
||||||
mmioArea = map_physical_memory("Silicon Image SATA regs", mmioBase,
|
|
||||||
kASICData[asicIndex].mmio_bar_size, B_ANY_KERNEL_ADDRESS, 0,
|
|
||||||
(void **)&mmioAddr);
|
|
||||||
if (mmioArea < B_OK) {
|
|
||||||
TRACE("controller_init: mapping memory failed\n");
|
|
||||||
free(controller);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = dm->get_parent_node(node);
|
|
||||||
dm->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
|
|
||||||
dm->put_node(parent);
|
|
||||||
|
|
||||||
TRACE("asic %ld\n", asicIndex);
|
|
||||||
TRACE("int_num %ld\n", interruptNumber);
|
|
||||||
TRACE("mmio_addr %p\n", (void *)mmioAddr);
|
|
||||||
|
|
||||||
controller->pci = pci;
|
|
||||||
controller->device = device;
|
|
||||||
controller->node = node;
|
|
||||||
controller->asic_index = asicIndex;
|
|
||||||
controller->int_num = interruptNumber;
|
|
||||||
controller->mmio_area = mmioArea;
|
|
||||||
controller->mmio_addr = mmioAddr;
|
|
||||||
controller->lost = 0;
|
|
||||||
|
|
||||||
controller->channel_count = kASICData[asicIndex].channel_count;
|
|
||||||
for (i = 0; i < kASICData[asicIndex].channel_count; i++)
|
|
||||||
controller->channel[i] = 0;
|
|
||||||
|
|
||||||
if (asicIndex == ASIC_SI3114) {
|
|
||||||
// I put a magic spell on you
|
|
||||||
temp = *(volatile uint32 *)(mmioAddr + SI_BMDMA2);
|
|
||||||
*(volatile uint32 *)(mmioAddr + SI_BMDMA2) = temp | SI_INT_STEERING;
|
|
||||||
*(volatile uint32 *)(mmioAddr + SI_BMDMA2); // flush
|
|
||||||
}
|
|
||||||
|
|
||||||
// disable all sata phy interrupts
|
|
||||||
for (i = 0; i < kASICData[asicIndex].channel_count; i++)
|
|
||||||
*(volatile uint32 *)(mmioAddr + kControllerChannelData[i].sien) = 0;
|
|
||||||
*(volatile uint32 *)(mmioAddr + kControllerChannelData[0].sien); // flush
|
|
||||||
|
|
||||||
// install interrupt handler
|
|
||||||
res = install_io_interrupt_handler(interruptNumber, handle_interrupt,
|
|
||||||
controller, 0);
|
|
||||||
if (res < B_OK) {
|
|
||||||
TRACE("controller_init: installing interrupt handler failed\n");
|
|
||||||
delete_area(mmioArea);
|
|
||||||
free(controller);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmask interrupts
|
|
||||||
temp = *(volatile uint32 *)(mmioAddr + SI_SYSCFG);
|
|
||||||
temp &= (asicIndex == ASIC_SI3114) ? (~SI_MASK_4PORT) : (~SI_MASK_2PORT);
|
|
||||||
*(volatile uint32 *)(mmioAddr + SI_SYSCFG) = temp;
|
|
||||||
*(volatile uint32 *)(mmioAddr + SI_SYSCFG); // flush
|
|
||||||
|
|
||||||
*_controllerCookie = controller;
|
|
||||||
|
|
||||||
TRACE("controller_init success\n");
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_uninit(void *controllerCookie)
|
|
||||||
{
|
|
||||||
controller_data *controller = controllerCookie;
|
|
||||||
uint32 temp;
|
|
||||||
|
|
||||||
TRACE("controller_uninit enter\n");
|
|
||||||
|
|
||||||
// disable interrupts
|
|
||||||
temp = *(volatile uint32 *)(controller->mmio_addr + SI_SYSCFG);
|
|
||||||
temp |= (controller->asic_index == ASIC_SI3114) ? SI_MASK_4PORT : SI_MASK_2PORT;
|
|
||||||
*(volatile uint32 *)(controller->mmio_addr + SI_SYSCFG) = temp;
|
|
||||||
*(volatile uint32 *)(controller->mmio_addr + SI_SYSCFG); // flush
|
|
||||||
|
|
||||||
remove_io_interrupt_handler(controller->int_num, handle_interrupt,
|
|
||||||
controller);
|
|
||||||
|
|
||||||
delete_area(controller->mmio_area);
|
|
||||||
free(controller);
|
|
||||||
|
|
||||||
TRACE("controller_uninit leave\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
controller_register_channels(void *cookie)
|
|
||||||
{
|
|
||||||
controller_data *controller = cookie;
|
|
||||||
int index;
|
|
||||||
|
|
||||||
// publish channel nodes
|
|
||||||
for (index = 0; index < kASICData[controller->asic_index].channel_count;
|
|
||||||
index++) {
|
|
||||||
device_attr attrs[] = {
|
|
||||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: DRIVER_PRETTY_NAME }},
|
|
||||||
// { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: kControllerChannelData[channelIndex].name }},
|
|
||||||
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE, { string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
|
||||||
|
|
||||||
// private data to identify channel
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: true }},
|
|
||||||
{ "silicon_image_3112/chan_index", B_UINT32_TYPE, { ui32: index }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
TRACE("publishing %s\n", kControllerChannelData[index].name);
|
|
||||||
|
|
||||||
dm->register_node(controller->node, CHANNEL_MODULE_NAME, attrs,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
controller_removed(void *controllerCookie)
|
|
||||||
{
|
|
||||||
controller_data *controller = controllerCookie;
|
|
||||||
controller->lost = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
channel_init(device_node *node, void **_channelCookie)
|
|
||||||
{
|
|
||||||
controller_data *controller;
|
|
||||||
device_node *parent;
|
|
||||||
channel_data *channel;
|
|
||||||
physical_entry entry;
|
|
||||||
size_t prdtSize;
|
|
||||||
uint32 channelIndex;
|
|
||||||
|
|
||||||
TRACE("channel_init enter\n");
|
|
||||||
|
|
||||||
channel = malloc(sizeof(channel_data));
|
|
||||||
if (!channel)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
if (dm->get_attr_uint32(node, "silicon_image_3112/chan_index", &channelIndex, false) != B_OK)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (1 /* debug */){
|
|
||||||
uint8 bus, device, function;
|
|
||||||
uint16 vendorID, deviceID;
|
|
||||||
dm->get_attr_uint8(node, PCI_DEVICE_BUS_ITEM, &bus, true);
|
|
||||||
dm->get_attr_uint8(node, PCI_DEVICE_DEVICE_ITEM, &device, true);
|
|
||||||
dm->get_attr_uint8(node, PCI_DEVICE_FUNCTION_ITEM, &function, true);
|
|
||||||
dm->get_attr_uint16(node, PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, true);
|
|
||||||
dm->get_attr_uint16(node, PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, true);
|
|
||||||
TRACE("bus %3d, device %2d, function %2d: vendor %04x, device %04x\n",
|
|
||||||
bus, device, function, vendorID, deviceID);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TRACE("channel_index %ld\n", channelIndex);
|
|
||||||
TRACE("channel name: %s\n", kControllerChannelData[channelIndex].name);
|
|
||||||
|
|
||||||
TRACE("channel %p\n", channel);
|
|
||||||
|
|
||||||
parent = dm->get_parent_node(node);
|
|
||||||
dm->get_driver(parent, NULL, (void **)&controller);
|
|
||||||
dm->put_node(parent);
|
|
||||||
|
|
||||||
TRACE("controller %p\n", controller);
|
|
||||||
TRACE("mmio_addr %p\n", (void *)controller->mmio_addr);
|
|
||||||
|
|
||||||
// PRDT must be contiguous, dword-aligned and must not cross 64K boundary
|
|
||||||
// TODO: Where's the handling for the 64 K boundary? create_area_etc() can be
|
|
||||||
// used.
|
|
||||||
prdtSize = (IDE_ADAPTER_MAX_SG_COUNT * sizeof(prd_entry) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
|
|
||||||
channel->prd_area = create_area("prd", (void **)&channel->prdt,
|
|
||||||
B_ANY_KERNEL_ADDRESS, prdtSize, B_32_BIT_CONTIGUOUS, 0);
|
|
||||||
if (channel->prd_area < B_OK) {
|
|
||||||
TRACE("creating prd_area failed\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_memory_map(channel->prdt, prdtSize, &entry, 1);
|
|
||||||
channel->prdt_phys = entry.address;
|
|
||||||
|
|
||||||
channel->pci = controller->pci;
|
|
||||||
channel->device = controller->device;
|
|
||||||
channel->node = node;
|
|
||||||
channel->ide_channel = NULL;
|
|
||||||
|
|
||||||
channel->task_file = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].cmd + 1);
|
|
||||||
channel->control_block = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].ctl);
|
|
||||||
channel->command_block = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].cmd);
|
|
||||||
channel->dev_ctrl = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].ctl);
|
|
||||||
channel->bm_prdt_address = (volatile uint32 *)(controller->mmio_addr + kControllerChannelData[channelIndex].bmdma + IDE_BM_PRDT_ADDRESS);
|
|
||||||
channel->bm_status_reg = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].bmdma + IDE_BM_STATUS_REG);
|
|
||||||
channel->bm_command_reg = (volatile uint8 *)(controller->mmio_addr + kControllerChannelData[channelIndex].bmdma + IDE_BM_COMMAND_REG);
|
|
||||||
channel->stat = (volatile uint32 *)(controller->mmio_addr + kControllerChannelData[channelIndex].stat);
|
|
||||||
|
|
||||||
channel->lost = 0;
|
|
||||||
channel->dma_active = 0;
|
|
||||||
|
|
||||||
controller->channel[channelIndex] = channel;
|
|
||||||
|
|
||||||
// enable interrupts so the channel is ready to run
|
|
||||||
device_control_write(channel, ide_devctrl_bit3);
|
|
||||||
|
|
||||||
*_channelCookie = channel;
|
|
||||||
|
|
||||||
TRACE("channel_init leave\n");
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err:
|
|
||||||
free(channel);
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_uninit(void *channelCookie)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
|
|
||||||
TRACE("channel_uninit enter\n");
|
|
||||||
|
|
||||||
// disable IRQs
|
|
||||||
device_control_write(channel, ide_devctrl_bit3 | ide_devctrl_nien);
|
|
||||||
|
|
||||||
// catch spurious interrupt
|
|
||||||
// (some controllers generate an IRQ when you _disable_ interrupts,
|
|
||||||
// they are delayed by less then 40 µs, so 1 ms is safe)
|
|
||||||
snooze(1000);
|
|
||||||
|
|
||||||
delete_area(channel->prd_area);
|
|
||||||
free(channel);
|
|
||||||
|
|
||||||
TRACE("channel_uninit leave\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
channel_removed(void *channelCookie)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
channel->lost = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_channel(void *channelCookie, ide_channel ideChannel)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
channel->ide_channel = ideChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
task_file_write(void *channelCookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
FLOW("task_file_write\n");
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
if( ((1 << (i+7)) & mask) != 0 ) {
|
|
||||||
FLOW("%x->HI(%x)\n", tf->raw.r[i + 7], i );
|
|
||||||
channel->task_file[i] = tf->raw.r[i + 7];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((1 << i) & mask) != 0) {
|
|
||||||
FLOW("%x->LO(%x)\n", tf->raw.r[i], i );
|
|
||||||
channel->task_file[i] = tf->raw.r[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
task_file_read(void *channelCookie, ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
FLOW("task_file_read\n");
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
if (((1 << i) & mask) != 0) {
|
|
||||||
tf->raw.r[i] = channel->task_file[i];
|
|
||||||
FLOW("%x: %x\n", i, (int)tf->raw.r[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
altstatus_read(void *channelCookie)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
|
|
||||||
FLOW("altstatus_read\n");
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return 0x01; // Error bit
|
|
||||||
|
|
||||||
return *channel->dev_ctrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
device_control_write(void *channelCookie, uint8 val)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
|
|
||||||
FLOW("device_control_write 0x%x\n", val);
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
*channel->dev_ctrl = val;
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
pio_write(void *channelCookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
FLOW("pio_write force_16bit = %d, (count & 1) = %d\n", force_16bit, (count & 1));
|
|
||||||
|
|
||||||
// The data port is only 8 bit wide in the command register block.
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
volatile uint16 * base = (volatile uint16 *)channel->command_block;
|
|
||||||
for ( ; count > 0; --count)
|
|
||||||
*base = *(data++);
|
|
||||||
} else {
|
|
||||||
volatile uint32 * base = (volatile uint32 *)channel->command_block;
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for ( ; count > 0; count -= 2 )
|
|
||||||
*base = *(cur_data++);
|
|
||||||
}
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
pio_read(void *channelCookie, uint16 *data, int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
FLOW("pio_read force_16bit = %d, (count & 1) = %d\n", force_16bit, (count & 1));
|
|
||||||
|
|
||||||
// The data port is only 8 bit wide in the command register block.
|
|
||||||
// We are memory mapped and read using 16 or 32 bit access from this 8 bit location.
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
volatile uint16 * base = (volatile uint16 *)channel->command_block;
|
|
||||||
for ( ; count > 0; --count)
|
|
||||||
*(data++) = *base;
|
|
||||||
} else {
|
|
||||||
volatile uint32 * base = (volatile uint32 *)channel->command_block;
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for ( ; count > 0; count -= 2 )
|
|
||||||
*(cur_data++) = *base;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_prepare(void *channelCookie, const physical_entry *sg_list,
|
|
||||||
size_t sg_list_count, bool write)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
prd_entry *prd = channel->prdt;
|
|
||||||
uint8 command;
|
|
||||||
uint8 status;
|
|
||||||
uint32 temp;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
FLOW("dma_prepare enter\n");
|
|
||||||
|
|
||||||
for (i = sg_list_count - 1, prd = channel->prdt; i >= 0;
|
|
||||||
--i, ++prd, ++sg_list ) {
|
|
||||||
prd->address = B_HOST_TO_LENDIAN_INT32(pci->ram_address(device,
|
|
||||||
(void*)(addr_t)sg_list->address));
|
|
||||||
|
|
||||||
// 0 means 64K - this is done automatically by discarding upper 16 bits
|
|
||||||
prd->count = B_HOST_TO_LENDIAN_INT16((uint16)sg_list->size);
|
|
||||||
prd->EOT = i == 0;
|
|
||||||
|
|
||||||
FLOW("%x, %x, %d\n", (int)prd->address, prd->count, prd->EOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX move this to chan init?
|
|
||||||
temp = (*channel->bm_prdt_address) & 3;
|
|
||||||
temp |= B_HOST_TO_LENDIAN_INT32(pci->ram_address(device,
|
|
||||||
(void *)(addr_t)channel->prdt_phys)) & ~3;
|
|
||||||
*channel->bm_prdt_address = temp;
|
|
||||||
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
// reset interrupt and error signal
|
|
||||||
status = *channel->bm_status_reg | IDE_BM_STATUS_INTERRUPT
|
|
||||||
| IDE_BM_STATUS_ERROR;
|
|
||||||
*channel->bm_status_reg = status;
|
|
||||||
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
// set data direction
|
|
||||||
command = *channel->bm_command_reg;
|
|
||||||
if (write)
|
|
||||||
command &= ~IDE_BM_COMMAND_READ_FROM_DEVICE;
|
|
||||||
else
|
|
||||||
command |= IDE_BM_COMMAND_READ_FROM_DEVICE;
|
|
||||||
|
|
||||||
*channel->bm_command_reg = command;
|
|
||||||
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
FLOW("dma_prepare leave\n");
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_start(void *channelCookie)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
uint8 command;
|
|
||||||
|
|
||||||
FLOW("dma_start enter\n");
|
|
||||||
|
|
||||||
command = *channel->bm_command_reg | IDE_BM_COMMAND_START_STOP;
|
|
||||||
channel->dma_active = true;
|
|
||||||
*channel->bm_command_reg = command;
|
|
||||||
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
FLOW("dma_start leave\n");
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
dma_finish(void *channelCookie)
|
|
||||||
{
|
|
||||||
channel_data *channel = channelCookie;
|
|
||||||
uint8 command;
|
|
||||||
uint8 status;
|
|
||||||
|
|
||||||
FLOW("dma_finish enter\n");
|
|
||||||
|
|
||||||
command = *channel->bm_command_reg & ~IDE_BM_COMMAND_START_STOP;
|
|
||||||
channel->dma_active = false;
|
|
||||||
|
|
||||||
*channel->bm_command_reg = command;
|
|
||||||
|
|
||||||
status = *channel->bm_status_reg;
|
|
||||||
|
|
||||||
*channel->bm_status_reg = status | IDE_BM_STATUS_INTERRUPT
|
|
||||||
| IDE_BM_STATUS_ERROR;
|
|
||||||
|
|
||||||
*channel->dev_ctrl; // read altstatus to flush
|
|
||||||
|
|
||||||
if ((status & IDE_BM_STATUS_ERROR) != 0) {
|
|
||||||
FLOW("dma_finish: failed\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((status & IDE_BM_STATUS_INTERRUPT) == 0) {
|
|
||||||
if ((status & IDE_BM_STATUS_ACTIVE) != 0) {
|
|
||||||
TRACE("dma_finish: transfer aborted\n");
|
|
||||||
return B_ERROR;
|
|
||||||
} else {
|
|
||||||
TRACE("dma_finish: buffer underrun\n");
|
|
||||||
return B_DEV_DATA_UNDERRUN;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((status & IDE_BM_STATUS_ACTIVE) != 0) {
|
|
||||||
TRACE("dma_finish: buffer too large\n");
|
|
||||||
return B_DEV_DATA_OVERRUN;
|
|
||||||
} else {
|
|
||||||
FLOW("dma_finish leave\n");
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
handle_interrupt(void *arg)
|
|
||||||
{
|
|
||||||
controller_data *controller = arg;
|
|
||||||
uint8 status;
|
|
||||||
int32 result, ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// FLOW("handle_interrupt\n");
|
|
||||||
|
|
||||||
result = B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
for (i = 0; i < controller->channel_count; i++) {
|
|
||||||
channel_data *channel = controller->channel[i];
|
|
||||||
if (!channel || channel->lost)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (channel->dma_active) {
|
|
||||||
if ((*channel->bm_status_reg & IDE_BM_STATUS_INTERRUPT) == 0)
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// for PIO, read the "Task File Configuration + Status" Interrupt
|
|
||||||
// status
|
|
||||||
if (!(*channel->stat & (1 << 11)))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// acknowledge IRQ
|
|
||||||
status = *(channel->command_block + 7);
|
|
||||||
ret = ide->irq_handler(channel->ide_channel, status);
|
|
||||||
if (ret == B_INVOKE_SCHEDULER || result == B_UNHANDLED_INTERRUPT)
|
|
||||||
result = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&dm },
|
|
||||||
{ IDE_ADAPTER_MODULE_NAME, (module_info **)&ide_adapter },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static ide_controller_interface sChannelInterface = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
CHANNEL_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
.supports_device = NULL,
|
|
||||||
.register_device = NULL,
|
|
||||||
.init_driver = &channel_init,
|
|
||||||
.uninit_driver = &channel_uninit,
|
|
||||||
.register_child_devices = NULL,
|
|
||||||
.device_removed = &channel_removed,
|
|
||||||
},
|
|
||||||
|
|
||||||
.set_channel = &set_channel,
|
|
||||||
.write_command_block_regs = &task_file_write,
|
|
||||||
.read_command_block_regs = &task_file_read,
|
|
||||||
.get_altstatus = &altstatus_read,
|
|
||||||
.write_device_control = &device_control_write,
|
|
||||||
.write_pio = &pio_write,
|
|
||||||
.read_pio = &pio_read,
|
|
||||||
.prepare_dma = &dma_prepare,
|
|
||||||
.start_dma = &dma_start,
|
|
||||||
.finish_dma = &dma_finish,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static driver_module_info sControllerInterface = {
|
|
||||||
{
|
|
||||||
CONTROLLER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
NULL
|
|
||||||
},
|
|
||||||
|
|
||||||
.supports_device = &controller_supports,
|
|
||||||
.register_device = &controller_probe,
|
|
||||||
.init_driver = &controller_init,
|
|
||||||
.uninit_driver = &controller_uninit,
|
|
||||||
.register_child_devices = &controller_register_channels,
|
|
||||||
.device_removed = &controller_removed,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
(module_info *)&sControllerInterface,
|
|
||||||
(module_info *)&sChannelInterface,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -4,7 +4,6 @@ SubInclude HAIKU_TOP src add-ons kernel generic ata_adapter ;
|
|||||||
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
|
SubInclude HAIKU_TOP src add-ons kernel generic atomizer ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic bios ;
|
SubInclude HAIKU_TOP src add-ons kernel generic bios ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
|
SubInclude HAIKU_TOP src add-ons kernel generic dpc ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic mpu401 ;
|
SubInclude HAIKU_TOP src add-ons kernel generic mpu401 ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic scsi_periph ;
|
SubInclude HAIKU_TOP src add-ons kernel generic scsi_periph ;
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel generic ide_adapter ;
|
|
||||||
|
|
||||||
UsePrivateHeaders drivers kernel ;
|
|
||||||
|
|
||||||
KernelAddon ide_adapter :
|
|
||||||
ide_adapter.cpp
|
|
||||||
;
|
|
||||||
|
|
||||||
@@ -1,845 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2002-04, Thomas Kurschel. All rights reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Generic IDE adapter library.
|
|
||||||
|
|
||||||
The correct name would be ATA adapter, but I chose the old name as it's
|
|
||||||
more widely known.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <device_manager.h>
|
|
||||||
#include <bus/PCI.h>
|
|
||||||
#include <bus/IDE.h>
|
|
||||||
#include <ide_types.h>
|
|
||||||
#include <ide_adapter.h>
|
|
||||||
#include <lendian_bitfield.h>
|
|
||||||
|
|
||||||
#define debug_level_flow 0
|
|
||||||
#define debug_level_error 3
|
|
||||||
#define debug_level_info 3
|
|
||||||
|
|
||||||
#define DEBUG_MSG_PREFIX "IDE PCI -- "
|
|
||||||
|
|
||||||
#include "wrapper.h"
|
|
||||||
|
|
||||||
#define TRACE dprintf
|
|
||||||
|
|
||||||
|
|
||||||
static ide_for_controller_interface *ide;
|
|
||||||
static device_manager_info *pnp;
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_channel(ide_adapter_channel_info *channel, ide_channel ideChannel)
|
|
||||||
{
|
|
||||||
channel->ideChannel = ideChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_write_command_block_regs(ide_adapter_channel_info *channel,
|
|
||||||
ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
// LBA48 registers must be written twice
|
|
||||||
if (((1 << (i + 7)) & mask) != 0) {
|
|
||||||
SHOW_FLOW( 4, "%x->HI(%x)", tf->raw.r[i + 7], i );
|
|
||||||
pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i + 7]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((1 << i) & mask) != 0) {
|
|
||||||
SHOW_FLOW( 4, "%x->LO(%x)", tf->raw.r[i], i );
|
|
||||||
pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_read_command_block_regs(ide_adapter_channel_info *channel,
|
|
||||||
ide_task_file *tf, ide_reg_mask mask)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
|
||||||
if (((1 << i) & mask) != 0) {
|
|
||||||
tf->raw.r[i] = pci->read_io_8(device, ioaddr + 1 + i);
|
|
||||||
SHOW_FLOW( 4, "%x: %x", i, (int)tf->raw.r[i] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uint8
|
|
||||||
ide_adapter_get_altstatus(ide_adapter_channel_info *channel)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint16 altstatusaddr = channel->control_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return 0x01; // Error bit
|
|
||||||
|
|
||||||
return pci->read_io_8(device, altstatusaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_write_device_control(ide_adapter_channel_info *channel, uint8 val)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint16 device_control_addr = channel->control_block_base;
|
|
||||||
|
|
||||||
SHOW_FLOW(3, "%x", (int)val);
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
pci->write_io_8(device, device_control_addr, val);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_write_pio(ide_adapter_channel_info *channel, uint16 *data,
|
|
||||||
int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
force_16bit = true;
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
for (; count > 0; --count)
|
|
||||||
pci->write_io_16(device, ioaddr, *(data++));
|
|
||||||
} else {
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for (; count > 0; count -= 2)
|
|
||||||
pci->write_io_32(device, ioaddr, *(cur_data++));
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_read_pio(ide_adapter_channel_info *channel, uint16 *data,
|
|
||||||
int count, bool force_16bit)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
|
|
||||||
uint16 ioaddr = channel->command_block_base;
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
force_16bit = true;
|
|
||||||
|
|
||||||
if ((count & 1) != 0 || force_16bit) {
|
|
||||||
for (; count > 0; --count)
|
|
||||||
*(data++) = pci->read_io_16(device, ioaddr );
|
|
||||||
} else {
|
|
||||||
uint32 *cur_data = (uint32 *)data;
|
|
||||||
|
|
||||||
for (; count > 0; count -= 2)
|
|
||||||
*(cur_data++) = pci->read_io_32(device, ioaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int32
|
|
||||||
ide_adapter_inthand(void *arg)
|
|
||||||
{
|
|
||||||
ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg;
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint8 status;
|
|
||||||
|
|
||||||
SHOW_FLOW0(3, "");
|
|
||||||
|
|
||||||
if (channel->lost)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
|
|
||||||
// add test whether this is really our IRQ
|
|
||||||
if (channel->dmaing) {
|
|
||||||
// in DMA mode, there is a safe test
|
|
||||||
// in PIO mode, this don't work
|
|
||||||
status = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_STATUS_REG);
|
|
||||||
if ((status & IDE_BM_STATUS_INTERRUPT) == 0)
|
|
||||||
return B_UNHANDLED_INTERRUPT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// acknowledge IRQ
|
|
||||||
status = pci->read_io_8(device, channel->command_block_base + 7);
|
|
||||||
|
|
||||||
return ide->irq_handler(channel->ideChannel, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_prepare_dma(ide_adapter_channel_info *channel,
|
|
||||||
const physical_entry *sgList, size_t sgListCount, bool writeToDevice)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint8 command;
|
|
||||||
uint8 status;
|
|
||||||
prd_entry *prd = channel->prdt;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = sgListCount - 1, prd = channel->prdt; i >= 0; --i, ++prd, ++sgList) {
|
|
||||||
prd->address = B_HOST_TO_LENDIAN_INT32(pci->ram_address(device,
|
|
||||||
(void*)(addr_t)sgList->address));
|
|
||||||
// 0 means 64K - this is done automatically be discarding upper 16 bits
|
|
||||||
prd->count = B_HOST_TO_LENDIAN_INT16((uint16)sgList->size);
|
|
||||||
prd->EOT = i == 0;
|
|
||||||
|
|
||||||
SHOW_FLOW( 4, "%x, %x, %d", (int)prd->address, prd->count, prd->EOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci->write_io_32(device, channel->bus_master_base + IDE_BM_PRDT_ADDRESS,
|
|
||||||
(pci->read_io_32(device, channel->bus_master_base + IDE_BM_PRDT_ADDRESS) & 3)
|
|
||||||
| (B_HOST_TO_LENDIAN_INT32(pci->ram_address(device, (void *)channel->prdt_phys)) & ~3));
|
|
||||||
|
|
||||||
// reset interrupt and error signal
|
|
||||||
status = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_STATUS_REG) | IDE_BM_STATUS_INTERRUPT | IDE_BM_STATUS_ERROR;
|
|
||||||
pci->write_io_8(device,
|
|
||||||
channel->bus_master_base + IDE_BM_STATUS_REG, status);
|
|
||||||
|
|
||||||
// set data direction
|
|
||||||
command = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_COMMAND_REG);
|
|
||||||
if (writeToDevice)
|
|
||||||
command &= ~IDE_BM_COMMAND_READ_FROM_DEVICE;
|
|
||||||
else
|
|
||||||
command |= IDE_BM_COMMAND_READ_FROM_DEVICE;
|
|
||||||
|
|
||||||
pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG,
|
|
||||||
command);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_start_dma(ide_adapter_channel_info *channel)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint8 command;
|
|
||||||
|
|
||||||
command = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_COMMAND_REG);
|
|
||||||
|
|
||||||
command |= IDE_BM_COMMAND_START_STOP;
|
|
||||||
channel->dmaing = true;
|
|
||||||
|
|
||||||
pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG,
|
|
||||||
command);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_finish_dma(ide_adapter_channel_info *channel)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci = channel->pci;
|
|
||||||
pci_device *device = channel->device;
|
|
||||||
uint8 command;
|
|
||||||
uint8 status, newStatus;
|
|
||||||
|
|
||||||
command = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_COMMAND_REG);
|
|
||||||
|
|
||||||
command &= ~IDE_BM_COMMAND_START_STOP;
|
|
||||||
channel->dmaing = false;
|
|
||||||
|
|
||||||
pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG,
|
|
||||||
command);
|
|
||||||
|
|
||||||
status = pci->read_io_8(device, channel->bus_master_base
|
|
||||||
+ IDE_BM_STATUS_REG);
|
|
||||||
|
|
||||||
// reset interrupt/error flags
|
|
||||||
newStatus = status | IDE_BM_STATUS_INTERRUPT | IDE_BM_STATUS_ERROR;
|
|
||||||
pci->write_io_8(device, channel->bus_master_base + IDE_BM_STATUS_REG,
|
|
||||||
newStatus);
|
|
||||||
|
|
||||||
if ((status & IDE_BM_STATUS_ERROR) != 0)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if ((status & IDE_BM_STATUS_INTERRUPT) == 0) {
|
|
||||||
if ((status & IDE_BM_STATUS_ACTIVE) != 0) {
|
|
||||||
SHOW_ERROR0( 2, "DMA transfer aborted" );
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHOW_ERROR0( 2, "DMA transfer: buffer underrun" );
|
|
||||||
return B_DEV_DATA_UNDERRUN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((status & IDE_BM_STATUS_ACTIVE) != 0) {
|
|
||||||
SHOW_ERROR0( 2, "DMA transfer: buffer too large" );
|
|
||||||
return B_DEV_DATA_OVERRUN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_init_channel(device_node *node,
|
|
||||||
ide_adapter_channel_info **cookie, size_t total_data_size,
|
|
||||||
int32 (*inthand)(void *arg))
|
|
||||||
{
|
|
||||||
ide_adapter_controller_info *controller;
|
|
||||||
ide_adapter_channel_info *channel;
|
|
||||||
uint16 command_block_base, control_block_base;
|
|
||||||
uint8 intnum;
|
|
||||||
int prdt_size;
|
|
||||||
physical_entry pe[1];
|
|
||||||
uint8 channel_index;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
TRACE("PCI-IDE: init channel...\n");
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (1 /* debug */){
|
|
||||||
uint8 bus, device, function;
|
|
||||||
uint16 vendorID, deviceID;
|
|
||||||
pnp->get_attr_uint8(node, PCI_DEVICE_BUS_ITEM, &bus, true);
|
|
||||||
pnp->get_attr_uint8(node, PCI_DEVICE_DEVICE_ITEM, &device, true);
|
|
||||||
pnp->get_attr_uint8(node, PCI_DEVICE_FUNCTION_ITEM, &function, true);
|
|
||||||
pnp->get_attr_uint16(node, PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, true);
|
|
||||||
pnp->get_attr_uint16(node, PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, true);
|
|
||||||
TRACE("PCI-IDE: bus %3d, device %2d, function %2d: vendor %04x, device %04x\n",
|
|
||||||
bus, device, function, vendorID, deviceID);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// get device data
|
|
||||||
if (pnp->get_attr_uint16(node, IDE_ADAPTER_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint16(node, IDE_ADAPTER_CONTROL_BLOCK_BASE, &control_block_base, false) != B_OK
|
|
||||||
|| pnp->get_attr_uint8(node, IDE_ADAPTER_INTNUM, &intnum, true) != B_OK
|
|
||||||
|| pnp->get_attr_uint8(node, IDE_ADAPTER_CHANNEL_INDEX, &channel_index, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
{
|
|
||||||
device_node *parent = pnp->get_parent_node(node);
|
|
||||||
pnp->get_driver(parent, NULL, (void **)&controller);
|
|
||||||
pnp->put_node(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
channel = (ide_adapter_channel_info *)malloc(total_data_size);
|
|
||||||
if (channel == NULL) {
|
|
||||||
res = B_NO_MEMORY;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("PCI-IDE: channel index %d\n", channel_index);
|
|
||||||
|
|
||||||
channel->node = node;
|
|
||||||
channel->pci = controller->pci;
|
|
||||||
channel->device = controller->device;
|
|
||||||
channel->lost = false;
|
|
||||||
channel->command_block_base = command_block_base;
|
|
||||||
channel->control_block_base = control_block_base;
|
|
||||||
channel->bus_master_base = controller->bus_master_base + (channel_index * 8);
|
|
||||||
channel->intnum = intnum;
|
|
||||||
channel->dmaing = false;
|
|
||||||
channel->inthand = inthand;
|
|
||||||
|
|
||||||
TRACE("PCI-IDE: bus master base %#x\n", channel->bus_master_base);
|
|
||||||
|
|
||||||
// PRDT must be contiguous, dword-aligned and must not cross 64K boundary
|
|
||||||
// TODO: Where's the handling for the 64 K boundary? create_area_etc() can be
|
|
||||||
// used.
|
|
||||||
prdt_size = (IDE_ADAPTER_MAX_SG_COUNT * sizeof( prd_entry ) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
|
|
||||||
channel->prd_area = create_area("prd", (void **)&channel->prdt, B_ANY_KERNEL_ADDRESS,
|
|
||||||
prdt_size, B_32_BIT_CONTIGUOUS, 0);
|
|
||||||
if (channel->prd_area < B_OK) {
|
|
||||||
res = channel->prd_area;
|
|
||||||
goto err2;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_memory_map(channel->prdt, prdt_size, pe, 1);
|
|
||||||
channel->prdt_phys = (uint32)pe[0].address;
|
|
||||||
|
|
||||||
SHOW_FLOW(3, "virt=%p, phys=%x", channel->prdt, (int)channel->prdt_phys);
|
|
||||||
|
|
||||||
res = install_io_interrupt_handler(channel->intnum,
|
|
||||||
inthand, channel, 0);
|
|
||||||
|
|
||||||
if (res < 0) {
|
|
||||||
SHOW_ERROR(0, "couldn't install irq handler @%d", channel->intnum);
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("PCI-IDE: init channel done\n");
|
|
||||||
// enable interrupts so the channel is ready to run
|
|
||||||
ide_adapter_write_device_control(channel, ide_devctrl_bit3);
|
|
||||||
|
|
||||||
*cookie = channel;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
err3:
|
|
||||||
delete_area(channel->prd_area);
|
|
||||||
err2:
|
|
||||||
err:
|
|
||||||
free(channel);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
ide_adapter_uninit_channel(ide_adapter_channel_info *channel)
|
|
||||||
{
|
|
||||||
// disable IRQs
|
|
||||||
ide_adapter_write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien);
|
|
||||||
|
|
||||||
// catch spurious interrupt
|
|
||||||
// (some controllers generate an IRQ when you _disable_ interrupts,
|
|
||||||
// they are delayed by less then 40 µs, so 1 ms is safe)
|
|
||||||
snooze(1000);
|
|
||||||
|
|
||||||
remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
|
|
||||||
|
|
||||||
delete_area(channel->prd_area);
|
|
||||||
free(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
ide_adapter_channel_removed(ide_adapter_channel_info *channel)
|
|
||||||
{
|
|
||||||
SHOW_FLOW0( 3, "" );
|
|
||||||
|
|
||||||
if (channel != NULL)
|
|
||||||
// disable access instantly
|
|
||||||
atomic_or((int32*)&channel->lost, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** publish node of ide channel */
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_publish_channel(device_node *controller_node,
|
|
||||||
const char *channel_module_name, uint16 command_block_base,
|
|
||||||
uint16 control_block_base, uint8 intnum, bool can_dma,
|
|
||||||
uint8 channel_index, const char *name, const io_resource *resources,
|
|
||||||
device_node **node)
|
|
||||||
{
|
|
||||||
char prettyName[25];
|
|
||||||
sprintf(prettyName, "IDE Channel %" B_PRIu8, channel_index);
|
|
||||||
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// info about ourself and our consumer
|
|
||||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
|
|
||||||
{ string: prettyName }},
|
|
||||||
{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
|
|
||||||
{ string: IDE_FOR_CONTROLLER_MODULE_NAME }},
|
|
||||||
|
|
||||||
// private data to identify channel
|
|
||||||
{ IDE_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE,
|
|
||||||
{ ui16: command_block_base }},
|
|
||||||
{ IDE_ADAPTER_CONTROL_BLOCK_BASE, B_UINT16_TYPE,
|
|
||||||
{ ui16: control_block_base }},
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: can_dma }},
|
|
||||||
{ IDE_ADAPTER_INTNUM, B_UINT8_TYPE, { ui8: intnum }},
|
|
||||||
{ IDE_ADAPTER_CHANNEL_INDEX, B_UINT8_TYPE, { ui8: channel_index }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0(2, "");
|
|
||||||
|
|
||||||
return pnp->register_node(controller_node, channel_module_name, attrs,
|
|
||||||
resources, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** detect IDE channel */
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_detect_channel(pci_device_module_info *pci, pci_device *pci_device,
|
|
||||||
device_node *controller_node, const char *channel_module_name,
|
|
||||||
bool controller_can_dma, uint16 command_block_base, uint16 control_block_base,
|
|
||||||
uint16 bus_master_base, uint8 intnum, uint8 channel_index, const char *name,
|
|
||||||
device_node **node, bool supports_compatibility_mode)
|
|
||||||
{
|
|
||||||
uint8 api;
|
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
|
||||||
|
|
||||||
// if channel works in compatibility mode, addresses and interrupt are fixed
|
|
||||||
api = pci->read_pci_config(pci_device, PCI_class_api, 1);
|
|
||||||
|
|
||||||
if (supports_compatibility_mode
|
|
||||||
&& channel_index == 0 && (api & PCI_ide_primary_native) == 0) {
|
|
||||||
command_block_base = 0x1f0;
|
|
||||||
control_block_base = 0x3f6;
|
|
||||||
intnum = 14;
|
|
||||||
TRACE("PCI-IDE: Controller in legacy mode: cmd %#x, ctrl %#x, irq %d\n",
|
|
||||||
command_block_base, control_block_base, intnum);
|
|
||||||
} else if (supports_compatibility_mode
|
|
||||||
&& channel_index == 1 && (api & PCI_ide_secondary_native) == 0) {
|
|
||||||
command_block_base = 0x170;
|
|
||||||
control_block_base = 0x376;
|
|
||||||
intnum = 15;
|
|
||||||
TRACE("PCI-IDE: Controller in legacy mode: cmd %#x, ctrl %#x, irq %d\n",
|
|
||||||
command_block_base, control_block_base, intnum);
|
|
||||||
} else {
|
|
||||||
if (command_block_base == 0 || control_block_base == 0) {
|
|
||||||
TRACE("PCI-IDE: Command/Control Block base is not configured\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
if (intnum == 0 || intnum == 0xff) {
|
|
||||||
TRACE("PCI-IDE: Interrupt is not configured\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// historically, they start at 3f6h/376h, but PCI spec requires registers
|
|
||||||
// to be aligned at 4 bytes, so only 3f4h/374h can be specified; thus
|
|
||||||
// PCI IDE defines that control block starts at offset 2
|
|
||||||
control_block_base += 2;
|
|
||||||
TRACE("PCI-IDE: Controller in native mode: cmd %#x, ctrl %#x, irq %d\n",
|
|
||||||
command_block_base, control_block_base, intnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supports_compatibility_mode) {
|
|
||||||
// read status of primary(!) channel to detect simplex
|
|
||||||
uint8 status = pci->read_io_8(pci_device, bus_master_base
|
|
||||||
+ IDE_BM_STATUS_REG);
|
|
||||||
|
|
||||||
if (status & IDE_BM_STATUS_SIMPLEX_DMA && channel_index != 0) {
|
|
||||||
// in simplex mode, channels cannot operate independantly of each other;
|
|
||||||
// we simply disable bus mastering of second channel to satisfy that;
|
|
||||||
// better were to use a controller lock, but this had to be done in the IDE
|
|
||||||
// bus manager, and I don't see any reason to add extra code for old
|
|
||||||
// simplex controllers
|
|
||||||
TRACE("PCI-IDE: Simplex controller - disabling DMA of secondary channel\n");
|
|
||||||
controller_can_dma = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
io_resource resources[3] = {
|
|
||||||
{ B_IO_PORT, command_block_base, 8 },
|
|
||||||
{ B_IO_PORT, control_block_base, 1 },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
return ide_adapter_publish_channel(controller_node, channel_module_name,
|
|
||||||
command_block_base, control_block_base, intnum, controller_can_dma,
|
|
||||||
channel_index, name, resources, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_init_controller(device_node *node,
|
|
||||||
ide_adapter_controller_info **cookie, size_t total_data_size)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
ide_adapter_controller_info *controller;
|
|
||||||
uint16 bus_master_base;
|
|
||||||
// uint16 pcicmd;
|
|
||||||
|
|
||||||
// get device data
|
|
||||||
if (pnp->get_attr_uint16(node, IDE_ADAPTER_BUS_MASTER_BASE, &bus_master_base, false) != B_OK)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
{
|
|
||||||
device_node *parent = pnp->get_parent_node(node);
|
|
||||||
pnp->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
|
|
||||||
pnp->put_node(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
controller = (ide_adapter_controller_info *)malloc(total_data_size);
|
|
||||||
if (controller == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
pcicmd = pci->read_pci_config(node, PCI_command, 2);
|
|
||||||
TRACE("PCI-IDE: adapter init: pcicmd old setting 0x%04x\n", pcicmd);
|
|
||||||
if ((pcicmd & PCI_command_io) == 0) {
|
|
||||||
TRACE("PCI-IDE: adapter init: enabling io decoder\n");
|
|
||||||
pcicmd |= PCI_command_io;
|
|
||||||
}
|
|
||||||
if ((pcicmd & PCI_command_master) == 0) {
|
|
||||||
TRACE("PCI-IDE: adapter init: enabling bus mastering\n");
|
|
||||||
pcicmd |= PCI_command_master;
|
|
||||||
}
|
|
||||||
pci->write_pci_config(node, PCI_command, 2, pcicmd);
|
|
||||||
TRACE("PCI-IDE: adapter init: pcicmd new setting 0x%04x\n", pci->read_pci_config(node, PCI_command, 2));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
controller->node = node;
|
|
||||||
controller->pci = pci;
|
|
||||||
controller->device = device;
|
|
||||||
controller->lost = false;
|
|
||||||
controller->bus_master_base = bus_master_base;
|
|
||||||
|
|
||||||
*cookie = controller;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
ide_adapter_uninit_controller(ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
free(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
ide_adapter_controller_removed(ide_adapter_controller_info *controller)
|
|
||||||
{
|
|
||||||
SHOW_FLOW0(3, "");
|
|
||||||
|
|
||||||
if (controller != NULL) {
|
|
||||||
// disable access instantly; unit_device takes care of unregistering ioports
|
|
||||||
atomic_or((int32*)&controller->lost, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** publish node of ide controller */
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_publish_controller(device_node *parent, uint16 bus_master_base,
|
|
||||||
io_resource *resources, const char *controller_driver,
|
|
||||||
const char *controller_driver_type, const char *controller_name, bool can_dma,
|
|
||||||
bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
|
|
||||||
device_node **node)
|
|
||||||
{
|
|
||||||
device_attr attrs[] = {
|
|
||||||
// properties of this controller for ide bus manager
|
|
||||||
// there are always max. 2 devices
|
|
||||||
// (unless this is a Compact Flash Card with a built-in IDE controller,
|
|
||||||
// which has exactly 1 device)
|
|
||||||
{ IDE_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
|
|
||||||
// of course we can DMA
|
|
||||||
{ IDE_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: can_dma }},
|
|
||||||
// command queuing always works (unless controller is buggy)
|
|
||||||
{ IDE_CONTROLLER_CAN_CQ_ITEM, B_UINT8_TYPE, { ui8: can_cq }},
|
|
||||||
// choose any name here
|
|
||||||
{ IDE_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE,
|
|
||||||
{ string: controller_name }},
|
|
||||||
|
|
||||||
// DMA properties
|
|
||||||
// data must be word-aligned;
|
|
||||||
// warning: some controllers are more picky!
|
|
||||||
{ B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: dma_alignment /*1*/}},
|
|
||||||
// one S/G block must not cross 64K boundary
|
|
||||||
{ B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: dma_boundary/*0xffff*/ }},
|
|
||||||
// max size of S/G block is 16 bits with zero being 64K
|
|
||||||
{ B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE,
|
|
||||||
{ ui32: max_sg_block_size/*0x10000*/ }},
|
|
||||||
{ B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
|
|
||||||
{ ui32: IDE_ADAPTER_MAX_SG_COUNT }},
|
|
||||||
{ B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
|
|
||||||
|
|
||||||
// private data to find controller
|
|
||||||
{ IDE_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: bus_master_base }},
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0( 2, "" );
|
|
||||||
|
|
||||||
return pnp->register_node(parent, controller_driver, attrs, resources, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** detect pure IDE controller, i.e. without channels */
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_detect_controller(pci_device_module_info *pci, pci_device *pci_device,
|
|
||||||
device_node *parent, uint16 bus_master_base, const char *controller_driver,
|
|
||||||
const char *controller_driver_type, const char *controller_name, bool can_dma,
|
|
||||||
bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 max_sg_block_size,
|
|
||||||
device_node **node)
|
|
||||||
{
|
|
||||||
io_resource resources[2] = {
|
|
||||||
{ B_IO_PORT, bus_master_base, 16 },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
|
||||||
|
|
||||||
if (bus_master_base == 0) {
|
|
||||||
TRACE("PCI-IDE: Controller detection failed! bus master base not configured\n");
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ide_adapter_publish_controller(parent, bus_master_base, resources,
|
|
||||||
controller_driver, controller_driver_type, controller_name, can_dma, can_cq,
|
|
||||||
dma_alignment, dma_boundary, max_sg_block_size, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
ide_adapter_probe_controller(device_node *parent, const char *controller_driver,
|
|
||||||
const char *controller_driver_type, const char *controller_name,
|
|
||||||
const char *channel_module_name, bool can_dma, bool can_cq, uint32 dma_alignment,
|
|
||||||
uint32 dma_boundary, uint32 max_sg_block_size, bool supports_compatibility_mode)
|
|
||||||
{
|
|
||||||
pci_device_module_info *pci;
|
|
||||||
pci_device *device;
|
|
||||||
uint16 command_block_base[2];
|
|
||||||
uint16 control_block_base[2];
|
|
||||||
uint16 bus_master_base;
|
|
||||||
device_node *controller_node;
|
|
||||||
device_node *channels[2];
|
|
||||||
uint8 intnum;
|
|
||||||
status_t res;
|
|
||||||
|
|
||||||
SHOW_FLOW0( 3, "" );
|
|
||||||
|
|
||||||
pnp->get_driver(parent, (driver_module_info **)&pci, (void **)&device);
|
|
||||||
|
|
||||||
command_block_base[0] = pci->read_pci_config(device, PCI_base_registers, 4 );
|
|
||||||
control_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 4, 4);
|
|
||||||
command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 8, 4);
|
|
||||||
control_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 12, 4);
|
|
||||||
bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 4);
|
|
||||||
intnum = pci->read_pci_config(device, PCI_interrupt_line, 1);
|
|
||||||
|
|
||||||
command_block_base[0] &= PCI_address_io_mask;
|
|
||||||
control_block_base[0] &= PCI_address_io_mask;
|
|
||||||
command_block_base[1] &= PCI_address_io_mask;
|
|
||||||
control_block_base[1] &= PCI_address_io_mask;
|
|
||||||
bus_master_base &= PCI_address_io_mask;
|
|
||||||
|
|
||||||
res = ide_adapter_detect_controller(pci, device, parent, bus_master_base,
|
|
||||||
controller_driver, controller_driver_type, controller_name, can_dma,
|
|
||||||
can_cq, dma_alignment, dma_boundary, max_sg_block_size, &controller_node);
|
|
||||||
// don't register if controller is already registered!
|
|
||||||
// (happens during rescan; registering new channels would kick out old channels)
|
|
||||||
if (res != B_OK || controller_node == NULL)
|
|
||||||
return res;
|
|
||||||
|
|
||||||
// ignore errors during registration of channels - could be a simple rescan collision
|
|
||||||
ide_adapter_detect_channel(pci, device, controller_node, channel_module_name,
|
|
||||||
can_dma, command_block_base[0], control_block_base[0], bus_master_base,
|
|
||||||
intnum, 0, "Primary Channel", &channels[0], supports_compatibility_mode);
|
|
||||||
|
|
||||||
ide_adapter_detect_channel(pci, device, controller_node, channel_module_name,
|
|
||||||
can_dma, command_block_base[1], control_block_base[1], bus_master_base,
|
|
||||||
intnum, 1, "Secondary Channel", &channels[1], supports_compatibility_mode);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
std_ops(int32 op, ...)
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
case B_MODULE_INIT:
|
|
||||||
case B_MODULE_UNINIT:
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module_dependency module_dependencies[] = {
|
|
||||||
{ IDE_FOR_CONTROLLER_MODULE_NAME, (module_info **)&ide },
|
|
||||||
{ B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static ide_adapter_interface adapter_interface = {
|
|
||||||
{
|
|
||||||
IDE_ADAPTER_MODULE_NAME,
|
|
||||||
0,
|
|
||||||
std_ops
|
|
||||||
},
|
|
||||||
|
|
||||||
set_channel,
|
|
||||||
|
|
||||||
ide_adapter_write_command_block_regs,
|
|
||||||
ide_adapter_read_command_block_regs,
|
|
||||||
|
|
||||||
ide_adapter_get_altstatus,
|
|
||||||
ide_adapter_write_device_control,
|
|
||||||
|
|
||||||
ide_adapter_write_pio,
|
|
||||||
ide_adapter_read_pio,
|
|
||||||
|
|
||||||
ide_adapter_prepare_dma,
|
|
||||||
ide_adapter_start_dma,
|
|
||||||
ide_adapter_finish_dma,
|
|
||||||
|
|
||||||
ide_adapter_inthand,
|
|
||||||
|
|
||||||
ide_adapter_init_channel,
|
|
||||||
ide_adapter_uninit_channel,
|
|
||||||
ide_adapter_channel_removed,
|
|
||||||
|
|
||||||
ide_adapter_publish_channel,
|
|
||||||
ide_adapter_detect_channel,
|
|
||||||
|
|
||||||
ide_adapter_init_controller,
|
|
||||||
ide_adapter_uninit_controller,
|
|
||||||
ide_adapter_controller_removed,
|
|
||||||
|
|
||||||
ide_adapter_publish_controller,
|
|
||||||
ide_adapter_detect_controller,
|
|
||||||
|
|
||||||
ide_adapter_probe_controller
|
|
||||||
};
|
|
||||||
|
|
||||||
module_info *modules[] = {
|
|
||||||
&adapter_interface.info,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
#ifndef _WRAPPER_H
|
|
||||||
#define _WRAPPER_H
|
|
||||||
|
|
||||||
#include <KernelExport.h>
|
|
||||||
#include <lock.h>
|
|
||||||
|
|
||||||
|
|
||||||
// benaphores
|
|
||||||
|
|
||||||
#define INIT_BEN(x, prefix) (mutex_init_etc(x, prefix, MUTEX_FLAG_CLONE_NAME), \
|
|
||||||
B_OK)
|
|
||||||
#define DELETE_BEN(x) mutex_destroy(x)
|
|
||||||
#define ACQUIRE_BEN(x) mutex_lock(x)
|
|
||||||
#define RELEASE_BEN(x) mutex_unlock(x)
|
|
||||||
|
|
||||||
// debug output
|
|
||||||
|
|
||||||
#ifdef DEBUG_WAIT_ON_MSG
|
|
||||||
# define DEBUG_WAIT snooze( DEBUG_WAIT_ON_MSG );
|
|
||||||
#else
|
|
||||||
# define DEBUG_WAIT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_WAIT_ON_ERROR
|
|
||||||
# define DEBUG_WAIT_ERROR snooze( DEBUG_WAIT_ON_ERROR );
|
|
||||||
#else
|
|
||||||
# define DEBUG_WAIT_ERROR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_FLOW
|
|
||||||
# define DEBUG_MAX_LEVEL_FLOW 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_INFO
|
|
||||||
# define DEBUG_MAX_LEVEL_INFO 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MAX_LEVEL_ERROR
|
|
||||||
# define DEBUG_MAX_LEVEL_ERROR 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef DEBUG_MSG_PREFIX
|
|
||||||
# define DEBUG_MSG_PREFIX ""
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_flow
|
|
||||||
# define debug_level_flow 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_info
|
|
||||||
# define debug_level_info 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef debug_level_error
|
|
||||||
# define debug_level_error 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FUNC_NAME DEBUG_MSG_PREFIX, __FUNCTION__
|
|
||||||
|
|
||||||
#define SHOW_FLOW(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_FLOW0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_flow && seriousness <= DEBUG_MAX_LEVEL_FLOW ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_INFO(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_INFO0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_info && seriousness <= DEBUG_MAX_LEVEL_INFO ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_ERROR(seriousness, format, param...) \
|
|
||||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME, param ); DEBUG_WAIT_ERROR \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#define SHOW_ERROR0(seriousness, format) \
|
|
||||||
do { if( seriousness <= debug_level_error && seriousness <= DEBUG_MAX_LEVEL_ERROR ) { \
|
|
||||||
dprintf( "%s%s: "format"\n", FUNC_NAME); DEBUG_WAIT_ERROR \
|
|
||||||
}} while( 0 )
|
|
||||||
|
|
||||||
#endif /* _BENAPHORE_H */
|
|
||||||
Reference in New Issue
Block a user