Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 *  Q40 I/O port IDE Driver
  3 *
  4 *     (c) Richard Zidlicky
  5 *
  6 *  This file is subject to the terms and conditions of the GNU General Public
  7 *  License.  See the file COPYING in the main directory of this archive for
  8 *  more details.
  9 *
 10 *
 11 */
 12
 13#include <linux/types.h>
 14#include <linux/mm.h>
 15#include <linux/interrupt.h>
 16#include <linux/blkdev.h>
 17#include <linux/ide.h>
 
 18
 19#include <asm/ide.h>
 20
 21    /*
 22     *  Bases of the IDE interfaces
 23     */
 24
 25#define Q40IDE_NUM_HWIFS	2
 26
 27#define PCIDE_BASE1	0x1f0
 28#define PCIDE_BASE2	0x170
 29#define PCIDE_BASE3	0x1e8
 30#define PCIDE_BASE4	0x168
 31#define PCIDE_BASE5	0x1e0
 32#define PCIDE_BASE6	0x160
 33
 34static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
 35    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
 36    PCIDE_BASE6 */
 37};
 38
 39static int q40ide_default_irq(unsigned long base)
 40{
 41           switch (base) {
 42	            case 0x1f0: return 14;
 43		    case 0x170: return 15;
 44		    case 0x1e8: return 11;
 45		    default:
 46			return 0;
 47	   }
 48}
 49
 50
 51/*
 52 * Addresses are pretranslated for Q40 ISA access.
 53 */
 54static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
 55{
 56	memset(hw, 0, sizeof(*hw));
 57	/* BIG FAT WARNING: 
 58	   assumption: only DATA port is ever used in 16 bit mode */
 59	hw->io_ports.data_addr = Q40_ISA_IO_W(base);
 60	hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
 61	hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
 62	hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
 63	hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
 64	hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
 65	hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
 66	hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
 67	hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
 68
 69	hw->irq = irq;
 70}
 71
 72static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
 73			      void *buf, unsigned int len)
 74{
 75	unsigned long data_addr = drive->hwif->io_ports.data_addr;
 76
 77	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
 78		__ide_mm_insw(data_addr, buf, (len + 1) / 2);
 79		return;
 80	}
 81
 82	raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 83}
 84
 85static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
 86			       void *buf, unsigned int len)
 87{
 88	unsigned long data_addr = drive->hwif->io_ports.data_addr;
 89
 90	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
 91		__ide_mm_outsw(data_addr, buf, (len + 1) / 2);
 92		return;
 93	}
 94
 95	raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 96}
 97
 98/* Q40 has a byte-swapped IDE interface */
 99static const struct ide_tp_ops q40ide_tp_ops = {
100	.exec_command		= ide_exec_command,
101	.read_status		= ide_read_status,
102	.read_altstatus		= ide_read_altstatus,
103	.write_devctl		= ide_write_devctl,
104
105	.dev_select		= ide_dev_select,
106	.tf_load		= ide_tf_load,
107	.tf_read		= ide_tf_read,
108
109	.input_data		= q40ide_input_data,
110	.output_data		= q40ide_output_data,
111};
112
113static const struct ide_port_info q40ide_port_info = {
114	.tp_ops			= &q40ide_tp_ops,
115	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
116	.irq_flags		= IRQF_SHARED,
117	.chipset		= ide_generic,
118};
119
120/* 
121 * the static array is needed to have the name reported in /proc/ioports,
122 * hwif->name unfortunately isn't available yet
123 */
124static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
125	"ide0", "ide1"
126};
127
128/*
129 *  Probe for Q40 IDE interfaces
130 */
131
132static int __init q40ide_init(void)
133{
134    int i;
135    struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
136
137    if (!MACH_IS_Q40)
138      return -ENODEV;
139
140    printk(KERN_INFO "ide: Q40 IDE controller\n");
141
142    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
143	const char *name = q40_ide_names[i];
144
145	if (!request_region(pcide_bases[i], 8, name)) {
146		printk("could not reserve ports %lx-%lx for %s\n",
147		       pcide_bases[i],pcide_bases[i]+8,name);
148		continue;
149	}
150	if (!request_region(pcide_bases[i]+0x206, 1, name)) {
151		printk("could not reserve port %lx for %s\n",
152		       pcide_bases[i]+0x206,name);
153		release_region(pcide_bases[i], 8);
154		continue;
155	}
156	q40_ide_setup_ports(&hw[i], pcide_bases[i],
157			q40ide_default_irq(pcide_bases[i]));
158
159	hws[i] = &hw[i];
160    }
161
162    return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
163}
164
165module_init(q40ide_init);
166
167MODULE_LICENSE("GPL");
v3.15
  1/*
  2 *  Q40 I/O port IDE Driver
  3 *
  4 *     (c) Richard Zidlicky
  5 *
  6 *  This file is subject to the terms and conditions of the GNU General Public
  7 *  License.  See the file COPYING in the main directory of this archive for
  8 *  more details.
  9 *
 10 *
 11 */
 12
 13#include <linux/types.h>
 14#include <linux/mm.h>
 15#include <linux/interrupt.h>
 16#include <linux/blkdev.h>
 17#include <linux/ide.h>
 18#include <linux/module.h>
 19
 20#include <asm/ide.h>
 21
 22    /*
 23     *  Bases of the IDE interfaces
 24     */
 25
 26#define Q40IDE_NUM_HWIFS	2
 27
 28#define PCIDE_BASE1	0x1f0
 29#define PCIDE_BASE2	0x170
 30#define PCIDE_BASE3	0x1e8
 31#define PCIDE_BASE4	0x168
 32#define PCIDE_BASE5	0x1e0
 33#define PCIDE_BASE6	0x160
 34
 35static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
 36    PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4  , PCIDE_BASE5,
 37    PCIDE_BASE6 */
 38};
 39
 40static int q40ide_default_irq(unsigned long base)
 41{
 42           switch (base) {
 43	            case 0x1f0: return 14;
 44		    case 0x170: return 15;
 45		    case 0x1e8: return 11;
 46		    default:
 47			return 0;
 48	   }
 49}
 50
 51
 52/*
 53 * Addresses are pretranslated for Q40 ISA access.
 54 */
 55static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
 56{
 57	memset(hw, 0, sizeof(*hw));
 58	/* BIG FAT WARNING: 
 59	   assumption: only DATA port is ever used in 16 bit mode */
 60	hw->io_ports.data_addr = Q40_ISA_IO_W(base);
 61	hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
 62	hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
 63	hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
 64	hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
 65	hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
 66	hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
 67	hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
 68	hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
 69
 70	hw->irq = irq;
 71}
 72
 73static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
 74			      void *buf, unsigned int len)
 75{
 76	unsigned long data_addr = drive->hwif->io_ports.data_addr;
 77
 78	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
 79		__ide_mm_insw(data_addr, buf, (len + 1) / 2);
 80		return;
 81	}
 82
 83	raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 84}
 85
 86static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
 87			       void *buf, unsigned int len)
 88{
 89	unsigned long data_addr = drive->hwif->io_ports.data_addr;
 90
 91	if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
 92		__ide_mm_outsw(data_addr, buf, (len + 1) / 2);
 93		return;
 94	}
 95
 96	raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
 97}
 98
 99/* Q40 has a byte-swapped IDE interface */
100static const struct ide_tp_ops q40ide_tp_ops = {
101	.exec_command		= ide_exec_command,
102	.read_status		= ide_read_status,
103	.read_altstatus		= ide_read_altstatus,
104	.write_devctl		= ide_write_devctl,
105
106	.dev_select		= ide_dev_select,
107	.tf_load		= ide_tf_load,
108	.tf_read		= ide_tf_read,
109
110	.input_data		= q40ide_input_data,
111	.output_data		= q40ide_output_data,
112};
113
114static const struct ide_port_info q40ide_port_info = {
115	.tp_ops			= &q40ide_tp_ops,
116	.host_flags		= IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
117	.irq_flags		= IRQF_SHARED,
118	.chipset		= ide_generic,
119};
120
121/* 
122 * the static array is needed to have the name reported in /proc/ioports,
123 * hwif->name unfortunately isn't available yet
124 */
125static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
126	"ide0", "ide1"
127};
128
129/*
130 *  Probe for Q40 IDE interfaces
131 */
132
133static int __init q40ide_init(void)
134{
135    int i;
136    struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
137
138    if (!MACH_IS_Q40)
139      return -ENODEV;
140
141    printk(KERN_INFO "ide: Q40 IDE controller\n");
142
143    for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
144	const char *name = q40_ide_names[i];
145
146	if (!request_region(pcide_bases[i], 8, name)) {
147		printk("could not reserve ports %lx-%lx for %s\n",
148		       pcide_bases[i],pcide_bases[i]+8,name);
149		continue;
150	}
151	if (!request_region(pcide_bases[i]+0x206, 1, name)) {
152		printk("could not reserve port %lx for %s\n",
153		       pcide_bases[i]+0x206,name);
154		release_region(pcide_bases[i], 8);
155		continue;
156	}
157	q40_ide_setup_ports(&hw[i], pcide_bases[i],
158			q40ide_default_irq(pcide_bases[i]));
159
160	hws[i] = &hw[i];
161    }
162
163    return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
164}
165
166module_init(q40ide_init);
167
168MODULE_LICENSE("GPL");