VOID DriverCleanup( struct DriverBase* AHIsubBase ) { struct EMU10kxBase* EMU10kxBase = (struct EMU10kxBase*) AHIsubBase; int i; ObtainSemaphore( &EMU10kxBase->camd.Semaphore ); RemSemaphore( &EMU10kxBase->camd.Semaphore ); ReleaseSemaphore( &EMU10kxBase->camd.Semaphore ); for( i = 0; i < EMU10kxBase->cards_found; ++i ) { emu10k1_irq_disable( &EMU10kxBase->driverdatas[ i ]->card, INTE_MIDIRXENABLE ); emu10k1_irq_disable( &EMU10kxBase->driverdatas[ i ]->card, INTE_MIDITXENABLE ); FreeDriverData( EMU10kxBase->driverdatas[ i ], AHIsubBase ); } FreeVec( EMU10kxBase->driverdatas ); CloseLibrary( OpenPciBase ); CloseLibrary( (struct Library*) DOSBase ); }
/* exist, send it up to IMIDI level. */ int emu10k1_mpuin_reset(struct emu10k1_card *card) { struct emu10k1_mpuin *card_mpuin = card->mpuin; struct midi_queue *midiq; DPF(2, "emu10k1_mpuin_reset()\n"); emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); while (card_mpuin->firstmidiq) { midiq = card_mpuin->firstmidiq; card_mpuin->firstmidiq = midiq->next; if (midiq->sizeLeft == midiq->length) emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0); else emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); kfree(midiq); } card_mpuin->lastmidiq = NULL; card_mpuin->status &= ~FLAGS_MIDM_STARTED; return 0; }
VOID CloseCAMDPort( struct Hook* hook, struct EMU10kxBase* EMU10kxBase, struct CloseMessage* msg ) { struct DriverBase* AHIsubBase = (struct DriverBase*) EMU10kxBase; struct EMU10kxData* dd = EMU10kxBase->driverdatas[ msg->PortNum ]; emu10k1_irq_disable( &dd->card, INTE_MIDIRXENABLE ); emu10k1_irq_disable( &dd->card, INTE_MIDITXENABLE ); emu10k1_mpu_reset( &dd->card ); ObtainSemaphore( &EMU10kxBase->semaphore ); dd->camd_transmitfunc = NULL; dd->camd_receivefunc = NULL; ReleaseSemaphore( &EMU10kxBase->semaphore ); }
ULONG OpenCAMDPort( struct Hook* hook, struct EMU10kxBase* EMU10kxBase, struct OpenMessage* msg ) { struct DriverBase* AHIsubBase = (struct DriverBase*) EMU10kxBase; struct EMU10kxData* dd; BOOL in_use; // KPrintF( "OpenCAMDPort(%ld,%ld)\n", msg->PortNum, msg->V40Mode ); if( msg->PortNum >= EMU10kxBase->cards_found || EMU10kxBase->driverdatas[ msg->PortNum ] == NULL ) { Req( "No valid EMU10kxData for CAMD port %ld.", msg->PortNum ); return FALSE; } dd = EMU10kxBase->driverdatas[ msg->PortNum ]; ObtainSemaphore( &EMU10kxBase->semaphore ); in_use = ( dd->camd_transmitfunc != NULL || dd->camd_receivefunc != NULL ); if( !in_use ) { dd->camd_v40 = msg->V40Mode; dd->camd_transmitfunc = msg->TransmitFunc; dd->camd_receivefunc = msg->ReceiveFunc; } ReleaseSemaphore( &EMU10kxBase->semaphore ); if( in_use ) { return FALSE; } emu10k1_irq_disable( &dd->card, INTE_MIDIRXENABLE ); emu10k1_irq_disable( &dd->card, INTE_MIDITXENABLE ); emu10k1_mpu_reset( &dd->card ); emu10k1_irq_enable( &dd->card, INTE_MIDIRXENABLE ); return TRUE; }
int emu10k1_mpuin_close(struct emu10k1_card *card) { struct emu10k1_mpuin *card_mpuin = card->mpuin; DPF(2, "emu10k1_mpuin_close()\n"); /* Check if there are pending input SysEx buffers */ if (card_mpuin->firstmidiq != NULL) { ERROR(); return -1; } /* Disable RX interrupt */ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); emu10k1_mpu_release(card); card_mpuin->status |= FLAGS_AVAILABLE; /* set */ card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ return 0; }
int emu10k1_mpuin_stop(struct emu10k1_card *card) { struct emu10k1_mpuin *card_mpuin = card->mpuin; struct midi_queue *midiq; unsigned long flags; DPF(2, "emu10k1_mpuin_stop()\n"); emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE); card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */ if (card_mpuin->firstmidiq) { spin_lock_irqsave(&card_mpuin->lock, flags); midiq = card_mpuin->firstmidiq; if (midiq != NULL) { if (midiq->sizeLeft == midiq->length) midiq = NULL; else { card_mpuin->firstmidiq = midiq->next; if (card_mpuin->firstmidiq == NULL) card_mpuin->lastmidiq = NULL; } } spin_unlock_irqrestore(&card_mpuin->lock, flags); if (midiq) { emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0); kfree(midiq); } } return 0; }
irqreturn_t emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct emu10k1_card *card = (struct emu10k1_card *) dev_id; u32 irqstatus, irqstatus_tmp; int handled = 0; DPD(4, "emu10k1_interrupt called, irq = %u\n", irq); /* ** NOTE : ** We do a 'while loop' here cos on certain machines, with both ** playback and recording going on at the same time, IRQs will ** stop coming in after a while. Checking IPND indeed shows that ** there are interrupts pending but the PIC says no IRQs pending. ** I suspect that some boards need edge-triggered IRQs but are not ** getting that condition if we don't completely clear the IPND ** (make sure no more interrupts are pending). ** - Eric */ while ((irqstatus = inl(card->iobase + IPR))) { DPD(4, "irq status %#x\n", irqstatus); irqstatus_tmp = irqstatus; if (irqstatus & IRQTYPE_TIMER) { emu10k1_timer_irqhandler(card); irqstatus &= ~IRQTYPE_TIMER; } if (irqstatus & IRQTYPE_DSP) { emu10k1_dsp_irqhandler(card); irqstatus &= ~IRQTYPE_DSP; } if (irqstatus & IRQTYPE_MPUIN) { emu10k1_mpuin_irqhandler(card); irqstatus &= ~IRQTYPE_MPUIN; } if (irqstatus & IRQTYPE_MPUOUT) { emu10k1_mpuout_irqhandler(card); irqstatus &= ~IRQTYPE_MPUOUT; } if (irqstatus & IPR_MUTE) { emu10k1_mute_irqhandler(card); irqstatus &=~IPR_MUTE; } if (irqstatus & IPR_VOLINCR) { emu10k1_volincr_irqhandler(card); irqstatus &=~IPR_VOLINCR; } if (irqstatus & IPR_VOLDECR) { emu10k1_voldecr_irqhandler(card); irqstatus &=~IPR_VOLDECR; } if (irqstatus){ printk(KERN_ERR "emu10k1: Warning, unhandled interrupt: %#08x\n", irqstatus); //make sure any interrupts we don't handle are disabled: emu10k1_irq_disable(card, ~(INTE_MIDIRXENABLE | INTE_MIDITXENABLE | INTE_INTERVALTIMERENB | INTE_VOLDECRENABLE | INTE_VOLINCRENABLE | INTE_MUTEENABLE | INTE_FXDSPENABLE)); } /* acknowledge interrupt */ outl(irqstatus_tmp, card->iobase + IPR); handled = 1; } return IRQ_RETVAL(handled); }