diff options
Diffstat (limited to 'arch/m68k/amiga/amiints.c')
| -rw-r--r-- | arch/m68k/amiga/amiints.c | 380 | 
1 files changed, 35 insertions, 345 deletions
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index e2d47b7bdfc1..f9403f4640a1 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c @@ -35,62 +35,30 @@   *           /Jes   */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/kernel_stat.h>  #include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/errno.h> -#include <linux/seq_file.h> -#include <asm/system.h>  #include <asm/irq.h>  #include <asm/traps.h>  #include <asm/amigahw.h>  #include <asm/amigaints.h>  #include <asm/amipcmcia.h> -extern int cia_request_irq(struct ciabase *base,int irq, -                           irqreturn_t (*handler)(int, void *, struct pt_regs *), -                           unsigned long flags, const char *devname, void *dev_id); -extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id); -extern void cia_init_IRQ(struct ciabase *base); -extern int cia_get_irq_list(struct ciabase *base, struct seq_file *p); +static void amiga_enable_irq(unsigned int irq); +static void amiga_disable_irq(unsigned int irq); +static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp); +static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp); -/* irq node variables for amiga interrupt sources */ -static irq_node_t *ami_irq_list[AMI_STD_IRQS]; - -static unsigned short amiga_intena_vals[AMI_STD_IRQS] = { -	[IRQ_AMIGA_VERTB-IRQ_USER]	= IF_VERTB, -	[IRQ_AMIGA_COPPER-IRQ_USER]	= IF_COPER, -	[IRQ_AMIGA_AUD0-IRQ_USER]	= IF_AUD0, -	[IRQ_AMIGA_AUD1-IRQ_USER]	= IF_AUD1, -	[IRQ_AMIGA_AUD2-IRQ_USER]	= IF_AUD2, -	[IRQ_AMIGA_AUD3-IRQ_USER]	= IF_AUD3, -	[IRQ_AMIGA_BLIT-IRQ_USER]	= IF_BLIT, -	[IRQ_AMIGA_DSKSYN-IRQ_USER]	= IF_DSKSYN, -	[IRQ_AMIGA_DSKBLK-IRQ_USER]	= IF_DSKBLK, -	[IRQ_AMIGA_RBF-IRQ_USER]	= IF_RBF, -	[IRQ_AMIGA_TBE-IRQ_USER]	= IF_TBE, -	[IRQ_AMIGA_SOFT-IRQ_USER]	= IF_SOFT, -	[IRQ_AMIGA_PORTS-IRQ_USER]	= IF_PORTS, -	[IRQ_AMIGA_EXTER-IRQ_USER]	= IF_EXTER -}; -static const unsigned char ami_servers[AMI_STD_IRQS] = { -	[IRQ_AMIGA_VERTB-IRQ_USER]	= 1, -	[IRQ_AMIGA_PORTS-IRQ_USER]	= 1, -	[IRQ_AMIGA_EXTER-IRQ_USER]	= 1 +static struct irq_controller amiga_irq_controller = { +	.name		= "amiga", +	.lock		= SPIN_LOCK_UNLOCKED, +	.enable		= amiga_enable_irq, +	.disable	= amiga_disable_irq,  }; -static short ami_ablecount[AMI_IRQS]; - -static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp) -{ -	num_spurious += 1; -	return IRQ_NONE; -} -  /*   * void amiga_init_IRQ(void)   * @@ -104,23 +72,12 @@ static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp)  void __init amiga_init_IRQ(void)  { -	int i; +	request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL); +	request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL); +	request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL); +	request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL); -	/* initialize handlers */ -	for (i = 0; i < AMI_STD_IRQS; i++) { -		if (ami_servers[i]) { -			ami_irq_list[i] = NULL; -		} else { -			ami_irq_list[i] = new_irq_node(); -			ami_irq_list[i]->handler = ami_badint; -			ami_irq_list[i]->flags   = 0; -			ami_irq_list[i]->dev_id  = NULL; -			ami_irq_list[i]->devname = NULL; -			ami_irq_list[i]->next    = NULL; -		} -	} -	for (i = 0; i < AMI_IRQS; i++) -		ami_ablecount[i] = 0; +	m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS);  	/* turn off PCMCIA interrupts */  	if (AMIGAHW_PRESENT(PCMCIA)) @@ -135,250 +92,21 @@ void __init amiga_init_IRQ(void)  	cia_init_IRQ(&ciab_base);  } -static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node) -{ -	unsigned long flags; -	irq_node_t *cur; - -	if (!node->dev_id) -		printk("%s: Warning: dev_id of %s is zero\n", -		       __FUNCTION__, node->devname); - -	local_irq_save(flags); - -	cur = *list; - -	if (node->flags & SA_INTERRUPT) { -		if (node->flags & SA_SHIRQ) -			return -EBUSY; -		/* -		 * There should never be more than one -		 */ -		while (cur && cur->flags & SA_INTERRUPT) { -			list = &cur->next; -			cur = cur->next; -		} -	} else { -		while (cur) { -			list = &cur->next; -			cur = cur->next; -		} -	} - -	node->next = cur; -	*list = node; - -	local_irq_restore(flags); -	return 0; -} - -static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) -{ -	unsigned long flags; -	irq_node_t *node; - -	local_irq_save(flags); - -	for (node = *list; node; list = &node->next, node = *list) { -		if (node->dev_id == dev_id) { -			*list = node->next; -			/* Mark it as free. */ -			node->handler = NULL; -			local_irq_restore(flags); -			return; -		} -	} -	local_irq_restore(flags); -	printk ("%s: tried to remove invalid irq\n", __FUNCTION__); -} - -/* - * amiga_request_irq : add an interrupt service routine for a particular - *                     machine specific interrupt source. - *                     If the addition was successful, it returns 0. - */ - -int amiga_request_irq(unsigned int irq, -		      irqreturn_t (*handler)(int, void *, struct pt_regs *), -                      unsigned long flags, const char *devname, void *dev_id) -{ -	irq_node_t *node; -	int error = 0; - -	if (irq >= AMI_IRQS) { -		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, -			irq, devname); -		return -ENXIO; -	} - -	if (irq < IRQ_USER) -		return cpu_request_irq(irq, handler, flags, devname, dev_id); - -	if (irq >= IRQ_AMIGA_CIAB) -		return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, -		                       handler, flags, devname, dev_id); - -	if (irq >= IRQ_AMIGA_CIAA) -		return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, -		                       handler, flags, devname, dev_id); - -	irq -= IRQ_USER; -	/* -	 * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared, -	 * we could add a check here for the SA_SHIRQ flag but all drivers -	 * should be aware of sharing anyway. -	 */ -	if (ami_servers[irq]) { -		if (!(node = new_irq_node())) -			return -ENOMEM; -		node->handler = handler; -		node->flags   = flags; -		node->dev_id  = dev_id; -		node->devname = devname; -		node->next    = NULL; -		error = amiga_insert_irq(&ami_irq_list[irq], node); -	} else { -		ami_irq_list[irq]->handler = handler; -		ami_irq_list[irq]->flags   = flags; -		ami_irq_list[irq]->dev_id  = dev_id; -		ami_irq_list[irq]->devname = devname; -	} - -	/* enable the interrupt */ -	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) -		amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq]; - -	return error; -} - -void amiga_free_irq(unsigned int irq, void *dev_id) -{ -	if (irq >= AMI_IRQS) { -		printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq); -		return; -	} - -	if (irq < IRQ_USER) -		cpu_free_irq(irq, dev_id); - -	if (irq >= IRQ_AMIGA_CIAB) { -		cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); -		return; -	} - -	if (irq >= IRQ_AMIGA_CIAA) { -		cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id); -		return; -	} - -	irq -= IRQ_USER; -	if (ami_servers[irq]) { -		amiga_delete_irq(&ami_irq_list[irq], dev_id); -		/* if server list empty, disable the interrupt */ -		if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS) -			amiga_custom.intena = amiga_intena_vals[irq]; -	} else { -		if (ami_irq_list[irq]->dev_id != dev_id) -			printk("%s: removing probably wrong IRQ %d from %s\n", -			       __FUNCTION__, irq, ami_irq_list[irq]->devname); -		ami_irq_list[irq]->handler = ami_badint; -		ami_irq_list[irq]->flags   = 0; -		ami_irq_list[irq]->dev_id  = NULL; -		ami_irq_list[irq]->devname = NULL; -		amiga_custom.intena = amiga_intena_vals[irq]; -	} -} -  /*   * Enable/disable a particular machine specific interrupt source.   * Note that this may affect other interrupts in case of a shared interrupt.   * This function should only be called for a _very_ short time to change some   * internal data, that may not be changed by the interrupt at the same time. - * ami_(enable|disable)_irq calls may also be nested.   */ -void amiga_enable_irq(unsigned int irq) -{ -	if (irq >= AMI_IRQS) { -		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); -		return; -	} - -	if (--ami_ablecount[irq]) -		return; - -	/* No action for auto-vector interrupts */ -	if (irq < IRQ_USER) { -		printk("%s: Trying to enable auto-vector IRQ %i\n", -		       __FUNCTION__, irq); -		return; -	} - -	if (irq >= IRQ_AMIGA_CIAB) { -		cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); -		cia_able_irq(&ciab_base, CIA_ICR_SETCLR | -		             (1 << (irq - IRQ_AMIGA_CIAB))); -		return; -	} - -	if (irq >= IRQ_AMIGA_CIAA) { -		cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); -		cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | -		             (1 << (irq - IRQ_AMIGA_CIAA))); -		return; -	} - -	/* enable the interrupt */ -	amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq-IRQ_USER]; -} - -void amiga_disable_irq(unsigned int irq) -{ -	if (irq >= AMI_IRQS) { -		printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); -		return; -	} - -	if (ami_ablecount[irq]++) -		return; - -	/* No action for auto-vector interrupts */ -	if (irq < IRQ_USER) { -		printk("%s: Trying to disable auto-vector IRQ %i\n", -		       __FUNCTION__, irq); -		return; -	} - -	if (irq >= IRQ_AMIGA_CIAB) { -		cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); -		return; -	} - -	if (irq >= IRQ_AMIGA_CIAA) { -		cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); -		return; -	} - -	/* disable the interrupt */ -	amiga_custom.intena = amiga_intena_vals[irq-IRQ_USER]; -} - -inline void amiga_do_irq(int irq, struct pt_regs *fp) +static void amiga_enable_irq(unsigned int irq)  { -	kstat_cpu(0).irqs[irq]++; -	ami_irq_list[irq-IRQ_USER]->handler(irq, ami_irq_list[irq-IRQ_USER]->dev_id, fp); +	amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER));  } -void amiga_do_irq_list(int irq, struct pt_regs *fp) +static void amiga_disable_irq(unsigned int irq)  { -	irq_node_t *node; - -	kstat_cpu(0).irqs[irq]++; - -	amiga_custom.intreq = amiga_intena_vals[irq-IRQ_USER]; - -	for (node = ami_irq_list[irq-IRQ_USER]; node; node = node->next) -		node->handler(irq, node->dev_id, fp); +	amiga_custom.intena = 1 << (irq - IRQ_USER);  }  /* @@ -392,19 +120,19 @@ static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp)  	/* if serial transmit buffer empty, interrupt */  	if (ints & IF_TBE) {  		amiga_custom.intreq = IF_TBE; -		amiga_do_irq(IRQ_AMIGA_TBE, fp); +		m68k_handle_int(IRQ_AMIGA_TBE, fp);  	}  	/* if floppy disk transfer complete, interrupt */  	if (ints & IF_DSKBLK) {  		amiga_custom.intreq = IF_DSKBLK; -		amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); +		m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);  	}  	/* if software interrupt set, interrupt */  	if (ints & IF_SOFT) {  		amiga_custom.intreq = IF_SOFT; -		amiga_do_irq(IRQ_AMIGA_SOFT, fp); +		m68k_handle_int(IRQ_AMIGA_SOFT, fp);  	}  	return IRQ_HANDLED;  } @@ -416,18 +144,20 @@ static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp)  	/* if a blitter interrupt */  	if (ints & IF_BLIT) {  		amiga_custom.intreq = IF_BLIT; -		amiga_do_irq(IRQ_AMIGA_BLIT, fp); +		m68k_handle_int(IRQ_AMIGA_BLIT, fp);  	}  	/* if a copper interrupt */  	if (ints & IF_COPER) {  		amiga_custom.intreq = IF_COPER; -		amiga_do_irq(IRQ_AMIGA_COPPER, fp); +		m68k_handle_int(IRQ_AMIGA_COPPER, fp);  	}  	/* if a vertical blank interrupt */ -	if (ints & IF_VERTB) -		amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); +	if (ints & IF_VERTB) { +		amiga_custom.intreq = IF_VERTB; +		m68k_handle_int(IRQ_AMIGA_VERTB, fp); +	}  	return IRQ_HANDLED;  } @@ -438,25 +168,25 @@ static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp)  	/* if audio 0 interrupt */  	if (ints & IF_AUD0) {  		amiga_custom.intreq = IF_AUD0; -		amiga_do_irq(IRQ_AMIGA_AUD0, fp); +		m68k_handle_int(IRQ_AMIGA_AUD0, fp);  	}  	/* if audio 1 interrupt */  	if (ints & IF_AUD1) {  		amiga_custom.intreq = IF_AUD1; -		amiga_do_irq(IRQ_AMIGA_AUD1, fp); +		m68k_handle_int(IRQ_AMIGA_AUD1, fp);  	}  	/* if audio 2 interrupt */  	if (ints & IF_AUD2) {  		amiga_custom.intreq = IF_AUD2; -		amiga_do_irq(IRQ_AMIGA_AUD2, fp); +		m68k_handle_int(IRQ_AMIGA_AUD2, fp);  	}  	/* if audio 3 interrupt */  	if (ints & IF_AUD3) {  		amiga_custom.intreq = IF_AUD3; -		amiga_do_irq(IRQ_AMIGA_AUD3, fp); +		m68k_handle_int(IRQ_AMIGA_AUD3, fp);  	}  	return IRQ_HANDLED;  } @@ -468,53 +198,13 @@ static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp)  	/* if serial receive buffer full interrupt */  	if (ints & IF_RBF) {  		/* acknowledge of IF_RBF must be done by the serial interrupt */ -		amiga_do_irq(IRQ_AMIGA_RBF, fp); +		m68k_handle_int(IRQ_AMIGA_RBF, fp);  	}  	/* if a disk sync interrupt */  	if (ints & IF_DSKSYN) {  		amiga_custom.intreq = IF_DSKSYN; -		amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); +		m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);  	}  	return IRQ_HANDLED;  } - -static irqreturn_t ami_int7(int irq, void *dev_id, struct pt_regs *fp) -{ -	panic ("level 7 interrupt received\n"); -} - -irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { -	[1] = ami_int1, -	[3] = ami_int3, -	[4] = ami_int4, -	[5] = ami_int5, -	[7] = ami_int7 -}; - -int show_amiga_interrupts(struct seq_file *p, void *v) -{ -	int i; -	irq_node_t *node; - -	for (i = IRQ_USER; i < IRQ_AMIGA_CIAA; i++) { -		node = ami_irq_list[i - IRQ_USER]; -		if (!node) -			continue; -		seq_printf(p, "ami  %2d: %10u ", i, -		               kstat_cpu(0).irqs[i]); -		do { -			if (node->flags & SA_INTERRUPT) -				seq_puts(p, "F "); -			else -				seq_puts(p, "  "); -			seq_printf(p, "%s\n", node->devname); -			if ((node = node->next)) -				seq_puts(p, "                    "); -		} while (node); -	} - -	cia_get_irq_list(&ciaa_base, p); -	cia_get_irq_list(&ciab_base, p); -	return 0; -}  | 
