Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

738
drivers/char/mwave/3780i.c Normal file
View file

@ -0,0 +1,738 @@
/*
*
* 3780i.c -- helper routines for the 3780i DSP
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/bitops.h>
#include <linux/sched.h> /* cond_resched() */
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include "smapi.h"
#include "mwavedd.h"
#include "3780i.h"
static DEFINE_SPINLOCK(dsp_lock);
static void PaceMsaAccess(unsigned short usDspBaseIO)
{
cond_resched();
udelay(100);
cond_resched();
}
unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr)
{
unsigned long flags;
unsigned short val;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_ReadMsaCfg entry usDspBaseIO %x ulMsaAddr %lx\n",
usDspBaseIO, ulMsaAddr);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
val = InWordDsp(DSP_MsaDataDSISHigh);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_2(TRACE_3780I, "3780i::dsp3780I_ReadMsaCfg exit val %x\n", val);
return val;
}
void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr, unsigned short usValue)
{
unsigned long flags;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_WriteMsaCfg entry usDspBaseIO %x ulMsaAddr %lx usValue %x\n",
usDspBaseIO, ulMsaAddr, usValue);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
OutWordDsp(DSP_MsaDataDSISHigh, usValue);
spin_unlock_irqrestore(&dsp_lock, flags);
}
static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
unsigned char ucValue)
{
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg entry usDspBaseIO %x uIndex %x ucValue %x\n",
usDspBaseIO, uIndex, ucValue);
MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg rSlaveControl %x\n",
MKBYTE(rSlaveControl));
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = TRUE;
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n",
MKBYTE(rSlaveControl));
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
OutByteDsp(DSP_ConfigData, ucValue);
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl_Save));
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_WriteGenCfg exit\n");
}
#if 0
unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
unsigned uIndex)
{
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
unsigned char ucValue;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780i_ReadGenCfg entry usDspBaseIO %x uIndex %x\n",
usDspBaseIO, uIndex);
MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = TRUE;
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
ucValue = InByteDsp(DSP_ConfigData);
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl_Save));
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_ReadGenCfg exit ucValue %x\n", ucValue);
return ucValue;
}
#endif /* 0 */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
unsigned short *pIrqMap,
unsigned short *pDmaMap)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
int i;
DSP_UART_CFG_1 rUartCfg1;
DSP_UART_CFG_2 rUartCfg2;
DSP_HBRIDGE_CFG_1 rHBridgeCfg1;
DSP_HBRIDGE_CFG_2 rHBridgeCfg2;
DSP_BUSMASTER_CFG_1 rBusmasterCfg1;
DSP_BUSMASTER_CFG_2 rBusmasterCfg2;
DSP_ISA_PROT_CFG rIsaProtCfg;
DSP_POWER_MGMT_CFG rPowerMgmtCfg;
DSP_HBUS_TIMER_CFG rHBusTimerCfg;
DSP_LBUS_TIMEOUT_DISABLE rLBusTimeoutDisable;
DSP_CHIP_RESET rChipReset;
DSP_CLOCK_CONTROL_1 rClockControl1;
DSP_CLOCK_CONTROL_2 rClockControl2;
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_HBRIDGE_CONTROL rHBridgeControl;
unsigned short ChipID = 0;
unsigned short tval;
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_EnableDSP entry pSettings->bDSPEnabled %x\n",
pSettings->bDSPEnabled);
if (!pSettings->bDSPEnabled) {
PRINTK_ERROR( KERN_ERR "3780i::dsp3780I_EnableDSP: Error: DSP not enabled. Aborting.\n" );
return -EIO;
}
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP entry pSettings->bModemEnabled %x\n",
pSettings->bModemEnabled);
if (pSettings->bModemEnabled) {
rUartCfg1.Reserved = rUartCfg2.Reserved = 0;
rUartCfg1.IrqActiveLow = pSettings->bUartIrqActiveLow;
rUartCfg1.IrqPulse = pSettings->bUartIrqPulse;
rUartCfg1.Irq =
(unsigned char) pIrqMap[pSettings->usUartIrq];
switch (pSettings->usUartBaseIO) {
case 0x03F8:
rUartCfg1.BaseIO = 0;
break;
case 0x02F8:
rUartCfg1.BaseIO = 1;
break;
case 0x03E8:
rUartCfg1.BaseIO = 2;
break;
case 0x02E8:
rUartCfg1.BaseIO = 3;
break;
}
rUartCfg2.Enable = TRUE;
}
rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0;
rHBridgeCfg1.IrqActiveLow = pSettings->bDspIrqActiveLow;
rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse;
rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq];
rHBridgeCfg1.AccessMode = 1;
rHBridgeCfg2.Enable = TRUE;
rBusmasterCfg2.Reserved = 0;
rBusmasterCfg1.Dma = (unsigned char) pDmaMap[pSettings->usDspDma];
rBusmasterCfg1.NumTransfers =
(unsigned char) pSettings->usNumTransfers;
rBusmasterCfg1.ReRequest = (unsigned char) pSettings->usReRequest;
rBusmasterCfg1.MEMCS16 = pSettings->bEnableMEMCS16;
rBusmasterCfg2.IsaMemCmdWidth =
(unsigned char) pSettings->usIsaMemCmdWidth;
rIsaProtCfg.Reserved = 0;
rIsaProtCfg.GateIOCHRDY = pSettings->bGateIOCHRDY;
rPowerMgmtCfg.Reserved = 0;
rPowerMgmtCfg.Enable = pSettings->bEnablePwrMgmt;
rHBusTimerCfg.LoadValue =
(unsigned char) pSettings->usHBusTimerLoadValue;
rLBusTimeoutDisable.Reserved = 0;
rLBusTimeoutDisable.DisableTimeout =
pSettings->bDisableLBusTimeout;
MKWORD(rChipReset) = ~pSettings->usChipletEnable;
rClockControl1.Reserved1 = rClockControl1.Reserved2 = 0;
rClockControl1.N_Divisor = pSettings->usN_Divisor;
rClockControl1.M_Multiplier = pSettings->usM_Multiplier;
rClockControl2.Reserved = 0;
rClockControl2.PllBypass = pSettings->bPllBypass;
/* Issue a soft reset to the chip */
/* Note: Since we may be coming in with 3780i clocks suspended, we must keep
* soft-reset active for 10ms.
*/
rSlaveControl.ClockControl = 0;
rSlaveControl.SoftReset = TRUE;
rSlaveControl.ConfigMode = FALSE;
rSlaveControl.Reserved = 0;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_EnableDSP usDspBaseIO %x index %x taddr %x\n",
usDspBaseIO, DSP_IsaSlaveControl,
usDspBaseIO + DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveContrl %x\n",
MKWORD(rSlaveControl));
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveControl 2 %x\n", tval);
for (i = 0; i < 11; i++)
udelay(2000);
rSlaveControl.SoftReset = FALSE;
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveControl 3 %x\n", tval);
/* Program our general configuration registers */
WriteGenCfg(DSP_HBridgeCfg1Index, MKBYTE(rHBridgeCfg1));
WriteGenCfg(DSP_HBridgeCfg2Index, MKBYTE(rHBridgeCfg2));
WriteGenCfg(DSP_BusMasterCfg1Index, MKBYTE(rBusmasterCfg1));
WriteGenCfg(DSP_BusMasterCfg2Index, MKBYTE(rBusmasterCfg2));
WriteGenCfg(DSP_IsaProtCfgIndex, MKBYTE(rIsaProtCfg));
WriteGenCfg(DSP_PowerMgCfgIndex, MKBYTE(rPowerMgmtCfg));
WriteGenCfg(DSP_HBusTimerCfgIndex, MKBYTE(rHBusTimerCfg));
if (pSettings->bModemEnabled) {
WriteGenCfg(DSP_UartCfg1Index, MKBYTE(rUartCfg1));
WriteGenCfg(DSP_UartCfg2Index, MKBYTE(rUartCfg2));
}
rHBridgeControl.EnableDspInt = FALSE;
rHBridgeControl.MemAutoInc = TRUE;
rHBridgeControl.IoAutoInc = FALSE;
rHBridgeControl.DiagnosticMode = FALSE;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n",
DSP_HBridgeControl, MKWORD(rHBridgeControl));
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
WriteMsaCfg(DSP_LBusTimeoutDisable, MKWORD(rLBusTimeoutDisable));
WriteMsaCfg(DSP_ClockControl_1, MKWORD(rClockControl1));
WriteMsaCfg(DSP_ClockControl_2, MKWORD(rClockControl2));
WriteMsaCfg(DSP_ChipReset, MKWORD(rChipReset));
ChipID = ReadMsaCfg(DSP_ChipID);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_EnableDSP exiting bRC=TRUE, ChipID %x\n",
ChipID);
return 0;
}
int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_ISA_SLAVE_CONTROL rSlaveControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n");
rSlaveControl.ClockControl = 0;
rSlaveControl.SoftReset = TRUE;
rSlaveControl.ConfigMode = FALSE;
rSlaveControl.Reserved = 0;
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
udelay(5);
rSlaveControl.ClockControl = 1;
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
spin_unlock_irqrestore(&dsp_lock, flags);
udelay(5);
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP exit\n");
return 0;
}
int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Reset entry\n");
spin_lock_irqsave(&dsp_lock, flags);
/* Mask DSP to PC interrupt */
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
rHBridgeControl.EnableDspInt = FALSE;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Reset the core via the boot domain register */
rBootDomain.ResetCore = TRUE;
rBootDomain.Halt = TRUE;
rBootDomain.NMI = TRUE;
rBootDomain.Reserved = 0;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n",
MKWORD(rBootDomain));
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
/* Reset all the chiplets and then reactivate them */
WriteMsaCfg(DSP_ChipReset, 0xFFFF);
udelay(5);
WriteMsaCfg(DSP_ChipReset,
(unsigned short) (~pSettings->usChipletEnable));
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Reset exit bRC=0\n");
return 0;
}
int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run entry\n");
/* Transition the core to a running state */
rBootDomain.ResetCore = TRUE;
rBootDomain.Halt = FALSE;
rBootDomain.NMI = TRUE;
rBootDomain.Reserved = 0;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
rBootDomain.ResetCore = FALSE;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
rBootDomain.NMI = FALSE;
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
udelay(5);
/* Enable DSP to PC interrupt */
spin_lock_irqsave(&dsp_lock, flags);
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
rHBridgeControl.EnableDspInt = TRUE;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=TRUE\n");
return 0;
}
int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Transfer the memory block */
while (uCount-- != 0) {
spin_lock_irqsave(&dsp_lock, flags);
val = InWordDsp(DSP_MsaDataDSISHigh);
spin_unlock_irqrestore(&dsp_lock, flags);
if(put_user(val, pusBuffer++))
return -EFAULT;
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_ReadDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadDStore exit bRC=TRUE\n");
return 0;
}
int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
void __user *pvBuffer, unsigned uCount,
unsigned long ulDSPAddr)
{
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadAndDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Transfer the memory block */
while (uCount-- != 0) {
spin_lock_irqsave(&dsp_lock, flags);
val = InWordDsp(DSP_ReadAndClear);
spin_unlock_irqrestore(&dsp_lock, flags);
if(put_user(val, pusBuffer++))
return -EFAULT;
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_ReadAndCleanDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadAndClearDStore exit bRC=TRUE\n");
return 0;
}
int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780D_WriteDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Transfer the memory block */
while (uCount-- != 0) {
unsigned short val;
if(get_user(val, pusBuffer++))
return -EFAULT;
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaDataDSISHigh, val);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_WriteDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780D_WriteDStore exit bRC=TRUE\n");
return 0;
}
int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadIStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/*
* Set the initial MSA address. To convert from an instruction store
* address to an MSA address
* shift the address two bits to the left and set bit 22
*/
ulDSPAddr = (ulDSPAddr << 2) | (1 << 22);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Transfer the memory block */
while (uCount-- != 0) {
unsigned short val_lo, val_hi;
spin_lock_irqsave(&dsp_lock, flags);
val_lo = InWordDsp(DSP_MsaDataISLow);
val_hi = InWordDsp(DSP_MsaDataDSISHigh);
spin_unlock_irqrestore(&dsp_lock, flags);
if(put_user(val_lo, pusBuffer++))
return -EFAULT;
if(put_user(val_hi, pusBuffer++))
return -EFAULT;
PRINTK_4(TRACE_3780I,
"3780I::dsp3780I_ReadIStore uCount %x val_lo %x val_hi %x\n",
uCount, val_lo, val_hi);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadIStore exit bRC=TRUE\n");
return 0;
}
int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr)
{
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_WriteIStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/*
* Set the initial MSA address. To convert from an instruction store
* address to an MSA address
* shift the address two bits to the left and set bit 22
*/
ulDSPAddr = (ulDSPAddr << 2) | (1 << 22);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
spin_unlock_irqrestore(&dsp_lock, flags);
/* Transfer the memory block */
while (uCount-- != 0) {
unsigned short val_lo, val_hi;
if(get_user(val_lo, pusBuffer++))
return -EFAULT;
if(get_user(val_hi, pusBuffer++))
return -EFAULT;
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaDataISLow, val_lo);
OutWordDsp(DSP_MsaDataDSISHigh, val_hi);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_4(TRACE_3780I,
"3780I::dsp3780I_WriteIStore uCount %x val_lo %x val_hi %x\n",
uCount, val_lo, val_hi);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_WriteIStore exit bRC=TRUE\n");
return 0;
}
int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
unsigned short *pusIPCSource)
{
unsigned long flags;
DSP_HBRIDGE_CONTROL rHBridgeControl;
unsigned short temp;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource entry usDspBaseIO %x pusIPCSource %p\n",
usDspBaseIO, pusIPCSource);
/*
* Disable DSP to PC interrupts, read the interrupt register,
* clear the pending IPC bits, and reenable DSP to PC interrupts
*/
spin_lock_irqsave(&dsp_lock, flags);
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
rHBridgeControl.EnableDspInt = FALSE;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
*pusIPCSource = InWordDsp(DSP_Interrupt);
temp = (unsigned short) ~(*pusIPCSource);
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource, usIPCSource %x ~ %x\n",
*pusIPCSource, temp);
OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource));
rHBridgeControl.EnableDspInt = TRUE;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource exit usIPCSource %x\n",
*pusIPCSource);
return 0;
}

358
drivers/char/mwave/3780i.h Normal file
View file

@ -0,0 +1,358 @@
/*
*
* 3780i.h -- declarations for 3780i.c
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#ifndef _LINUX_3780I_H
#define _LINUX_3780I_H
#include <asm/io.h>
/* DSP I/O port offsets and definitions */
#define DSP_IsaSlaveControl 0x0000 /* ISA slave control register */
#define DSP_IsaSlaveStatus 0x0001 /* ISA slave status register */
#define DSP_ConfigAddress 0x0002 /* General config address register */
#define DSP_ConfigData 0x0003 /* General config data register */
#define DSP_HBridgeControl 0x0002 /* HBridge control register */
#define DSP_MsaAddrLow 0x0004 /* MSP System Address, low word */
#define DSP_MsaAddrHigh 0x0006 /* MSP System Address, high word */
#define DSP_MsaDataDSISHigh 0x0008 /* MSA data register: d-store word or high byte of i-store */
#define DSP_MsaDataISLow 0x000A /* MSA data register: low word of i-store */
#define DSP_ReadAndClear 0x000C /* MSA read and clear data register */
#define DSP_Interrupt 0x000E /* Interrupt register (IPC source) */
typedef struct {
unsigned char ClockControl:1; /* RW: Clock control: 0=normal, 1=stop 3780i clocks */
unsigned char SoftReset:1; /* RW: Soft reset 0=normal, 1=soft reset active */
unsigned char ConfigMode:1; /* RW: Configuration mode, 0=normal, 1=config mode */
unsigned char Reserved:5; /* 0: Reserved */
} DSP_ISA_SLAVE_CONTROL;
typedef struct {
unsigned short EnableDspInt:1; /* RW: Enable DSP to X86 ISA interrupt 0=mask it, 1=enable it */
unsigned short MemAutoInc:1; /* RW: Memory address auto increment, 0=disable, 1=enable */
unsigned short IoAutoInc:1; /* RW: I/O address auto increment, 0=disable, 1=enable */
unsigned short DiagnosticMode:1; /* RW: Disgnostic mode 0=nromal, 1=diagnostic mode */
unsigned short IsaPacingTimer:12; /* R: ISA access pacing timer: count of core cycles stolen */
} DSP_HBRIDGE_CONTROL;
/* DSP register indexes used with the configuration register address (index) register */
#define DSP_UartCfg1Index 0x0003 /* UART config register 1 */
#define DSP_UartCfg2Index 0x0004 /* UART config register 2 */
#define DSP_HBridgeCfg1Index 0x0007 /* HBridge config register 1 */
#define DSP_HBridgeCfg2Index 0x0008 /* HBridge config register 2 */
#define DSP_BusMasterCfg1Index 0x0009 /* ISA bus master config register 1 */
#define DSP_BusMasterCfg2Index 0x000A /* ISA bus master config register 2 */
#define DSP_IsaProtCfgIndex 0x000F /* ISA protocol control register */
#define DSP_PowerMgCfgIndex 0x0010 /* Low poser suspend/resume enable */
#define DSP_HBusTimerCfgIndex 0x0011 /* HBUS timer load value */
typedef struct {
unsigned char IrqActiveLow:1; /* RW: IRQ active high or low: 0=high, 1=low */
unsigned char IrqPulse:1; /* RW: IRQ pulse or level: 0=level, 1=pulse */
unsigned char Irq:3; /* RW: IRQ selection */
unsigned char BaseIO:2; /* RW: Base I/O selection */
unsigned char Reserved:1; /* 0: Reserved */
} DSP_UART_CFG_1;
typedef struct {
unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=FALSE, 1=TRUE */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_UART_CFG_2;
typedef struct {
unsigned char IrqActiveLow:1; /* RW: IRQ active high=0 or low=1 */
unsigned char IrqPulse:1; /* RW: IRQ pulse=1 or level=0 */
unsigned char Irq:3; /* RW: IRQ selection */
unsigned char AccessMode:1; /* RW: 16-bit register access method 0=byte, 1=word */
unsigned char Reserved:2; /* 0: Reserved */
} DSP_HBRIDGE_CFG_1;
typedef struct {
unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=FALSE, 1=TRUE */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_HBRIDGE_CFG_2;
typedef struct {
unsigned char Dma:3; /* RW: DMA channel selection */
unsigned char NumTransfers:2; /* RW: Maximum # of transfers once being granted the ISA bus */
unsigned char ReRequest:2; /* RW: Minimum delay between releasing the ISA bus and requesting it again */
unsigned char MEMCS16:1; /* RW: ISA signal MEMCS16: 0=disabled, 1=enabled */
} DSP_BUSMASTER_CFG_1;
typedef struct {
unsigned char IsaMemCmdWidth:2; /* RW: ISA memory command width */
unsigned char Reserved:6; /* 0: Reserved */
} DSP_BUSMASTER_CFG_2;
typedef struct {
unsigned char GateIOCHRDY:1; /* RW: Enable IOCHRDY gating: 0=FALSE, 1=TRUE */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_ISA_PROT_CFG;
typedef struct {
unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=FALSE, 1=TRUE */
unsigned char Reserved:7; /* 0: Reserved */
} DSP_POWER_MGMT_CFG;
typedef struct {
unsigned char LoadValue:8; /* RW: HBUS timer load value */
} DSP_HBUS_TIMER_CFG;
/* DSP registers that exist in MSA I/O space */
#define DSP_ChipID 0x80000000
#define DSP_MspBootDomain 0x80000580
#define DSP_LBusTimeoutDisable 0x80000580
#define DSP_ClockControl_1 0x8000058A
#define DSP_ClockControl_2 0x8000058C
#define DSP_ChipReset 0x80000588
#define DSP_GpioModeControl_15_8 0x80000082
#define DSP_GpioDriverEnable_15_8 0x80000076
#define DSP_GpioOutputData_15_8 0x80000072
typedef struct {
unsigned short NMI:1; /* RW: non maskable interrupt */
unsigned short Halt:1; /* RW: Halt MSP clock */
unsigned short ResetCore:1; /* RW: Reset MSP core interface */
unsigned short Reserved:13; /* 0: Reserved */
} DSP_BOOT_DOMAIN;
typedef struct {
unsigned short DisableTimeout:1; /* RW: Disable LBus timeout */
unsigned short Reserved:15; /* 0: Reserved */
} DSP_LBUS_TIMEOUT_DISABLE;
typedef struct {
unsigned short Memory:1; /* RW: Reset memory interface */
unsigned short SerialPort1:1; /* RW: Reset serial port 1 interface */
unsigned short SerialPort2:1; /* RW: Reset serial port 2 interface */
unsigned short SerialPort3:1; /* RW: Reset serial port 3 interface */
unsigned short Gpio:1; /* RW: Reset GPIO interface */
unsigned short Dma:1; /* RW: Reset DMA interface */
unsigned short SoundBlaster:1; /* RW: Reset soundblaster interface */
unsigned short Uart:1; /* RW: Reset UART interface */
unsigned short Midi:1; /* RW: Reset MIDI interface */
unsigned short IsaMaster:1; /* RW: Reset ISA master interface */
unsigned short Reserved:6; /* 0: Reserved */
} DSP_CHIP_RESET;
typedef struct {
unsigned short N_Divisor:6; /* RW: (N) PLL output clock divisor */
unsigned short Reserved1:2; /* 0: reserved */
unsigned short M_Multiplier:6; /* RW: (M) PLL feedback clock multiplier */
unsigned short Reserved2:2; /* 0: reserved */
} DSP_CLOCK_CONTROL_1;
typedef struct {
unsigned short PllBypass:1; /* RW: PLL Bypass */
unsigned short Reserved:15; /* 0: Reserved */
} DSP_CLOCK_CONTROL_2;
typedef struct {
unsigned short Latch8:1;
unsigned short Latch9:1;
unsigned short Latch10:1;
unsigned short Latch11:1;
unsigned short Latch12:1;
unsigned short Latch13:1;
unsigned short Latch14:1;
unsigned short Latch15:1;
unsigned short Mask8:1;
unsigned short Mask9:1;
unsigned short Mask10:1;
unsigned short Mask11:1;
unsigned short Mask12:1;
unsigned short Mask13:1;
unsigned short Mask14:1;
unsigned short Mask15:1;
} DSP_GPIO_OUTPUT_DATA_15_8;
typedef struct {
unsigned short Enable8:1;
unsigned short Enable9:1;
unsigned short Enable10:1;
unsigned short Enable11:1;
unsigned short Enable12:1;
unsigned short Enable13:1;
unsigned short Enable14:1;
unsigned short Enable15:1;
unsigned short Mask8:1;
unsigned short Mask9:1;
unsigned short Mask10:1;
unsigned short Mask11:1;
unsigned short Mask12:1;
unsigned short Mask13:1;
unsigned short Mask14:1;
unsigned short Mask15:1;
} DSP_GPIO_DRIVER_ENABLE_15_8;
typedef struct {
unsigned short GpioMode8:2;
unsigned short GpioMode9:2;
unsigned short GpioMode10:2;
unsigned short GpioMode11:2;
unsigned short GpioMode12:2;
unsigned short GpioMode13:2;
unsigned short GpioMode14:2;
unsigned short GpioMode15:2;
} DSP_GPIO_MODE_15_8;
/* Component masks that are defined in dspmgr.h */
#define MW_ADC_MASK 0x0001
#define MW_AIC2_MASK 0x0006
#define MW_MIDI_MASK 0x0008
#define MW_CDDAC_MASK 0x8001
#define MW_AIC1_MASK 0xE006
#define MW_UART_MASK 0xE00A
#define MW_ACI_MASK 0xE00B
/*
* Definition of 3780i configuration structure. Unless otherwise stated,
* these values are provided as input to the 3780i support layer. At present,
* the only values maintained by the 3780i support layer are the saved UART
* registers.
*/
typedef struct _DSP_3780I_CONFIG_SETTINGS {
/* Location of base configuration register */
unsigned short usBaseConfigIO;
/* Enables for various DSP components */
int bDSPEnabled;
int bModemEnabled;
int bInterruptClaimed;
/* IRQ, DMA, and Base I/O addresses for various DSP components */
unsigned short usDspIrq;
unsigned short usDspDma;
unsigned short usDspBaseIO;
unsigned short usUartIrq;
unsigned short usUartBaseIO;
/* IRQ modes for various DSP components */
int bDspIrqActiveLow;
int bUartIrqActiveLow;
int bDspIrqPulse;
int bUartIrqPulse;
/* Card abilities */
unsigned uIps;
unsigned uDStoreSize;
unsigned uIStoreSize;
unsigned uDmaBandwidth;
/* Adapter specific 3780i settings */
unsigned short usNumTransfers;
unsigned short usReRequest;
int bEnableMEMCS16;
unsigned short usIsaMemCmdWidth;
int bGateIOCHRDY;
int bEnablePwrMgmt;
unsigned short usHBusTimerLoadValue;
int bDisableLBusTimeout;
unsigned short usN_Divisor;
unsigned short usM_Multiplier;
int bPllBypass;
unsigned short usChipletEnable; /* Used with the chip reset register to enable specific chiplets */
/* Saved UART registers. These are maintained by the 3780i support layer. */
int bUartSaved; /* True after a successful save of the UART registers */
unsigned char ucIER; /* Interrupt enable register */
unsigned char ucFCR; /* FIFO control register */
unsigned char ucLCR; /* Line control register */
unsigned char ucMCR; /* Modem control register */
unsigned char ucSCR; /* Scratch register */
unsigned char ucDLL; /* Divisor latch, low byte */
unsigned char ucDLM; /* Divisor latch, high byte */
} DSP_3780I_CONFIG_SETTINGS;
/* 3780i support functions */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
unsigned short *pIrqMap,
unsigned short *pDmaMap);
int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr);
int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
void __user *pvBuffer, unsigned uCount,
unsigned long ulDSPAddr);
int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr);
int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr);
int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr);
unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr);
void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr, unsigned short usValue);
int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
unsigned short *pusIPCSource);
/* I/O port access macros */
#define MKWORD(var) (*((unsigned short *)(&var)))
#define MKBYTE(var) (*((unsigned char *)(&var)))
#define WriteMsaCfg(addr,value) dsp3780I_WriteMsaCfg(usDspBaseIO,addr,value)
#define ReadMsaCfg(addr) dsp3780I_ReadMsaCfg(usDspBaseIO,addr)
#define WriteGenCfg(index,value) dsp3780I_WriteGenCfg(usDspBaseIO,index,value)
#define ReadGenCfg(index) dsp3780I_ReadGenCfg(usDspBaseIO,index)
#define InWordDsp(index) inw(usDspBaseIO+index)
#define InByteDsp(index) inb(usDspBaseIO+index)
#define OutWordDsp(index,value) outw(value,usDspBaseIO+index)
#define OutByteDsp(index,value) outb(value,usDspBaseIO+index)
#endif

View file

@ -0,0 +1,15 @@
#
# Makefile for ACP Modem (Mwave).
#
# See the README file in this directory for more info. <paulsch@us.ibm.com>
#
obj-$(CONFIG_MWAVE) += mwave.o
mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o
# To have the mwave driver disable other uarts if necessary
# ccflags-y := -DMWAVE_FUTZ_WITH_OTHER_DEVICES
# To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
ccflags-y += -DMW_TRACE

47
drivers/char/mwave/README Normal file
View file

@ -0,0 +1,47 @@
Module options
--------------
The mwave module takes the following options. Note that these options
are not saved by the BIOS and so do not persist after unload and reload.
mwave_debug=value, where value is bitwise OR of trace flags:
0x0001 mwavedd api tracing
0x0002 smapi api tracing
0x0004 3780i tracing
0x0008 tp3780i tracing
Tracing only occurs if the driver has been compiled with the
MW_TRACE macro #defined (i.e. let ccflags-y := -DMW_TRACE
in the Makefile).
mwave_3780i_irq=5/7/10/11/15
If the dsp irq has not been setup and stored in bios by the
thinkpad configuration utility then this parameter allows the
irq used by the dsp to be configured.
mwave_3780i_io=0x130/0x350/0x0070/0xDB0
If the dsp io range has not been setup and stored in bios by the
thinkpad configuration utility then this parameter allows the
io range used by the dsp to be configured.
mwave_uart_irq=3/4
If the mwave's uart irq has not been setup and stored in bios by the
thinkpad configuration utility then this parameter allows the
irq used by the mwave uart to be configured.
mwave_uart_io=0x3f8/0x2f8/0x3E8/0x2E8
If the uart io range has not been setup and stored in bios by the
thinkpad configuration utility then this parameter allows the
io range used by the mwave uart to be configured.
Example to enable the 3780i DSP using ttyS1 resources:
insmod mwave mwave_3780i_irq=10 mwave_3780i_io=0x0130 mwave_uart_irq=3 mwave_uart_io=0x2f8
Accessing the driver
--------------------
You must also create a node for the driver:
mkdir -p /dev/modems
mknod --mode=660 /dev/modems/mwave c 10 219

View file

@ -0,0 +1,697 @@
/*
*
* mwavedd.c -- mwave device driver
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/serial_8250.h>
#include "smapi.h"
#include "mwavedd.h"
#include "3780i.h"
#include "tp3780i.h"
MODULE_DESCRIPTION("3780i Advanced Communications Processor (Mwave) driver");
MODULE_AUTHOR("Mike Sullivan and Paul Schroeder");
MODULE_LICENSE("GPL");
/*
* These parameters support the setting of MWave resources. Note that no
* checks are made against other devices (ie. superio) for conflicts.
* We'll depend on users using the tpctl utility to do that for now
*/
static DEFINE_MUTEX(mwave_mutex);
int mwave_debug = 0;
int mwave_3780i_irq = 0;
int mwave_3780i_io = 0;
int mwave_uart_irq = 0;
int mwave_uart_io = 0;
module_param(mwave_debug, int, 0);
module_param(mwave_3780i_irq, int, 0);
module_param(mwave_3780i_io, int, 0);
module_param(mwave_uart_irq, int, 0);
module_param(mwave_uart_io, int, 0);
static int mwave_open(struct inode *inode, struct file *file);
static int mwave_close(struct inode *inode, struct file *file);
static long mwave_ioctl(struct file *filp, unsigned int iocmd,
unsigned long ioarg);
MWAVE_DEVICE_DATA mwave_s_mdd;
static int mwave_open(struct inode *inode, struct file *file)
{
unsigned int retval = 0;
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_open, entry inode %p file %p\n",
inode, file);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_open, exit return retval %x\n", retval);
return retval;
}
static int mwave_close(struct inode *inode, struct file *file)
{
unsigned int retval = 0;
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_close, entry inode %p file %p\n",
inode, file);
PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",
retval);
return retval;
}
static long mwave_ioctl(struct file *file, unsigned int iocmd,
unsigned long ioarg)
{
unsigned int retval = 0;
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
void __user *arg = (void __user *)ioarg;
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",
file, iocmd, (int) ioarg);
switch (iocmd) {
case IOCTL_MW_RESET:
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" calling tp3780I_ResetDSP\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_ResetDSP(&pDrvData->rBDData);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" retval %x from tp3780I_ResetDSP\n",
retval);
break;
case IOCTL_MW_RUN:
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" calling tp3780I_StartDSP\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_StartDSP(&pDrvData->rBDData);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" retval %x from tp3780I_StartDSP\n",
retval);
break;
case IOCTL_MW_DSP_ABILITIES: {
MW_ABILITIES rAbilities;
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl,"
" IOCTL_MW_DSP_ABILITIES calling"
" tp3780I_QueryAbilities\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
&rAbilities);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
" retval %x from tp3780I_QueryAbilities\n",
retval);
if (retval == 0) {
if( copy_to_user(arg, &rAbilities,
sizeof(MW_ABILITIES)) )
return -EFAULT;
}
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
" exit retval %x\n",
retval);
}
break;
case IOCTL_MW_READ_DATA:
case IOCTL_MW_READCLEAR_DATA: {
MW_READWRITE rReadData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rReadData, arg,
sizeof(MW_READWRITE)) )
return -EFAULT;
pusBuffer = (unsigned short __user *) (rReadData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength, ioarg, pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd,
pusBuffer,
rReadData.ulDataLength,
rReadData.usDspAddress);
mutex_unlock(&mwave_mutex);
}
break;
case IOCTL_MW_READ_INST: {
MW_READWRITE rReadData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rReadData, arg,
sizeof(MW_READWRITE)) )
return -EFAULT;
pusBuffer = (unsigned short __user *) (rReadData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength / 2, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rReadData.ulDataLength / 2,
rReadData.usDspAddress);
mutex_unlock(&mwave_mutex);
}
break;
case IOCTL_MW_WRITE_DATA: {
MW_READWRITE rWriteData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rWriteData, arg,
sizeof(MW_READWRITE)) )
return -EFAULT;
pusBuffer = (unsigned short __user *) (rWriteData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rWriteData.ulDataLength,
rWriteData.usDspAddress);
mutex_unlock(&mwave_mutex);
}
break;
case IOCTL_MW_WRITE_INST: {
MW_READWRITE rWriteData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rWriteData, arg,
sizeof(MW_READWRITE)) )
return -EFAULT;
pusBuffer = (unsigned short __user *)(rWriteData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
iocmd, pusBuffer,
rWriteData.ulDataLength,
rWriteData.usDspAddress);
mutex_unlock(&mwave_mutex);
}
break;
case IOCTL_MW_REGISTER_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_REGISTER_IPC:"
" Error: Invalid ipcnum %x\n",
ipcnum);
return -EINVAL;
}
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
" ipcnum %x entry usIntCount %x\n",
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
" ipcnum %x exit\n",
ipcnum);
}
break;
case IOCTL_MW_GET_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_GET_IPC: Error:"
" Invalid ipcnum %x\n", ipcnum);
return -EINVAL;
}
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
" ipcnum %x, usIntCount %x\n",
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
DECLARE_WAITQUEUE(wait, current);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, thread for"
" ipc %x going to sleep\n",
ipcnum);
add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
pDrvData->IPCs[ipcnum].bIsHere = TRUE;
set_current_state(TASK_INTERRUPTIBLE);
/* check whether an event was signalled by */
/* the interrupt handler while we were gone */
if (pDrvData->IPCs[ipcnum].usIntCount == 1) { /* first int has occurred (race condition) */
pDrvData->IPCs[ipcnum].usIntCount = 2; /* first int has been handled */
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl"
" IOCTL_MW_GET_IPC ipcnum %x"
" handling first int\n",
ipcnum);
} else { /* either 1st int has not yet occurred, or we have already handled the first int */
schedule();
if (pDrvData->IPCs[ipcnum].usIntCount == 1) {
pDrvData->IPCs[ipcnum].usIntCount = 2;
}
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl"
" IOCTL_MW_GET_IPC ipcnum %x"
" woke up and returning to"
" application\n",
ipcnum);
}
pDrvData->IPCs[ipcnum].bIsHere = FALSE;
remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
set_current_state(TASK_RUNNING);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"
" returning thread for ipc %x"
" processing\n",
ipcnum);
}
mutex_unlock(&mwave_mutex);
}
break;
case IOCTL_MW_UNREGISTER_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
" ipcnum %x\n",
ipcnum);
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_UNREGISTER_IPC:"
" Error: Invalid ipcnum %x\n",
ipcnum);
return -EINVAL;
}
mutex_lock(&mwave_mutex);
if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
}
}
mutex_unlock(&mwave_mutex);
}
break;
default:
return -ENOTTY;
break;
} /* switch */
PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);
return retval;
}
static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
PRINTK_5(TRACE_MWAVE,
"mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",
file, buf, count, ppos);
return -EINVAL;
}
static ssize_t mwave_write(struct file *file, const char __user *buf,
size_t count, loff_t * ppos)
{
PRINTK_5(TRACE_MWAVE,
"mwavedd::mwave_write entry file %p, buf %p,"
" count %zx ppos %p\n",
file, buf, count, ppos);
return -EINVAL;
}
static int register_serial_portandirq(unsigned int port, int irq)
{
struct uart_8250_port uart;
switch ( port ) {
case 0x3f8:
case 0x2f8:
case 0x3e8:
case 0x2e8:
/* OK */
break;
default:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::register_serial_portandirq:"
" Error: Illegal port %x\n", port );
return -1;
} /* switch */
/* port is okay */
switch ( irq ) {
case 3:
case 4:
case 5:
case 7:
/* OK */
break;
default:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::register_serial_portandirq:"
" Error: Illegal irq %x\n", irq );
return -1;
} /* switch */
/* irq is okay */
memset(&uart, 0, sizeof(uart));
uart.port.uartclk = 1843200;
uart.port.iobase = port;
uart.port.irq = irq;
uart.port.iotype = UPIO_PORT;
uart.port.flags = UPF_SHARE_IRQ;
return serial8250_register_8250_port(&uart);
}
static const struct file_operations mwave_fops = {
.owner = THIS_MODULE,
.read = mwave_read,
.write = mwave_write,
.unlocked_ioctl = mwave_ioctl,
.open = mwave_open,
.release = mwave_close,
.llseek = default_llseek,
};
static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
#if 0 /* totally b0rked */
/*
* sysfs support <paulsch@us.ibm.com>
*/
struct device mwave_device;
/* Prevent code redundancy, create a macro for mwave_show_* functions. */
#define mwave_show_function(attr_name, format_string, field) \
static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
DSP_3780I_CONFIG_SETTINGS *pSettings = \
&mwave_s_mdd.rBDData.rDspSettings; \
return sprintf(buf, format_string, pSettings->field); \
}
/* All of our attributes are read attributes. */
#define mwave_dev_rd_attr(attr_name, format_string, field) \
mwave_show_function(attr_name, format_string, field) \
static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
static struct device_attribute * const mwave_dev_attrs[] = {
&dev_attr_3780i_dma,
&dev_attr_3780i_irq,
&dev_attr_3780i_io,
&dev_attr_uart_irq,
&dev_attr_uart_io,
};
#endif
/*
* mwave_init is called on module load
*
* mwave_exit is called on module unload
* mwave_exit is also used to clean up after an aborted mwave_init
*/
static void mwave_exit(void)
{
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
#if 0
for (i = 0; i < pDrvData->nr_registered_attrs; i++)
device_remove_file(&mwave_device, mwave_dev_attrs[i]);
pDrvData->nr_registered_attrs = 0;
if (pDrvData->device_registered) {
device_unregister(&mwave_device);
pDrvData->device_registered = FALSE;
}
#endif
if ( pDrvData->sLine >= 0 ) {
serial8250_unregister_port(pDrvData->sLine);
}
if (pDrvData->bMwaveDevRegistered) {
misc_deregister(&mwave_misc_dev);
}
if (pDrvData->bDSPEnabled) {
tp3780I_DisableDSP(&pDrvData->rBDData);
}
if (pDrvData->bResourcesClaimed) {
tp3780I_ReleaseResources(&pDrvData->rBDData);
}
if (pDrvData->bBDInitialized) {
tp3780I_Cleanup(&pDrvData->rBDData);
}
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
}
module_exit(mwave_exit);
static int __init mwave_init(void)
{
int i;
int retval = 0;
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
pDrvData->bBDInitialized = FALSE;
pDrvData->bResourcesClaimed = FALSE;
pDrvData->bDSPEnabled = FALSE;
pDrvData->bDSPReset = FALSE;
pDrvData->bMwaveDevRegistered = FALSE;
pDrvData->sLine = -1;
for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
pDrvData->IPCs[i].bIsEnabled = FALSE;
pDrvData->IPCs[i].bIsHere = FALSE;
pDrvData->IPCs[i].usIntCount = 0; /* no ints received yet */
init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
}
retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_init: Error:"
" Failed to initialize board data\n");
goto cleanup_error;
}
pDrvData->bBDInitialized = TRUE;
retval = tp3780I_CalcResources(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_CalcResources"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to calculate resources\n");
goto cleanup_error;
}
retval = tp3780I_ClaimResources(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_ClaimResources"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to claim resources\n");
goto cleanup_error;
}
pDrvData->bResourcesClaimed = TRUE;
retval = tp3780I_EnableDSP(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_EnableDSP"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to enable DSP\n");
goto cleanup_error;
}
pDrvData->bDSPEnabled = TRUE;
if (misc_register(&mwave_misc_dev) < 0) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to register misc device\n");
goto cleanup_error;
}
pDrvData->bMwaveDevRegistered = TRUE;
pDrvData->sLine = register_serial_portandirq(
pDrvData->rBDData.rDspSettings.usUartBaseIO,
pDrvData->rBDData.rDspSettings.usUartIrq
);
if (pDrvData->sLine < 0) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to register serial driver\n");
goto cleanup_error;
}
/* uart is registered */
#if 0
/* sysfs */
memset(&mwave_device, 0, sizeof (struct device));
dev_set_name(&mwave_device, "mwave");
if (device_register(&mwave_device))
goto cleanup_error;
pDrvData->device_registered = TRUE;
for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to create sysfs file %s\n",
mwave_dev_attrs[i]->attr.name);
goto cleanup_error;
}
pDrvData->nr_registered_attrs++;
}
#endif
/* SUCCESS! */
return 0;
cleanup_error:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_init: Error:"
" Failed to initialize\n");
mwave_exit(); /* clean up */
return -EIO;
}
module_init(mwave_init);

View file

@ -0,0 +1,152 @@
/*
*
* mwavedd.h -- declarations for mwave device driver
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#ifndef _LINUX_MWAVEDD_H
#define _LINUX_MWAVEDD_H
#include "3780i.h"
#include "tp3780i.h"
#include "smapi.h"
#include "mwavepub.h"
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
extern int mwave_debug;
extern int mwave_3780i_irq;
extern int mwave_3780i_io;
extern int mwave_uart_irq;
extern int mwave_uart_io;
#define PRINTK_ERROR printk
#define KERN_ERR_MWAVE KERN_ERR "mwave: "
#define TRACE_MWAVE 0x0001
#define TRACE_SMAPI 0x0002
#define TRACE_3780I 0x0004
#define TRACE_TP3780I 0x0008
#ifdef MW_TRACE
#define PRINTK_1(f,s) \
if (f & (mwave_debug)) { \
printk(s); \
}
#define PRINTK_2(f,s,v1) \
if (f & (mwave_debug)) { \
printk(s,v1); \
}
#define PRINTK_3(f,s,v1,v2) \
if (f & (mwave_debug)) { \
printk(s,v1,v2); \
}
#define PRINTK_4(f,s,v1,v2,v3) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3); \
}
#define PRINTK_5(f,s,v1,v2,v3,v4) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4); \
}
#define PRINTK_6(f,s,v1,v2,v3,v4,v5) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5); \
}
#define PRINTK_7(f,s,v1,v2,v3,v4,v5,v6) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5,v6); \
}
#define PRINTK_8(f,s,v1,v2,v3,v4,v5,v6,v7) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5,v6,v7); \
}
#else
#define PRINTK_1(f,s)
#define PRINTK_2(f,s,v1)
#define PRINTK_3(f,s,v1,v2)
#define PRINTK_4(f,s,v1,v2,v3)
#define PRINTK_5(f,s,v1,v2,v3,v4)
#define PRINTK_6(f,s,v1,v2,v3,v4,v5)
#define PRINTK_7(f,s,v1,v2,v3,v4,v5,v6)
#define PRINTK_8(f,s,v1,v2,v3,v4,v5,v6,v7)
#endif
typedef struct _MWAVE_IPC {
unsigned short usIntCount; /* 0=none, 1=first, 2=greater than 1st */
BOOLEAN bIsEnabled;
BOOLEAN bIsHere;
/* entry spin lock */
wait_queue_head_t ipc_wait_queue;
} MWAVE_IPC;
typedef struct _MWAVE_DEVICE_DATA {
THINKPAD_BD_DATA rBDData; /* board driver's data area */
unsigned long ulIPCSource_ISR; /* IPC source bits for recently processed intr, set during ISR processing */
unsigned long ulIPCSource_DPC; /* IPC source bits for recently processed intr, set during DPC processing */
BOOLEAN bBDInitialized;
BOOLEAN bResourcesClaimed;
BOOLEAN bDSPEnabled;
BOOLEAN bDSPReset;
MWAVE_IPC IPCs[16];
BOOLEAN bMwaveDevRegistered;
short sLine;
int nr_registered_attrs;
int device_registered;
} MWAVE_DEVICE_DATA, *pMWAVE_DEVICE_DATA;
extern MWAVE_DEVICE_DATA mwave_s_mdd;
#endif

View file

@ -0,0 +1,89 @@
/*
*
* mwavepub.h -- PUBLIC declarations for the mwave driver
* and applications using it
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#ifndef _LINUX_MWAVEPUB_H
#define _LINUX_MWAVEPUB_H
#include <linux/miscdevice.h>
typedef struct _MW_ABILITIES {
unsigned long instr_per_sec;
unsigned long data_size;
unsigned long inst_size;
unsigned long bus_dma_bw;
unsigned short uart_enable;
short component_count;
unsigned long component_list[7];
char mwave_os_name[16];
char bios_task_name[16];
} MW_ABILITIES, *pMW_ABILITIES;
typedef struct _MW_READWRITE {
unsigned short usDspAddress; /* The dsp address */
unsigned long ulDataLength; /* The size in bytes of the data or user buffer */
void __user *pBuf; /* Input:variable sized buffer */
} MW_READWRITE, *pMW_READWRITE;
#define IOCTL_MW_RESET _IO(MWAVE_MINOR,1)
#define IOCTL_MW_RUN _IO(MWAVE_MINOR,2)
#define IOCTL_MW_DSP_ABILITIES _IOR(MWAVE_MINOR,3,MW_ABILITIES)
#define IOCTL_MW_READ_DATA _IOR(MWAVE_MINOR,4,MW_READWRITE)
#define IOCTL_MW_READCLEAR_DATA _IOR(MWAVE_MINOR,5,MW_READWRITE)
#define IOCTL_MW_READ_INST _IOR(MWAVE_MINOR,6,MW_READWRITE)
#define IOCTL_MW_WRITE_DATA _IOW(MWAVE_MINOR,7,MW_READWRITE)
#define IOCTL_MW_WRITE_INST _IOW(MWAVE_MINOR,8,MW_READWRITE)
#define IOCTL_MW_REGISTER_IPC _IOW(MWAVE_MINOR,9,int)
#define IOCTL_MW_UNREGISTER_IPC _IOW(MWAVE_MINOR,10,int)
#define IOCTL_MW_GET_IPC _IOW(MWAVE_MINOR,11,int)
#define IOCTL_MW_TRACE _IOR(MWAVE_MINOR,12,MW_READWRITE)
#endif

570
drivers/char/mwave/smapi.c Normal file
View file

@ -0,0 +1,570 @@
/*
*
* smapi.c -- SMAPI interface routines
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#include <linux/kernel.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
#include "smapi.h"
#include "mwavedd.h"
static unsigned short g_usSmapiPort = 0;
static int smapi_request(unsigned short inBX, unsigned short inCX,
unsigned short inDI, unsigned short inSI,
unsigned short *outAX, unsigned short *outBX,
unsigned short *outCX, unsigned short *outDX,
unsigned short *outDI, unsigned short *outSI)
{
unsigned short myoutAX = 2, *pmyoutAX = &myoutAX;
unsigned short myoutBX = 3, *pmyoutBX = &myoutBX;
unsigned short myoutCX = 4, *pmyoutCX = &myoutCX;
unsigned short myoutDX = 5, *pmyoutDX = &myoutDX;
unsigned short myoutDI = 6, *pmyoutDI = &myoutDI;
unsigned short myoutSI = 7, *pmyoutSI = &myoutSI;
unsigned short usSmapiOK = -EIO, *pusSmapiOK = &usSmapiOK;
unsigned int inBXCX = (inBX << 16) | inCX;
unsigned int inDISI = (inDI << 16) | inSI;
int retval = 0;
PRINTK_5(TRACE_SMAPI, "inBX %x inCX %x inDI %x inSI %x\n",
inBX, inCX, inDI, inSI);
__asm__ __volatile__("movw $0x5380,%%ax\n\t"
"movl %7,%%ebx\n\t"
"shrl $16, %%ebx\n\t"
"movw %7,%%cx\n\t"
"movl %8,%%edi\n\t"
"shrl $16,%%edi\n\t"
"movw %8,%%si\n\t"
"movw %9,%%dx\n\t"
"out %%al,%%dx\n\t"
"out %%al,$0x4F\n\t"
"cmpb $0x53,%%ah\n\t"
"je 2f\n\t"
"1:\n\t"
"orb %%ah,%%ah\n\t"
"jnz 2f\n\t"
"movw %%ax,%0\n\t"
"movw %%bx,%1\n\t"
"movw %%cx,%2\n\t"
"movw %%dx,%3\n\t"
"movw %%di,%4\n\t"
"movw %%si,%5\n\t"
"movw $1,%6\n\t"
"2:\n\t":"=m"(*(unsigned short *) pmyoutAX),
"=m"(*(unsigned short *) pmyoutBX),
"=m"(*(unsigned short *) pmyoutCX),
"=m"(*(unsigned short *) pmyoutDX),
"=m"(*(unsigned short *) pmyoutDI),
"=m"(*(unsigned short *) pmyoutSI),
"=m"(*(unsigned short *) pusSmapiOK)
:"m"(inBXCX), "m"(inDISI), "m"(g_usSmapiPort)
:"%eax", "%ebx", "%ecx", "%edx", "%edi",
"%esi");
PRINTK_8(TRACE_SMAPI,
"myoutAX %x myoutBX %x myoutCX %x myoutDX %x myoutDI %x myoutSI %x usSmapiOK %x\n",
myoutAX, myoutBX, myoutCX, myoutDX, myoutDI, myoutSI,
usSmapiOK);
*outAX = myoutAX;
*outBX = myoutBX;
*outCX = myoutCX;
*outDX = myoutDX;
*outDI = myoutDI;
*outSI = myoutSI;
retval = (usSmapiOK == 1) ? 0 : -EIO;
PRINTK_2(TRACE_SMAPI, "smapi::smapi_request exit retval %x\n", retval);
return retval;
}
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
{
int bRC = -EIO;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
unsigned short ausDspBases[] = { 0x0030, 0x4E30, 0x8E30, 0xCE30, 0x0130, 0x0350, 0x0070, 0x0DB0 };
unsigned short ausUartBases[] = { 0x03F8, 0x02F8, 0x03E8, 0x02E8 };
unsigned short numDspBases = 8;
unsigned short numUartBases = 4;
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg entry\n");
bRC = smapi_request(0x1802, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Error: Could not get DSP Settings. Aborting.\n");
return bRC;
}
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n");
pSettings->bDSPPresent = ((usBX & 0x0100) != 0);
pSettings->bDSPEnabled = ((usCX & 0x0001) != 0);
pSettings->usDspIRQ = usSI & 0x00FF;
pSettings->usDspDMA = (usSI & 0xFF00) >> 8;
if ((usDI & 0x00FF) < numDspBases) {
pSettings->usDspBaseIO = ausDspBases[usDI & 0x00FF];
} else {
pSettings->usDspBaseIO = 0;
}
PRINTK_6(TRACE_SMAPI,
"smapi::smapi_query_DSP_cfg get DSP Settings bDSPPresent %x bDSPEnabled %x usDspIRQ %x usDspDMA %x usDspBaseIO %x\n",
pSettings->bDSPPresent, pSettings->bDSPEnabled,
pSettings->usDspIRQ, pSettings->usDspDMA,
pSettings->usDspBaseIO);
/* check for illegal values */
if ( pSettings->usDspBaseIO == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP base I/O address is 0\n");
if ( pSettings->usDspIRQ == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP IRQ line is 0\n");
bRC = smapi_request(0x1804, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) {
PRINTK_ERROR("smapi::smapi_query_DSP_cfg: Error: Could not get DSP modem settings. Aborting.\n");
return bRC;
}
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n");
pSettings->bModemEnabled = ((usCX & 0x0001) != 0);
pSettings->usUartIRQ = usSI & 0x000F;
if (((usSI & 0xFF00) >> 8) < numUartBases) {
pSettings->usUartBaseIO = ausUartBases[(usSI & 0xFF00) >> 8];
} else {
pSettings->usUartBaseIO = 0;
}
PRINTK_4(TRACE_SMAPI,
"smapi::smapi_query_DSP_cfg get DSP modem settings bModemEnabled %x usUartIRQ %x usUartBaseIO %x\n",
pSettings->bModemEnabled,
pSettings->usUartIRQ,
pSettings->usUartBaseIO);
/* check for illegal values */
if ( pSettings->usUartBaseIO == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART base I/O address is 0\n");
if ( pSettings->usUartIRQ == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART IRQ line is 0\n");
PRINTK_2(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg exit bRC %x\n", bRC);
return bRC;
}
int smapi_set_DSP_cfg(void)
{
int bRC = -EIO;
int i;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
unsigned short ausDspBases[] = { 0x0030, 0x4E30, 0x8E30, 0xCE30, 0x0130, 0x0350, 0x0070, 0x0DB0 };
unsigned short ausUartBases[] = { 0x03F8, 0x02F8, 0x03E8, 0x02E8 };
unsigned short ausDspIrqs[] = { 5, 7, 10, 11, 15 };
unsigned short ausUartIrqs[] = { 3, 4 };
unsigned short numDspBases = 8;
unsigned short numUartBases = 4;
unsigned short numDspIrqs = 5;
unsigned short numUartIrqs = 2;
unsigned short dspio_index = 0, uartio_index = 0;
PRINTK_5(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg entry mwave_3780i_irq %x mwave_3780i_io %x mwave_uart_irq %x mwave_uart_io %x\n",
mwave_3780i_irq, mwave_3780i_io, mwave_uart_irq, mwave_uart_io);
if (mwave_3780i_io) {
for (i = 0; i < numDspBases; i++) {
if (mwave_3780i_io == ausDspBases[i])
break;
}
if (i == numDspBases) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io);
return bRC;
}
dspio_index = i;
}
if (mwave_3780i_irq) {
for (i = 0; i < numDspIrqs; i++) {
if (mwave_3780i_irq == ausDspIrqs[i])
break;
}
if (i == numDspIrqs) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq);
return bRC;
}
}
if (mwave_uart_io) {
for (i = 0; i < numUartBases; i++) {
if (mwave_uart_io == ausUartBases[i])
break;
}
if (i == numUartBases) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io);
return bRC;
}
uartio_index = i;
}
if (mwave_uart_irq) {
for (i = 0; i < numUartIrqs; i++) {
if (mwave_uart_irq == ausUartIrqs[i])
break;
}
if (i == numUartIrqs) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq);
return bRC;
}
}
if (mwave_uart_irq || mwave_uart_io) {
/* Check serial port A */
bRC = smapi_request(0x1402, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
/* bRC == 0 */
if (usBX & 0x0100) { /* serial port A is present */
if (usCX & 1) { /* serial port is enabled */
if ((usSI & 0xFF) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
bRC = smapi_request(0x1403, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1402, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
} else {
if ((usSI >> 8) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port A\n");
bRC = smapi_request (0x1403, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request (0x1402, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
}
}
}
}
/* Check serial port B */
bRC = smapi_request(0x1404, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
/* bRC == 0 */
if (usBX & 0x0100) { /* serial port B is present */
if (usCX & 1) { /* serial port is enabled */
if ((usSI & 0xFF) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
bRC = smapi_request(0x1405, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1404, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
} else {
if ((usSI >> 8) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1 (TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
bRC = smapi_request (0x1405, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request (0x1404, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
}
}
}
}
/* Check IR port */
bRC = smapi_request(0x1700, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1704, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
/* bRC == 0 */
if ((usCX & 0xff) != 0xff) { /* IR port not disabled */
if ((usCX & 0xff) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
bRC = smapi_request(0x1701, 0x0100, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1700, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1704, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
} else {
if ((usSI & 0xff) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
bRC = smapi_request(0x1701, 0x0100, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1700, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1704, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
goto exit_conflict;
#endif
}
}
}
}
bRC = smapi_request(0x1802, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
if (mwave_3780i_io) {
usDI = dspio_index;
}
if (mwave_3780i_irq) {
usSI = (usSI & 0xff00) | mwave_3780i_irq;
}
bRC = smapi_request(0x1803, 0x0101, usDI, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1804, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
if (mwave_uart_io) {
usSI = (usSI & 0x00ff) | (uartio_index << 8);
}
if (mwave_uart_irq) {
usSI = (usSI & 0xff00) | mwave_uart_irq;
}
bRC = smapi_request(0x1805, 0x0101, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1802, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1804, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
/* normal exit: */
PRINTK_1(TRACE_SMAPI, "smapi::smapi_set_DSP_cfg exit\n");
return 0;
exit_conflict:
/* Message has already been printed */
return -EIO;
exit_smapi_request_error:
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg exit on smapi_request error bRC %x\n", bRC);
return bRC;
}
int smapi_set_DSP_power_state(BOOLEAN bOn)
{
int bRC = -EIO;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
unsigned short usPowerFunction;
PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state entry bOn %x\n", bOn);
usPowerFunction = (bOn) ? 1 : 0;
bRC = smapi_request(0x4901, 0x0000, 0, usPowerFunction,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state exit bRC %x\n", bRC);
return bRC;
}
#if 0
static int SmapiQuerySystemID(void)
{
int bRC = -EIO;
unsigned short usAX = 0xffff, usBX = 0xffff, usCX = 0xffff,
usDX = 0xffff, usDI = 0xffff, usSI = 0xffff;
printk("smapi::SmapiQUerySystemID entry\n");
bRC = smapi_request(0x0000, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC == 0) {
printk("AX=%x, BX=%x, CX=%x, DX=%x, DI=%x, SI=%x\n",
usAX, usBX, usCX, usDX, usDI, usSI);
} else {
printk("smapi::SmapiQuerySystemID smapi_request error\n");
}
return bRC;
}
#endif /* 0 */
int smapi_init(void)
{
int retval = -EIO;
unsigned short usSmapiID = 0;
unsigned long flags;
PRINTK_1(TRACE_SMAPI, "smapi::smapi_init entry\n");
spin_lock_irqsave(&rtc_lock, flags);
usSmapiID = CMOS_READ(0x7C);
usSmapiID |= (CMOS_READ(0x7D) << 8);
spin_unlock_irqrestore(&rtc_lock, flags);
PRINTK_2(TRACE_SMAPI, "smapi::smapi_init usSmapiID %x\n", usSmapiID);
if (usSmapiID == 0x5349) {
spin_lock_irqsave(&rtc_lock, flags);
g_usSmapiPort = CMOS_READ(0x7E);
g_usSmapiPort |= (CMOS_READ(0x7F) << 8);
spin_unlock_irqrestore(&rtc_lock, flags);
if (g_usSmapiPort == 0) {
PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n");
} else {
PRINTK_2(TRACE_SMAPI,
"smapi::smapi_init, exit TRUE g_usSmapiPort %x\n",
g_usSmapiPort);
retval = 0;
//SmapiQuerySystemID();
}
} else {
PRINTK_ERROR("smapi::smapi_init, ERROR invalid usSmapiID\n");
retval = -ENXIO;
}
return retval;
}

View file

@ -0,0 +1,80 @@
/*
*
* smapi.h -- declarations for SMAPI interface routines
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#ifndef _LINUX_SMAPI_H
#define _LINUX_SMAPI_H
#define TRUE 1
#define FALSE 0
#define BOOLEAN int
typedef struct {
int bDSPPresent;
int bDSPEnabled;
int bModemEnabled;
int bMIDIEnabled;
int bSblstEnabled;
unsigned short usDspIRQ;
unsigned short usDspDMA;
unsigned short usDspBaseIO;
unsigned short usUartIRQ;
unsigned short usUartBaseIO;
unsigned short usMidiIRQ;
unsigned short usMidiBaseIO;
unsigned short usSndblstIRQ;
unsigned short usSndblstDMA;
unsigned short usSndblstBaseIO;
} SMAPI_DSP_SETTINGS;
int smapi_init(void);
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings);
int smapi_set_DSP_cfg(void);
int smapi_set_DSP_power_state(BOOLEAN bOn);
#endif

View file

@ -0,0 +1,580 @@
/*
*
* tp3780i.c -- board driver for 3780i on ThinkPads
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include "smapi.h"
#include "mwavedd.h"
#include "tp3780i.h"
#include "3780i.h"
#include "mwavepub.h"
static unsigned short s_ausThinkpadIrqToField[16] =
{ 0xFFFF, 0xFFFF, 0xFFFF, 0x0001, 0x0002, 0x0003, 0xFFFF, 0x0004,
0xFFFF, 0xFFFF, 0x0005, 0x0006, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007 };
static unsigned short s_ausThinkpadDmaToField[8] =
{ 0x0001, 0x0002, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0003, 0x0004 };
static unsigned short s_numIrqs = 16, s_numDmas = 8;
static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_GPIO_OUTPUT_DATA_15_8 rGpioOutputData;
DSP_GPIO_DRIVER_ENABLE_15_8 rGpioDriverEnable;
DSP_GPIO_MODE_15_8 rGpioMode;
PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM, entry\n");
MKWORD(rGpioMode) = ReadMsaCfg(DSP_GpioModeControl_15_8);
rGpioMode.GpioMode10 = 0;
WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode));
MKWORD(rGpioDriverEnable) = 0;
rGpioDriverEnable.Enable10 = TRUE;
rGpioDriverEnable.Mask10 = TRUE;
WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable));
MKWORD(rGpioOutputData) = 0;
rGpioOutputData.Latch10 = 0;
rGpioOutputData.Mask10 = TRUE;
WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData));
PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n");
}
static irqreturn_t UartInterrupt(int irq, void *dev_id)
{
PRINTK_3(TRACE_TP3780I,
"tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
return IRQ_HANDLED;
}
static irqreturn_t DspInterrupt(int irq, void *dev_id)
{
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
unsigned short usIPCSource = 0, usIsolationMask, usPCNum;
PRINTK_3(TRACE_TP3780I,
"tp3780i::DspInterrupt entry irq %x dev_id %p\n", irq, dev_id);
if (dsp3780I_GetIPCSource(usDspBaseIO, &usIPCSource) == 0) {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, return from dsp3780i_GetIPCSource, usIPCSource %x\n",
usIPCSource);
usIsolationMask = 1;
for (usPCNum = 1; usPCNum <= 16; usPCNum++) {
if (usIPCSource & usIsolationMask) {
usIPCSource &= ~usIsolationMask;
PRINTK_3(TRACE_TP3780I,
"tp3780i::DspInterrupt usPCNum %x usIPCSource %x\n",
usPCNum, usIPCSource);
if (pDrvData->IPCs[usPCNum - 1].usIntCount == 0) {
pDrvData->IPCs[usPCNum - 1].usIntCount = 1;
}
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt usIntCount %x\n",
pDrvData->IPCs[usPCNum - 1].usIntCount);
if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == TRUE) {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, waking up usPCNum %x\n",
usPCNum - 1);
wake_up_interruptible(&pDrvData->IPCs[usPCNum - 1].ipc_wait_queue);
} else {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, no one waiting for IPC %x\n",
usPCNum - 1);
}
}
if (usIPCSource == 0)
break;
/* try next IPC */
usIsolationMask = usIsolationMask << 1;
}
} else {
PRINTK_1(TRACE_TP3780I,
"tp3780i::DspInterrupt, return false from dsp3780i_GetIPCSource\n");
}
PRINTK_1(TRACE_TP3780I, "tp3780i::DspInterrupt exit\n");
return IRQ_HANDLED;
}
int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData);
pBDData->bDSPEnabled = FALSE;
pSettings->bInterruptClaimed = FALSE;
retval = smapi_init();
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_InitializeBoardData: Error: SMAPI is not available on this machine\n");
} else {
if (mwave_3780i_irq || mwave_3780i_io || mwave_uart_irq || mwave_uart_io) {
retval = smapi_set_DSP_cfg();
}
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData exit retval %x\n", retval);
return retval;
}
int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_Cleanup entry and exit pBDData %p\n", pBDData);
return retval;
}
int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)
{
SMAPI_DSP_SETTINGS rSmapiInfo;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_CalcResources entry pBDData %p\n", pBDData);
if (smapi_query_DSP_cfg(&rSmapiInfo)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Could not query DSP config. Aborting.\n");
return -EIO;
}
/* Sanity check */
if (
( rSmapiInfo.usDspIRQ == 0 )
|| ( rSmapiInfo.usDspBaseIO == 0 )
|| ( rSmapiInfo.usUartIRQ == 0 )
|| ( rSmapiInfo.usUartBaseIO == 0 )
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Illegal resource setting. Aborting.\n");
return -EIO;
}
pSettings->bDSPEnabled = (rSmapiInfo.bDSPEnabled && rSmapiInfo.bDSPPresent);
pSettings->bModemEnabled = rSmapiInfo.bModemEnabled;
pSettings->usDspIrq = rSmapiInfo.usDspIRQ;
pSettings->usDspDma = rSmapiInfo.usDspDMA;
pSettings->usDspBaseIO = rSmapiInfo.usDspBaseIO;
pSettings->usUartIrq = rSmapiInfo.usUartIRQ;
pSettings->usUartBaseIO = rSmapiInfo.usUartBaseIO;
pSettings->uDStoreSize = TP_ABILITIES_DATA_SIZE;
pSettings->uIStoreSize = TP_ABILITIES_INST_SIZE;
pSettings->uIps = TP_ABILITIES_INTS_PER_SEC;
if (pSettings->bDSPEnabled && pSettings->bModemEnabled && pSettings->usDspIrq == pSettings->usUartIrq) {
pBDData->bShareDspIrq = pBDData->bShareUartIrq = 1;
} else {
pBDData->bShareDspIrq = pBDData->bShareUartIrq = 0;
}
PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_CalcResources exit\n");
return 0;
}
int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct resource *pres;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
if ( pres == NULL ) retval = -EIO;
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
retval = -EIO;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ClaimResources exit retval %x\n", retval);
return retval;
}
int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReleaseResources entry pBDData %p\n", pBDData);
release_region(pSettings->usDspBaseIO & (~3), 16);
if (pSettings->bInterruptClaimed) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
}
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReleaseResources exit retval %x\n", retval);
return retval;
}
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
if (pBDData->bDSPEnabled) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: DSP already enabled!\n");
goto exit_cleanup;
}
if (!pSettings->bDSPEnabled) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780::tp3780I_EnableDSP: Error: pSettings->bDSPEnabled not set\n");
goto exit_cleanup;
}
if (
(pSettings->usDspIrq >= s_numIrqs)
|| (pSettings->usDspDma >= s_numDmas)
|| (s_ausThinkpadIrqToField[pSettings->usDspIrq] == 0xFFFF)
|| (s_ausThinkpadDmaToField[pSettings->usDspDma] == 0xFFFF)
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: invalid irq %x\n", pSettings->usDspIrq);
goto exit_cleanup;
}
if (
((pSettings->usDspBaseIO & 0xF00F) != 0)
|| (pSettings->usDspBaseIO & 0x0FF0) == 0
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid DSP base I/O address %x\n", pSettings->usDspBaseIO);
goto exit_cleanup;
}
if (pSettings->bModemEnabled) {
if (
pSettings->usUartIrq >= s_numIrqs
|| s_ausThinkpadIrqToField[pSettings->usUartIrq] == 0xFFFF
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid UART IRQ %x\n", pSettings->usUartIrq);
goto exit_cleanup;
}
switch (pSettings->usUartBaseIO) {
case 0x03F8:
case 0x02F8:
case 0x03E8:
case 0x02E8:
break;
default:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Invalid UART base I/O address %x\n", pSettings->usUartBaseIO);
goto exit_cleanup;
}
}
pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = TRUE;
pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = TRUE;
if (pBDData->bShareDspIrq) {
pSettings->bDspIrqActiveLow = FALSE;
}
if (pBDData->bShareUartIrq) {
pSettings->bUartIrqActiveLow = FALSE;
}
pSettings->usNumTransfers = TP_CFG_NumTransfers;
pSettings->usReRequest = TP_CFG_RerequestTimer;
pSettings->bEnableMEMCS16 = TP_CFG_MEMCS16;
pSettings->usIsaMemCmdWidth = TP_CFG_IsaMemCmdWidth;
pSettings->bGateIOCHRDY = TP_CFG_GateIOCHRDY;
pSettings->bEnablePwrMgmt = TP_CFG_EnablePwrMgmt;
pSettings->usHBusTimerLoadValue = TP_CFG_HBusTimerValue;
pSettings->bDisableLBusTimeout = TP_CFG_DisableLBusTimeout;
pSettings->usN_Divisor = TP_CFG_N_Divisor;
pSettings->usM_Multiplier = TP_CFG_M_Multiplier;
pSettings->bPllBypass = TP_CFG_PllBypass;
pSettings->usChipletEnable = TP_CFG_ChipletEnable;
if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", NULL)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq);
goto exit_cleanup;
} else { /* no conflict just release */
free_irq(pSettings->usUartIrq, NULL);
}
if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", NULL)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Could not get 3780i IRQ %x\n", pSettings->usDspIrq);
goto exit_cleanup;
} else {
PRINTK_3(TRACE_TP3780I,
"tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n",
pSettings->usDspIrq, pBDData->bShareDspIrq);
bInterruptAllocated = TRUE;
pSettings->bInterruptClaimed = TRUE;
}
smapi_set_DSP_power_state(FALSE);
if (smapi_set_DSP_power_state(TRUE)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(TRUE) failed\n");
goto exit_cleanup;
} else {
bDSPPoweredUp = TRUE;
}
if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
goto exit_cleanup;
}
EnableSRAM(pBDData);
pBDData->bDSPEnabled = TRUE;
PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n");
return 0;
exit_cleanup:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
if (bDSPPoweredUp)
smapi_set_DSP_power_state(FALSE);
if (bInterruptAllocated) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
}
return -EIO;
}
int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP entry pBDData %p\n", pBDData);
if (pBDData->bDSPEnabled) {
dsp3780I_DisableDSP(&pBDData->rDspSettings);
if (pSettings->bInterruptClaimed) {
free_irq(pSettings->usDspIrq, NULL);
pSettings->bInterruptClaimed = FALSE;
}
smapi_set_DSP_power_state(FALSE);
pBDData->bDSPEnabled = FALSE;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval);
return retval;
}
int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP entry pBDData %p\n",
pBDData);
if (dsp3780I_Reset(pSettings) == 0) {
EnableSRAM(pBDData);
} else {
retval = -EIO;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP exit retval %x\n", retval);
return retval;
}
int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP entry pBDData %p\n", pBDData);
if (dsp3780I_Run(pSettings) == 0) {
// @BUG @TBD EnableSRAM(pBDData);
} else {
retval = -EIO;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP exit retval %x\n", retval);
return retval;
}
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities)
{
int retval = 0;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
memset(pAbilities, 0, sizeof(*pAbilities));
/* fill out standard constant fields */
pAbilities->instr_per_sec = pBDData->rDspSettings.uIps;
pAbilities->data_size = pBDData->rDspSettings.uDStoreSize;
pAbilities->inst_size = pBDData->rDspSettings.uIStoreSize;
pAbilities->bus_dma_bw = pBDData->rDspSettings.uDmaBandwidth;
/* fill out dynamically determined fields */
pAbilities->component_list[0] = 0x00010000 | MW_ADC_MASK;
pAbilities->component_list[1] = 0x00010000 | MW_ACI_MASK;
pAbilities->component_list[2] = 0x00010000 | MW_AIC1_MASK;
pAbilities->component_list[3] = 0x00010000 | MW_AIC2_MASK;
pAbilities->component_list[4] = 0x00010000 | MW_CDDAC_MASK;
pAbilities->component_list[5] = 0x00010000 | MW_MIDI_MASK;
pAbilities->component_list[6] = 0x00010000 | MW_UART_MASK;
pAbilities->component_count = 7;
/* Fill out Mwave OS and BIOS task names */
memcpy(pAbilities->mwave_os_name, TP_ABILITIES_MWAVEOS_NAME,
sizeof(TP_ABILITIES_MWAVEOS_NAME));
memcpy(pAbilities->bios_task_name, TP_ABILITIES_BIOSTASK_NAME,
sizeof(TP_ABILITIES_BIOSTASK_NAME));
PRINTK_1(TRACE_TP3780I,
"tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
return retval;
}
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
BOOLEAN bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
if (pBDData->bDSPEnabled) {
switch (uOpcode) {
case IOCTL_MW_READ_DATA:
bRC = dsp3780I_ReadDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
break;
case IOCTL_MW_READCLEAR_DATA:
bRC = dsp3780I_ReadAndClearDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
break;
case IOCTL_MW_WRITE_DATA:
bRC = dsp3780I_WriteDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
break;
}
}
retval = (bRC) ? -EIO : 0;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ReadWriteDspDStore exit retval %x\n", retval);
return retval;
}
int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
BOOLEAN bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
if (pBDData->bDSPEnabled) {
switch (uOpcode) {
case IOCTL_MW_READ_INST:
bRC = dsp3780I_ReadIStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
break;
case IOCTL_MW_WRITE_INST:
bRC = dsp3780I_WriteIStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
break;
}
}
retval = (bRC) ? -EIO : 0;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspIStore exit retval %x\n", retval);
return retval;
}

View file

@ -0,0 +1,103 @@
/*
*
* tp3780i.h -- declarations for tp3780i.c
*
*
* Written By: Mike Sullivan IBM Corporation
*
* Copyright (C) 1999 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* NO WARRANTY
* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
* solely responsible for determining the appropriateness of using and
* distributing the Program and assumes all risks associated with its
* exercise of rights under this Agreement, including but not limited to
* the risks and costs of program errors, damage to or loss of data,
* programs or equipment, and unavailability or interruption of operations.
*
* DISCLAIMER OF LIABILITY
* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* 10/23/2000 - Alpha Release
* First release to the public
*/
#ifndef _LINUX_TP3780I_H
#define _LINUX_TP3780I_H
#include <asm/io.h>
#include "mwavepub.h"
/* DSP abilities constants for 3780i based Thinkpads */
#define TP_ABILITIES_INTS_PER_SEC 39160800
#define TP_ABILITIES_DATA_SIZE 32768
#define TP_ABILITIES_INST_SIZE 32768
#define TP_ABILITIES_MWAVEOS_NAME "mwaveos0700.dsp"
#define TP_ABILITIES_BIOSTASK_NAME "mwbio701.dsp"
/* DSP configuration values for 3780i based Thinkpads */
#define TP_CFG_NumTransfers 3 /* 16 transfers */
#define TP_CFG_RerequestTimer 1 /* 2 usec */
#define TP_CFG_MEMCS16 0 /* Disabled, 16-bit memory assumed */
#define TP_CFG_IsaMemCmdWidth 3 /* 295 nsec (16-bit) */
#define TP_CFG_GateIOCHRDY 0 /* No IOCHRDY gating */
#define TP_CFG_EnablePwrMgmt 1 /* Enable low poser suspend/resume */
#define TP_CFG_HBusTimerValue 255 /* HBus timer load value */
#define TP_CFG_DisableLBusTimeout 0 /* Enable LBus timeout */
#define TP_CFG_N_Divisor 32 /* Clock = 39.1608 Mhz */
#define TP_CFG_M_Multiplier 37 /* " */
#define TP_CFG_PllBypass 0 /* don't bypass */
#define TP_CFG_ChipletEnable 0xFFFF /* Enable all chiplets */
typedef struct {
int bDSPEnabled;
int bShareDspIrq;
int bShareUartIrq;
DSP_3780I_CONFIG_SETTINGS rDspSettings;
} THINKPAD_BD_DATA;
int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData);
int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities);
int tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData);
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr);
int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr);
#endif