📄 xp_osi_inter.c
字号:
/*----------------------------------------------------------------------------+| This source code has been made available to you by IBM on an AS-IS| basis. Anyone receiving this source is licensed under IBM| copyrights to use it in any way he or she deems fit, including| copying it, modifying it, compiling it, and redistributing it either| with or without modifications. No license under IBM patents or| patent applications is to be implied by the copyright license.|| Any user of this software should understand that IBM cannot provide| technical support for this software and will not be responsible for| any consequences resulting from the use of this software.|| Any person who transfers this source code or any derivative work| must include the IBM copyright notice, this paragraph, and the| preceding two paragraphs in the transferred software.|| COPYRIGHT I B M CORPORATION 1998| LICENSED MATERIAL - PROGRAM PROPERTY OF I B M+----------------------------------------------------------------------------*//*----------------------------------------------------------------------------+|| Author : Ian Govett| Component : xp| File : xp0_inter.c| Purpose : Interrupt Management| Changes :|| Date By Comments| --------- --- ---------------------------------------------------------| 15-Jan-98 IG Created| 22-Jun-99 PAG Only clear unmasked status interrupt bits.| 30-Sep-01 LGH Ported to Linux, combined codes of 3 devices|+----------------------------------------------------------------------------*//*----------------------------------------------------------------------------+| Interrupt processing & management+-----------------------------------------------------------------------------+|| The following functions provide interrupt services for the demux| driver. A large number of interrupts are available to the demux| driver. The hardware provides a set of interrupt registers which are| organized in a hierarchical manner, with the primary interrupt register| at the top of the hierarchy. Status registers for audio, video, and| channel registers provide the secondary interrupt layer. See the demux| specification for more detailed information.|| The demux driver processes all interrupts signaled by the transport| hardware. The primary interrupt register is read and cleared before| executing any callback function which may have been registered. This| is done to minimize the loss of any future interrupts delivered by the| hardware. Information in the primary interrupt register indicates if| there are any status, audio, video, or channel interrupts pending.| Other primary interrupts such as clock recovery are processed first,| followed by the secondary interrupts.|| The interface provided by the demux driver features the registration of| callback functions for each type of interrupt in any of the interrupt| registers. Multiple functions may register their callback functions| for the same or a different set of interrupts. Callback functions are| called in the order of their registration.|| There are three callback functions which process the primary, status,| and channel interrupts. The registration of callback functions require| a bit mask (channel interrupts also require a channel_id). This bit| mask indicates the interrupt types being registered for notification.| Only one callback is made for each registration no matter how many bits| may be set.|| To minimize the number of interrupts received from the hardware, the| union of all the interrupt masks registered with callback functions is| calculated. This value is used to set the hardware masks.|+----------------------------------------------------------------------------*//* The necessary header files */#if 0#include <linux/config.h>#include <linux/version.h>#ifdef MODVERSIONS#include <linux/modversions.h>#endif#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#endif#include "hw/hardware.h"#include "xp_osi_global.h"#include "xp_atom_reg.h"/*----------------------------------------------------------------------------+| Local Defines+----------------------------------------------------------------------------*/#define QSTAT_INTERRUPT_MASK 0x0000FFFF /* Valid Queue Status bits */#define XP0_FESTAT_INTERRUPT_MASK 0x00007F3F /* Valid Front-End Status bits */#define XP0_PRIMARY_INTERRUPT_MASK 0xFFFE0003 /* Valid Primary Interrupt bits */#define XP0_PRIMARY_SET_MASK 0xF0000000 /* Primary Ints auto enabled */#define XP12_FESTAT_INTERRUPT_MASK 0x0000713F /* Valid Front-End Status bits */#define XP12_PRIMARY_INTERRUPT_MASK 0xC6CE0000 /* Valid Primary Interrupt bits */#define XP12_PRIMARY_SET_MASK 0xC0000000 /* Primary Ints auto enabled */#define QUEUE_SIZE 20typedef struct xp_os_msg_type{ GLOBAL_RESOURCES *pGlobal; SHORT wChannelId; /* channel id for the interrupt */ ULONG ulInterrupt; /* interrupt vector for channel */ XP_INTERRUPT_CHANNEL_FN notify_fn; /* callback function */} XP_OS_MSG_TYPE, *XP_OS_MSG_PTR;/*----------------------------------------------------------------------------+| Static Variables+----------------------------------------------------------------------------*/static GLOBAL_RESOURCES *pXp0Global;static GLOBAL_RESOURCES *pXp1Global;static GLOBAL_RESOURCES *pXp2Global;/*----------------------------------------------------------------------------+| Local Prototype Definitions+----------------------------------------------------------------------------*///Internalstatic void process_channel_interrupt(GLOBAL_RESOURCES *pGlobal, SHORT wChannelId);static void status_interrupt(GLOBAL_RESOURCES *pGlobal);static void audio_interrupt(GLOBAL_RESOURCES *pGlobal);static void video_interrupt(GLOBAL_RESOURCES *pGlobal);static void channel_interrupt(GLOBAL_RESOURCES *pGlobal);static SHORT add_mask(GLOBAL_RESOURCES *pGlobal,ULONG ulMask,PFS notify_fn, INTERRUPT_INFO_PTR pInfo);static SHORT del_mask(GLOBAL_RESOURCES * pGlobal,ULONG ulMask,PFS notify_fn, INTERRUPT_INFO_PTR pInfo);static void reset_mask(GLOBAL_RESOURCES *pGlobal,INTERRUPT_INFO_PTR pInfo);/*----------------------------------------------------------------------------+| XXXX XX XX XXXXXX XXXXXXX XXXXXX XX XX XX XXXX| XX XXX XX X XX X XX X XX XX XXX XX XXXX XX| XX XXXX XX XX XX X XX XX XXXX XX XX XX XX| XX XX XXXX XX XXXX XXXXX XX XXXX XX XX XX| XX XX XXX XX XX X XX XX XX XXX XXXXXX XX| XX XX XX XX XX X XX XX XX XX XX XX XX XX| XXXX XX XX XXXX XXXXXXX XXX XX XX XX XX XX XXXXXXX+----------------------------------------------------------------------------*//*----------------------------------------------------------------------------+| process_channel_interrupt+-----------------------------------------------------------------------------+|| FUNCTION : process_channel_interrupt|| DESCRIPTION : process interrupts for audio, video, and system channels|+----------------------------------------------------------------------------*/static void process_channel_interrupt(GLOBAL_RESOURCES *pGlobal, SHORT wChannelId){ short i, j; unsigned long addr; unsigned long interrupt; XP_OS_MSG_TYPE msg; switch(wChannelId) { case XP_INTERRUPT_VIDEO: addr = XP_DCR_ADDR_VSTATUS; break; case XP_INTERRUPT_AUDIO: addr = XP_DCR_ADDR_ASTATUS; break; default: addr = XP_DCR_ADDR_BASE_QSTAT + wChannelId; break; } /*------------------------------------------------------------------------+ | Read & clear the primary interrupts +------------------------------------------------------------------------*/// flag = os_enter_critical_section(); interrupt = xp_atom_dcr_read(pGlobal->uDeviceIndex,addr); xp_atom_dcr_write(pGlobal->uDeviceIndex, addr, interrupt);// os_leave_critical_section(flag); for(i=0, j=0; i<pGlobal->InterInfo.XpInterChanInt[wChannelId].wNotifyAlloc && j<pGlobal->InterInfo.XpInterChanInt[wChannelId].wNotifyCount; i++) { if(interrupt & pGlobal->InterInfo.XpInterChanInt[wChannelId].pNotify[i].ulMask) { j++; /*----------------------------------------------------------------+ | Process the current interrupt by adding the work to the | Task queue. Note: direct call is | (*notify_fn)(channel_id, interrupt) +----------------------------------------------------------------*/ if (pGlobal->InterInfo.XpInterChanInt[wChannelId].pNotify[i].notify_fn) { msg.pGlobal = pGlobal; msg.wChannelId = wChannelId; msg.ulInterrupt = interrupt; msg.notify_fn = (XP_INTERRUPT_CHANNEL_FN) pGlobal->InterInfo.XpInterChanInt[wChannelId].pNotify[i].notify_fn; if(os_call_irq_task(XP_IRQ,&msg)) { ; } } } }}/*----------------------------------------------------------------------------+| status_interrupt+-----------------------------------------------------------------------------+|| FUNCTION : status_interrupt|| DESCRIPTION : process all status interrupts|+----------------------------------------------------------------------------*/static void status_interrupt(GLOBAL_RESOURCES *pGlobal){ short i, j; unsigned long interrupt; /*------------------------------------------------------------------------+ | Read & clear the primary interrupts +------------------------------------------------------------------------*/ //flag = os_enter_critical_section(); interrupt = xp_atom_dcr_read(pGlobal->uDeviceIndex,XP_DCR_ADDR_FESTAT) & xp_atom_dcr_read(pGlobal->uDeviceIndex,XP_DCR_ADDR_FEIMASK); xp_atom_dcr_write(pGlobal->uDeviceIndex, XP_DCR_ADDR_FESTAT, interrupt); //os_leave_critical_section(flag); for(i=0, j=0; i<pGlobal->InterInfo.XpInterStatInt.wNotifyAlloc && j<pGlobal->InterInfo.XpInterStatInt.wNotifyCount; i++) { if(interrupt & pGlobal->InterInfo.XpInterStatInt.pNotify[i].ulMask) { j++; if(pGlobal->InterInfo.XpInterStatInt.pNotify[i].notify_fn) { (*pGlobal->InterInfo.XpInterStatInt.pNotify[i].notify_fn)(pGlobal, interrupt); } } }}/*----------------------------------------------------------------------------+| audio_interrupt+-----------------------------------------------------------------------------+|| FUNCTION : audio_interrupt|| DESCRIPTION : process all status interrupts|+----------------------------------------------------------------------------*/static void audio_interrupt(GLOBAL_RESOURCES *pGlobal){ process_channel_interrupt(pGlobal,XP_INTERRUPT_AUDIO);}/*----------------------------------------------------------------------------+| video_interrupt+-----------------------------------------------------------------------------+|| FUNCTION : video_interrupt|| DESCRIPTION : process all status interrupts|+----------------------------------------------------------------------------*/static void video_interrupt(GLOBAL_RESOURCES *pGlobal){ process_channel_interrupt(pGlobal,XP_INTERRUPT_VIDEO);}/*----------------------------------------------------------------------------+| channel_interrupt+-----------------------------------------------------------------------------+|| FUNCTION : channel_interrupt|| DESCRIPTION : process all the channel interrupts|+----------------------------------------------------------------------------*/static void channel_interrupt(GLOBAL_RESOURCES *pGlobal){ short i; unsigned long k; unsigned long ireq; /*------------------------------------------------------------------------+ | Get the interrupt vector which shows which channels have an | interrupt pending +------------------------------------------------------------------------*/// flag = os_enter_critical_section(); ireq = xp_atom_dcr_read(pGlobal->uDeviceIndex,XP_DCR_ADDR_QINT) & xp_atom_dcr_read(pGlobal->uDeviceIndex,XP_DCR_ADDR_QINTMSK);// os_leave_critical_section(flag); /*------------------------------------------------------------------------+ | for each interrupt on a channel, process the interrupts +------------------------------------------------------------------------*/ for(i=0, k=0x80000000; i<XP_CHANNEL_COUNT; i++, k>>=1) { if(k & ireq) { process_channel_interrupt(pGlobal,i); } }}/*----------------------------------------------------------------------------+| add_mask+----------------------------------------------------------------------------*/static SHORT add_mask(GLOBAL_RESOURCES *pGlobal,ULONG ulMask,PFS notify_fn, INTERRUPT_INFO_PTR pInfo){ short i; short index; /* array index available */ INTERRUPT_NOTIFY_PTR pNotify; /*------------------------------------------------------------------------+ | Make sure this mask isn't already registered +------------------------------------------------------------------------*/ for(i=0, index=-1; i<pInfo->wNotifyAlloc; i++) { if((ulMask == pInfo->pNotify[i].ulMask) && (notify_fn == pInfo->pNotify[i].notify_fn)) { return(XP_ERROR_INTER_NOTIFY_DUP); } if(pInfo->pNotify[i].ulMask == 0) { index = i; } } /*------------------------------------------------------------------------+ | If there is no space, allocate more space +------------------------------------------------------------------------*/ if (index < 0) { if (pInfo->wNotifyAlloc == 0) { //added by lingh index = pInfo->wNotifyAlloc; pInfo->wNotifyAlloc += 10; pNotify = (INTERRUPT_NOTIFY_PTR) MALLOC(pInfo->wNotifyAlloc * sizeof(XP_INTERRUPT_NOTIFY_TYPE)); if(pNotify == NULL) { return(XP_ERROR_INTERNAL); } pInfo->pNotify = pNotify; /*------------------------------------------------------------------------+ | Initialize the new space +------------------------------------------------------------------------*/ for(i=index; i<pInfo->wNotifyAlloc; i++) { pInfo->pNotify[i].ulMask = 0; pInfo->pNotify[i].notify_fn = NULL; } } else { return (XP_ERROR_INTERNAL); /* which should not happen */ } } pInfo->pNotify[index].ulMask = ulMask; pInfo->pNotify[index].notify_fn = notify_fn; pInfo->wNotifyCount++; return(0);}/*----------------------------------------------------------------------------+| del_mask+----------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -