162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * 5/2/94 Roman Hodek: 562306a36Sopenharmony_ci * Added support for TT interrupts; setup for TT SCU (may someone has 662306a36Sopenharmony_ci * twiddled there and we won't get the right interrupts :-() 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Major change: The device-independent code in m68k/ints.c didn't know 962306a36Sopenharmony_ci * about non-autovec ints yet. It hardcoded the number of possible ints to 1062306a36Sopenharmony_ci * 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the 1162306a36Sopenharmony_ci * number of possible ints a constant defined in interrupt.h, which is 1262306a36Sopenharmony_ci * 47 for the Atari. So we can call request_irq() for all Atari interrupts 1362306a36Sopenharmony_ci * just the normal way. Additionally, all vectors >= 48 are initialized to 1462306a36Sopenharmony_ci * call trap() instead of inthandler(). This must be changed here, too. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * 1995-07-16 Lars Brinkhoff <f93labr@dd.chalmers.se>: 1762306a36Sopenharmony_ci * Corrected a bug in atari_add_isr() which rejected all SCC 1862306a36Sopenharmony_ci * interrupt sources if there were no TT MFP! 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * 12/13/95: New interface functions atari_level_triggered_int() and 2162306a36Sopenharmony_ci * atari_register_vme_int() as support for level triggered VME interrupts. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * 02/12/96: (Roman) 2462306a36Sopenharmony_ci * Total rewrite of Atari interrupt handling, for new scheme see comments 2562306a36Sopenharmony_ci * below. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * 1996-09-03 lars brinkhoff <f93labr@dd.chalmers.se>: 2862306a36Sopenharmony_ci * Added new function atari_unregister_vme_int(), and 2962306a36Sopenharmony_ci * modified atari_register_vme_int() as well as IS_VALID_INTNO() 3062306a36Sopenharmony_ci * to work with it. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 3362306a36Sopenharmony_ci * License. See the file COPYING in the main directory of this archive 3462306a36Sopenharmony_ci * for more details. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <linux/types.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/kernel_stat.h> 4162306a36Sopenharmony_ci#include <linux/init.h> 4262306a36Sopenharmony_ci#include <linux/seq_file.h> 4362306a36Sopenharmony_ci#include <linux/module.h> 4462306a36Sopenharmony_ci#include <linux/irq.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <asm/traps.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include <asm/atarihw.h> 4962306a36Sopenharmony_ci#include <asm/atariints.h> 5062306a36Sopenharmony_ci#include <asm/atari_stdma.h> 5162306a36Sopenharmony_ci#include <asm/irq.h> 5262306a36Sopenharmony_ci#include <asm/entry.h> 5362306a36Sopenharmony_ci#include <asm/io.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Atari interrupt handling scheme: 5862306a36Sopenharmony_ci * -------------------------------- 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * All interrupt source have an internal number (defined in 6162306a36Sopenharmony_ci * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, 6262306a36Sopenharmony_ci * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can 6362306a36Sopenharmony_ci * be allocated by atari_register_vme_int(). 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * Bitmap for free interrupt vector numbers 6862306a36Sopenharmony_ci * (new vectors starting from 0x70 can be allocated by 6962306a36Sopenharmony_ci * atari_register_vme_int()) 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_cistatic int free_vme_vec_bitmap; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* GK: 7462306a36Sopenharmony_ci * HBL IRQ handler for Falcon. Nobody needs it :-) 7562306a36Sopenharmony_ci * ++andreas: raise ipl to disable further HBLANK interrupts. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ciasmlinkage void falcon_hblhandler(void); 7862306a36Sopenharmony_ciasm(".text\n" 7962306a36Sopenharmony_ci__ALIGN_STR "\n\t" 8062306a36Sopenharmony_ci"falcon_hblhandler:\n\t" 8162306a36Sopenharmony_ci "orw #0x200,%sp@\n\t" /* set saved ipl to 2 */ 8262306a36Sopenharmony_ci "rte"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ciextern void atari_microwire_cmd(int cmd); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic unsigned int atari_irq_startup(struct irq_data *data) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci unsigned int irq = data->irq; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci m68k_irq_startup(data); 9162306a36Sopenharmony_ci atari_turnon_irq(irq); 9262306a36Sopenharmony_ci atari_enable_irq(irq); 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void atari_irq_shutdown(struct irq_data *data) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci unsigned int irq = data->irq; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci atari_disable_irq(irq); 10162306a36Sopenharmony_ci atari_turnoff_irq(irq); 10262306a36Sopenharmony_ci m68k_irq_shutdown(data); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (irq == IRQ_AUTO_4) 10562306a36Sopenharmony_ci vectors[VEC_INT4] = falcon_hblhandler; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void atari_irq_enable(struct irq_data *data) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci atari_enable_irq(data->irq); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic void atari_irq_disable(struct irq_data *data) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci atari_disable_irq(data->irq); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic struct irq_chip atari_irq_chip = { 11962306a36Sopenharmony_ci .name = "atari", 12062306a36Sopenharmony_ci .irq_startup = atari_irq_startup, 12162306a36Sopenharmony_ci .irq_shutdown = atari_irq_shutdown, 12262306a36Sopenharmony_ci .irq_enable = atari_irq_enable, 12362306a36Sopenharmony_ci .irq_disable = atari_irq_disable, 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * ST-MFP timer D chained interrupts - each driver gets its own timer 12862306a36Sopenharmony_ci * interrupt instance. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct mfptimerbase { 13262306a36Sopenharmony_ci volatile struct MFP *mfp; 13362306a36Sopenharmony_ci unsigned char mfp_mask, mfp_data; 13462306a36Sopenharmony_ci unsigned short int_mask; 13562306a36Sopenharmony_ci int handler_irq, mfptimer_irq, server_irq; 13662306a36Sopenharmony_ci char *name; 13762306a36Sopenharmony_ci} stmfp_base = { 13862306a36Sopenharmony_ci .mfp = &st_mfp, 13962306a36Sopenharmony_ci .int_mask = 0x0, 14062306a36Sopenharmony_ci .handler_irq = IRQ_MFP_TIMD, 14162306a36Sopenharmony_ci .mfptimer_irq = IRQ_MFP_TIMER1, 14262306a36Sopenharmony_ci .name = "MFP Timer D" 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic irqreturn_t mfp_timer_d_handler(int irq, void *dev_id) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct mfptimerbase *base = dev_id; 14862306a36Sopenharmony_ci int mach_irq; 14962306a36Sopenharmony_ci unsigned char ints; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci mach_irq = base->mfptimer_irq; 15262306a36Sopenharmony_ci ints = base->int_mask; 15362306a36Sopenharmony_ci for (; ints; mach_irq++, ints >>= 1) { 15462306a36Sopenharmony_ci if (ints & 1) 15562306a36Sopenharmony_ci generic_handle_irq(mach_irq); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci return IRQ_HANDLED; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void atari_mfptimer_enable(struct irq_data *data) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int mfp_num = data->irq - IRQ_MFP_TIMER1; 16462306a36Sopenharmony_ci stmfp_base.int_mask |= 1 << mfp_num; 16562306a36Sopenharmony_ci atari_enable_irq(IRQ_MFP_TIMD); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic void atari_mfptimer_disable(struct irq_data *data) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci int mfp_num = data->irq - IRQ_MFP_TIMER1; 17162306a36Sopenharmony_ci stmfp_base.int_mask &= ~(1 << mfp_num); 17262306a36Sopenharmony_ci if (!stmfp_base.int_mask) 17362306a36Sopenharmony_ci atari_disable_irq(IRQ_MFP_TIMD); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic struct irq_chip atari_mfptimer_chip = { 17762306a36Sopenharmony_ci .name = "timer_d", 17862306a36Sopenharmony_ci .irq_enable = atari_mfptimer_enable, 17962306a36Sopenharmony_ci .irq_disable = atari_mfptimer_disable, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * EtherNAT CPLD interrupt handling 18562306a36Sopenharmony_ci * CPLD interrupt register is at phys. 0x80000023 18662306a36Sopenharmony_ci * Need this mapped in at interrupt startup time 18762306a36Sopenharmony_ci * Possibly need this mapped on demand anyway - 18862306a36Sopenharmony_ci * EtherNAT USB driver needs to disable IRQ before 18962306a36Sopenharmony_ci * startup! 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic unsigned char *enat_cpld; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic unsigned int atari_ethernat_startup(struct irq_data *data) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int enat_num = 140 - data->irq + 1; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci m68k_irq_startup(data); 19962306a36Sopenharmony_ci /* 20062306a36Sopenharmony_ci * map CPLD interrupt register 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci if (!enat_cpld) 20362306a36Sopenharmony_ci enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * do _not_ enable the USB chip interrupt here - causes interrupt storm 20662306a36Sopenharmony_ci * and triggers dead interrupt watchdog 20762306a36Sopenharmony_ci * Need to reset the USB chip to a sane state in early startup before 20862306a36Sopenharmony_ci * removing this hack 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci if (enat_num == 1) 21162306a36Sopenharmony_ci *enat_cpld |= 1 << enat_num; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void atari_ethernat_enable(struct irq_data *data) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci int enat_num = 140 - data->irq + 1; 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * map CPLD interrupt register 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci if (!enat_cpld) 22362306a36Sopenharmony_ci enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); 22462306a36Sopenharmony_ci *enat_cpld |= 1 << enat_num; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void atari_ethernat_disable(struct irq_data *data) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci int enat_num = 140 - data->irq + 1; 23062306a36Sopenharmony_ci /* 23162306a36Sopenharmony_ci * map CPLD interrupt register 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci if (!enat_cpld) 23462306a36Sopenharmony_ci enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2); 23562306a36Sopenharmony_ci *enat_cpld &= ~(1 << enat_num); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void atari_ethernat_shutdown(struct irq_data *data) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int enat_num = 140 - data->irq + 1; 24162306a36Sopenharmony_ci if (enat_cpld) { 24262306a36Sopenharmony_ci *enat_cpld &= ~(1 << enat_num); 24362306a36Sopenharmony_ci iounmap(enat_cpld); 24462306a36Sopenharmony_ci enat_cpld = NULL; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic struct irq_chip atari_ethernat_chip = { 24962306a36Sopenharmony_ci .name = "ethernat", 25062306a36Sopenharmony_ci .irq_startup = atari_ethernat_startup, 25162306a36Sopenharmony_ci .irq_shutdown = atari_ethernat_shutdown, 25262306a36Sopenharmony_ci .irq_enable = atari_ethernat_enable, 25362306a36Sopenharmony_ci .irq_disable = atari_ethernat_disable, 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * void atari_init_IRQ (void) 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Parameters: None 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Returns: Nothing 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * This function should be called during kernel startup to initialize 26462306a36Sopenharmony_ci * the atari IRQ handling routines. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_civoid __init atari_init_IRQ(void) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER); 27062306a36Sopenharmony_ci m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1, 27162306a36Sopenharmony_ci NUM_ATARI_SOURCES - 1); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* Initialize the MFP(s) */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci#ifdef ATARI_USE_SOFTWARE_EOI 27662306a36Sopenharmony_ci st_mfp.vec_adr = 0x48; /* Software EOI-Mode */ 27762306a36Sopenharmony_ci#else 27862306a36Sopenharmony_ci st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */ 27962306a36Sopenharmony_ci#endif 28062306a36Sopenharmony_ci st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ 28162306a36Sopenharmony_ci st_mfp.int_en_b = 0x00; 28262306a36Sopenharmony_ci st_mfp.int_mk_a = 0xff; /* no Masking */ 28362306a36Sopenharmony_ci st_mfp.int_mk_b = 0xff; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (ATARIHW_PRESENT(TT_MFP)) { 28662306a36Sopenharmony_ci#ifdef ATARI_USE_SOFTWARE_EOI 28762306a36Sopenharmony_ci tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */ 28862306a36Sopenharmony_ci#else 28962306a36Sopenharmony_ci tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */ 29062306a36Sopenharmony_ci#endif 29162306a36Sopenharmony_ci tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */ 29262306a36Sopenharmony_ci tt_mfp.int_en_b = 0x00; 29362306a36Sopenharmony_ci tt_mfp.int_mk_a = 0xff; /* no Masking */ 29462306a36Sopenharmony_ci tt_mfp.int_mk_b = 0xff; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) { 29862306a36Sopenharmony_ci atari_scc.cha_a_ctrl = 9; 29962306a36Sopenharmony_ci MFPDELAY(); 30062306a36Sopenharmony_ci atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */ 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (ATARIHW_PRESENT(SCU)) { 30462306a36Sopenharmony_ci /* init the SCU if present */ 30562306a36Sopenharmony_ci tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and 30662306a36Sopenharmony_ci * disable HSYNC interrupts (who 30762306a36Sopenharmony_ci * needs them?) MFP and SCC are 30862306a36Sopenharmony_ci * enabled in VME mask 30962306a36Sopenharmony_ci */ 31062306a36Sopenharmony_ci tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */ 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci /* If no SCU and no Hades, the HSYNC interrupt needs to be 31362306a36Sopenharmony_ci * disabled this way. (Else _inthandler in kernel/sys_call.S 31462306a36Sopenharmony_ci * gets overruns) 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci vectors[VEC_INT2] = falcon_hblhandler; 31862306a36Sopenharmony_ci vectors[VEC_INT4] = falcon_hblhandler; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) { 32262306a36Sopenharmony_ci /* Initialize the LM1992 Sound Controller to enable 32362306a36Sopenharmony_ci the PSG sound. This is misplaced here, it should 32462306a36Sopenharmony_ci be in an atasound_init(), that doesn't exist yet. */ 32562306a36Sopenharmony_ci atari_microwire_cmd(MW_LM1992_PSG_HIGH); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci stdma_init(); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Initialize the PSG: all sounds off, both ports output */ 33162306a36Sopenharmony_ci sound_ym.rd_data_reg_sel = 7; 33262306a36Sopenharmony_ci sound_ym.wd_data = 0xff; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci m68k_setup_irq_controller(&atari_mfptimer_chip, handle_simple_irq, 33562306a36Sopenharmony_ci IRQ_MFP_TIMER1, 8); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci irq_set_status_flags(IRQ_MFP_TIMER1, IRQ_IS_POLLED); 33862306a36Sopenharmony_ci irq_set_status_flags(IRQ_MFP_TIMER2, IRQ_IS_POLLED); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* prepare timer D data for use as poll interrupt */ 34162306a36Sopenharmony_ci /* set Timer D data Register - needs to be > 0 */ 34262306a36Sopenharmony_ci st_mfp.tim_dt_d = 254; /* < 100 Hz */ 34362306a36Sopenharmony_ci /* start timer D, div = 1:100 */ 34462306a36Sopenharmony_ci st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 0xf0) | 0x6; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* request timer D dispatch handler */ 34762306a36Sopenharmony_ci if (request_irq(IRQ_MFP_TIMD, mfp_timer_d_handler, IRQF_SHARED, 34862306a36Sopenharmony_ci stmfp_base.name, &stmfp_base)) 34962306a36Sopenharmony_ci pr_err("Couldn't register %s interrupt\n", stmfp_base.name); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* 35262306a36Sopenharmony_ci * EtherNAT ethernet / USB interrupt handlers 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq, 35662306a36Sopenharmony_ci 139, 2); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * atari_register_vme_int() returns the number of a free interrupt vector for 36262306a36Sopenharmony_ci * hardware with a programmable int vector (probably a VME board). 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciunsigned int atari_register_vme_int(void) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci int i; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci for (i = 0; i < 32; i++) 37062306a36Sopenharmony_ci if ((free_vme_vec_bitmap & (1 << i)) == 0) 37162306a36Sopenharmony_ci break; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (i == 16) 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci free_vme_vec_bitmap |= 1 << i; 37762306a36Sopenharmony_ci return VME_SOURCE_BASE + i; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ciEXPORT_SYMBOL(atari_register_vme_int); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_civoid atari_unregister_vme_int(unsigned int irq) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) { 38562306a36Sopenharmony_ci irq -= VME_SOURCE_BASE; 38662306a36Sopenharmony_ci free_vme_vec_bitmap &= ~(1 << irq); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ciEXPORT_SYMBOL(atari_unregister_vme_int); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci 392