📄 dsk5402_mcbsp_ad50.c
字号:
/*
* Copyright 2003 by Texas Instruments Incorporated.
* All rights reserved. Property of Texas Instruments Incorporated.
* Restricted rights to use, duplicate or disclose this code are
* granted through contract.
*
*/
/* "@(#) DDK 1.10.00.23 07-02-03 (ddk-b12)" */
/*
* ======== dsk5402_mcbsp_ad50.c ========
*
* MCBSP sample-by-sample device driver for TI.
* 5402 DSK. Uses the C54x Chip Support Library.
*/
#include <std.h>
#include <atm.h>
#include <hwi.h>
#include <que.h>
#include <csl.h>
#include <csl_mcbsp.h>
#include <csl_irq.h>
#include <iom.h>
#include <dsk5402_mcbsp_ad50.h>
#include <ad50.h>
typedef struct ChanObj {
Bool inuse; /* TRUE => channel has been opened */
Int mode; /* IOM_INPUT or IOM_OUTPUT */
IOM_Packet *dataPacket; /* current active I/O packet */
QUE_Obj pendList; /* list of packets for I/O */
Uns *bufptr; /* pointer *within* current buffer */
Uns bufcnt; /* remaining samples to be handled */
IOM_TiomCallback cbFxn; /* used to notify client when I/O complete */
Ptr cbArg;
} ChanObj, *ChanHandle;
#define INPUT 0 /* Used as index since IOM mode is a bit mask, not index */
#define OUTPUT 1
#define NUMCHANS 2 /* INPUT and OUTPUT */
static ChanObj chans[NUMCHANS] = {
{ FALSE, INPUT, NULL, { NULL, NULL }, NULL, 0, NULL, NULL },
{ FALSE, OUTPUT, NULL, { NULL, NULL }, NULL, 0, NULL, NULL }
};
static MCBSP_Handle hMcbsp;
/*
* Forward declaration of IOM interface functions.
*/
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
static Int mdDeleteChan(Ptr chanp);
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
/*
* Public IOM interface table.
*/
IOM_Fxns DSK5402_MCBSP_AD50_FXNS = {
mdBindDev,
IOM_UNBINDDEVNOTIMPL,
mdControlChan,
mdCreateChan,
mdDeleteChan,
mdSubmitChan
};
/*
* Public driver setup data object. Used if the user passes NULL as
* setup() argument, or by the user to modify the default parameters.
*/
DSK5402_MCBSP_AD50_DevParams DSK5402_MCBSP_AD50_DEVPARAMS = {
AD50_DEFAULTPARAMS, /* default codec parameters */
};
/*
* local ISR functions.
* rxIsr() and txIsr() are plugged using HWI_dispatchPlug() in mdBindDev().
*/
static Void rxIsr(void);
static Void txIsr(void);
static Void updateChan(ChanHandle chan);
static Void abortio(ChanHandle chan);
/*
* ======== mdBindDev ========
* This function is called by DSP/BIOS during device initialization.
* It is called after DSK5402_MCBSP_AD50_init().
*
*/
#pragma CODE_SECTION(mdBindDev, ".text:init")
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
DSK5402_MCBSP_AD50_DevParams *params =
(DSK5402_MCBSP_AD50_DevParams *)devParams;
static Bool curinit = FALSE;
/* CSL handle to the McBSP. The McBSP is shared between the two channels */
static MCBSP_Config mcbspCfg0 = {
0x0021, /* Serial Port Control Register 1 */
0x0201, /* Serial Port Control Register 2 */
0x0040, /* Receive Control Register 1 */
0x0000, /* Receive Control Register 2 */
0x0040, /* Transmit Control Register 1 */
0x0000, /* Transmit Control Register 2 */
0x0000, /* Sample Rate Generator Register 1 */
0x0000, /* Sample Rate Generator Register 2 */
0x0000, /* Multichannel Control Register 1 */
0x0000, /* Multichannel Control Register 2 */
0x000c, /* Pin Control Register */
0x0000, /* Receive Channel Enable Register Partition A */
0x0000, /* Receive Channel Enable Register Partition B */
0x0000, /* Transmit Channel Enable Register Partition A */
0x0000 /* Transmit Channel Enable Register Partition B */
};
static volatile ioport unsigned port04; /* for CPLD CTRL 2 */
if (curinit) {
return (IOM_EBADIO);
}
curinit = TRUE;
/* use default parameters if none are given */
if (params == NULL) {
params = &DSK5402_MCBSP_AD50_DEVPARAMS;
}
/* open the McBSP */
hMcbsp = MCBSP_open(MCBSP_PORT1, MCBSP_OPEN_RESET);
MCBSP_config(hMcbsp, &mcbspCfg0);
/*
* DSK5402 board setup ...
* Select McBSP1 mapped to Audio Codec (CPLD Register)
* and FC bit = 0 (secondary control off)
*/
port04 &= 0xf5;
/* start the McBSP */
MCBSP_start(hMcbsp, MCBSP_XMIT_START | MCBSP_RCV_START, 0x0);
/* set codec parameters (this will also initialize the codec) */
AD50_setParams(hMcbsp, &(params->ad50) );
/* bind Rx/Tx interrupts and use DSP/BIOS HWI dispatcher */
HWI_dispatchPlug(IRQ_EVT_RINT1, (Fxn)rxIsr, NULL);
HWI_dispatchPlug(IRQ_EVT_XINT1, (Fxn)txIsr, NULL);
*devp = chans;
return (IOM_COMPLETED);
}
/*
* ======== mdControlChan ========
*/
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
{
/*
* If a channel timeouts(in IOM class driver) a calldown is made to mdControlChan w/
* cmd = IOM_CHAN_TIMED out. Timeout processing is optionally implemented here.
* If not performed return status of IOM_ENOTIMPL.
*/
if (cmd == IOM_CHAN_TIMEDOUT) {
/*
* Channel timed out. Perform needed channel cleanup.
*/
abortio(chanp);
}
else {
return (IOM_ENOTIMPL); /* return IOM_ENOTIMPL for codes not handled */
}
return (IOM_COMPLETED);
}
/*
* ======== mdCreateChan ========
*/
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
ChanHandle chans = (ChanHandle)devp;
ChanHandle chan;
if (mode == IOM_INPUT) {
chan = &chans[INPUT]; /* input only channel */
}
else if (mode == IOM_OUTPUT) {
chan = &chans[OUTPUT]; /* output only channel */
}
else {
return (IOM_EBADMODE); /* bi-directional channels not supported */
}
/*
* Check check if channel is already in use.
* Use ATM_setu() for atomic test-and-set.
*/
if (ATM_setu((Uns *)&chan->inuse, TRUE)) {
return (IOM_EBADIO); /* ERROR! channel is already open! */
}
QUE_new(&chan->pendList);
chan->dataPacket = NULL;
/* no need to initialize chan->bufptr */
chan->cbFxn = cbFxn;
chan->cbArg = cbArg;
if (chan->mode == INPUT) {
IRQ_enable(IRQ_EVT_RINT1); /* Rx Intr enable */
}
else {
IRQ_enable(IRQ_EVT_XINT1); /* Tx intr enable */
}
*chanp = chan; /* return channel handle */
return (IOM_COMPLETED); /* success */
}
/*
* ======== mdDeleteChan ========
* Mark the channel available and disable the appropriate interrupt.
*/
static Int mdDeleteChan(Ptr chanp)
{
ChanHandle chan = (ChanHandle)chanp;
chan->inuse = FALSE;
if (chan->mode == INPUT) {
IRQ_disable(IRQ_EVT_RINT1);
}
else {
IRQ_disable(IRQ_EVT_XINT1);
}
return (IOM_COMPLETED);
}
/*
* ======== mdSubmitChan ========
* Sets the buf variables in the channel object. ISR will then
* emtpy or fill this buffer.
*/
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet)
{
ChanHandle chan = (ChanHandle)chanp;
Uns imask;
/*
* First check if command is to abort or flush this channel.
* Note: For this audio codec we are going to toss the output data even
* when flushing.
*/
if (packet->cmd == IOM_FLUSH || packet->cmd == IOM_ABORT) {
abortio(chan);
packet->status = IOM_COMPLETED; /* flush/abort pkt completed */
return (IOM_COMPLETED);
}
imask = HWI_disable();
if (chan->dataPacket == NULL) {
chan->bufptr = (Uns *)packet->addr;
chan->bufcnt = packet->size;
/* 'dataPacket' must be set last to synchronize with ISR */
chan->dataPacket = packet;
}
else {
QUE_put(&chan->pendList, packet);
}
HWI_restore(imask);
return (IOM_PENDING);
}
/*
* ======== DSK5402_MCBSP_AD50_init ========
*/
#pragma CODE_SECTION(DSK5402_MCBSP_AD50_init, ".text:init")
Void DSK5402_MCBSP_AD50_init(Void)
{
}
/*
* ======== rxIsr ========
* Handle receive (input) interrupt.
*
* Copies a new sample from McBSP to buffer. If buffer is full, then call
* the registered callback function with the registered argument and the
* size of the buffer.
*/
static Void rxIsr(Void)
{
ChanHandle chan = &chans[INPUT];
if (chan->dataPacket == NULL) {
MCBSP_read(hMcbsp); /* toss data */
return;
}
*chan->bufptr = MCBSP_read(hMcbsp);
updateChan(chan);
}
/*
* ======== txIsr ========
* Handle transmit (output) interrupt.
*
* Copies a new sample from the buffer to MCBSP. If buffer is empty, then
* call the registered callback function with the registered argument and
* the size of the buffer.
*/
static Void txIsr(Void)
{
ChanHandle chan = &chans[OUTPUT];
if (chan->dataPacket == NULL) {
MCBSP_write(hMcbsp, 0); /* output dummy sample */
return;
}
MCBSP_write(hMcbsp, *chan->bufptr & 0xfffe);
updateChan(chan);
}
/*
* ======== updateChan ========
* updateChan() is called at ISR context with appropriate ISR disabled.
* updateChan() is used by the rx and tx ISRs to update the channel
* structures after input or output sample has been handled.
*/
static Void updateChan(ChanHandle chan)
{
IOM_Packet *tmpPacket;
chan->bufptr++;
chan->bufcnt--;
/* Is this buffer finished? */
if (chan->bufcnt == 0) {
chan->dataPacket->status = IOM_COMPLETED;
tmpPacket = chan->dataPacket;
chan->dataPacket = QUE_get(&chan->pendList);
if (chan->dataPacket == (IOM_Packet *)&chan->pendList) {
chan->dataPacket = NULL;
}
else {
chan->bufptr = chan->dataPacket->addr;
chan->bufcnt = chan->dataPacket->size;
}
(*chan->cbFxn)(chan->cbArg, tmpPacket);
}
}
/*
* ======== abortio ========
* Aborts uncompleted i/o packet requests.
*/
static Void abortio(ChanHandle chan)
{
IOM_Packet *tmpPacket;
HWI_disable();
tmpPacket = chan->dataPacket;
chan->dataPacket = NULL;
HWI_enable();
if (tmpPacket) {
tmpPacket->status = IOM_ABORTED; /* abort current request */
(*chan->cbFxn)(chan->cbArg, tmpPacket);
tmpPacket = QUE_get(&chan->pendList);
while (tmpPacket != (IOM_Packet *)&chan->pendList) {
tmpPacket->status = IOM_ABORTED; /* abort queued requests */
(*chan->cbFxn)(chan->cbArg, tmpPacket);
tmpPacket = QUE_get(&chan->pendList);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -