q40ide.c 4.2 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *  Q40 I/O port IDE Driver
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 *     (c) Richard Zidlicky
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License.  See the file COPYING in the main directory of this archive for
 *  more details.
 *
 *
 */

#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/ide.h>

19 20
#include <asm/ide.h>

L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
    /*
     *  Bases of the IDE interfaces
     */

#define Q40IDE_NUM_HWIFS	2

#define PCIDE_BASE1	0x1f0
#define PCIDE_BASE2	0x170
#define PCIDE_BASE3	0x1e8
#define PCIDE_BASE4	0x168
#define PCIDE_BASE5	0x1e0
#define PCIDE_BASE6	0x160

static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
    PCIDE_BASE6 */
};

static int q40ide_default_irq(unsigned long base)
{
           switch (base) {
	            case 0x1f0: return 14;
		    case 0x170: return 15;
		    case 0x1e8: return 11;
		    default:
			return 0;
	   }
}


/*
52
 * Addresses are pretranslated for Q40 ISA access.
L
Linus Torvalds 已提交
53
 */
A
Al Viro 已提交
54
static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base,
L
Linus Torvalds 已提交
55 56 57
			ide_ack_intr_t *ack_intr,
			int irq)
{
58
	memset(hw, 0, sizeof(hw_regs_t));
A
Al Viro 已提交
59 60 61 62 63 64 65 66 67 68 69
	/* BIG FAT WARNING: 
	   assumption: only DATA port is ever used in 16 bit mode */
	hw->io_ports.data_addr = Q40_ISA_IO_W(base);
	hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
	hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
	hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
	hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
	hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
	hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
	hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
	hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
70

L
Linus Torvalds 已提交
71 72
	hw->irq = irq;
	hw->ack_intr = ack_intr;
73 74

	hw->chipset = ide_generic;
L
Linus Torvalds 已提交
75 76
}

77
static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
78
			      void *buf, unsigned int len)
79
{
80
	unsigned long data_addr = drive->hwif->io_ports.data_addr;
81

82 83 84 85
	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
		__ide_mm_insw(data_addr, buf, (len + 1) / 2);
		return;
	}
86

87
	raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
88 89
}

90
static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
91
			       void *buf, unsigned int len)
92
{
93 94
	unsigned long data_addr = drive->hwif->io_ports.data_addr;

95 96 97 98
	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
		__ide_mm_outsw(data_addr, buf, (len + 1) / 2);
		return;
	}
99

100
	raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
101
}
L
Linus Torvalds 已提交
102

103 104 105 106 107
/* Q40 has a byte-swapped IDE interface */
static const struct ide_tp_ops q40ide_tp_ops = {
	.exec_command		= ide_exec_command,
	.read_status		= ide_read_status,
	.read_altstatus		= ide_read_altstatus,
108
	.write_devctl		= ide_write_devctl,
109

110
	.dev_select		= ide_dev_select,
111 112 113 114 115 116 117 118 119
	.tf_load		= ide_tf_load,
	.tf_read		= ide_tf_read,

	.input_data		= q40ide_input_data,
	.output_data		= q40ide_output_data,
};

static const struct ide_port_info q40ide_port_info = {
	.tp_ops			= &q40ide_tp_ops,
120
	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
121
	.irq_flags		= IRQF_SHARED,
122 123
};

L
Linus Torvalds 已提交
124 125
/* 
 * the static array is needed to have the name reported in /proc/ioports,
126
 * hwif->name unfortunately isn't available yet
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134 135
 */
static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
	"ide0", "ide1"
};

/*
 *  Probe for Q40 IDE interfaces
 */

136
static int __init q40ide_init(void)
L
Linus Torvalds 已提交
137 138
{
    int i;
139
    hw_regs_t hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL, NULL, NULL };
L
Linus Torvalds 已提交
140 141

    if (!MACH_IS_Q40)
142
      return -ENODEV;
L
Linus Torvalds 已提交
143

144 145
    printk(KERN_INFO "ide: Q40 IDE controller\n");

L
Linus Torvalds 已提交
146
    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
147
	const char *name = q40_ide_names[i];
L
Linus Torvalds 已提交
148 149 150 151 152 153 154 155 156 157 158 159

	if (!request_region(pcide_bases[i], 8, name)) {
		printk("could not reserve ports %lx-%lx for %s\n",
		       pcide_bases[i],pcide_bases[i]+8,name);
		continue;
	}
	if (!request_region(pcide_bases[i]+0x206, 1, name)) {
		printk("could not reserve port %lx for %s\n",
		       pcide_bases[i]+0x206,name);
		release_region(pcide_bases[i], 8);
		continue;
	}
160
	q40_ide_setup_ports(&hw[i], pcide_bases[i], NULL,
L
Linus Torvalds 已提交
161
			q40ide_default_irq(pcide_bases[i]));
162

163
	hws[i] = &hw[i];
L
Linus Torvalds 已提交
164
    }
165

166
    return ide_host_add(&q40ide_port_info, hws, NULL);
L
Linus Torvalds 已提交
167 168
}

169
module_init(q40ide_init);
170 171

MODULE_LICENSE("GPL");