📄 pcan_sja1000.c
字号:
local.dwID >>= 21;
while (ucLen--)
{
m->Msg.DATA[j] = dev->readreg(dev, RECEIVE_FRAME_BASE + 3 + j);
j++;
}
}
m->Msg.ID = local.dwID;
if (rxfi & BUFFER_RTR)
m->Msg.MSGTYPE |= MSGTYPE_RTR;
// step forward in fifo
result = pcan_fifo_put(&dev->readFifo);
if (result)
goto fail;
}
else
{
// filtered out extended messages in non extended mode, reject claim
result = pcan_fifo_put_reject(&dev->readFifo);
if (result)
goto fail;
}
// release the receive buffer
dev->writereg(dev, COMMAND, RELEASE_RECEIVE_BUFFER);
wmb();
// give time to settle
udelay(1);
} while (dev->readreg(dev, CHIPSTATUS) & RECEIVE_BUFFER_STATUS && (i--));
fail:
return result ;
}
//----------------------------------------------------------------------------
// write CAN-data to chip,
int sja1000_write(struct pcandev *dev)
{
int result;
int j;
TPCANMsg *m;
u8 txfi;
ID local;
u8 ucLen;
DPRINTK(KERN_DEBUG "%s: sja1000_write() %d\n", DEVICE_NAME, dev->writeFifo.nStored);
// aquire a fifo element
result = pcan_fifo_claim_for_get(&dev->writeFifo, (void *)&m);
if (result)
goto fail;
txfi = ucLen = m->LEN;
j = 0;
local.dwID = m->ID;
if (m->MSGTYPE & MSGTYPE_EXTENDED)
{
local.dwID <<= 3;
#ifdef __LITTLE_ENDIAN
dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[3]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[2]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, local.ucID[1]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, local.ucID[0]);
#else
dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[0]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[1]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, local.ucID[2]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, local.ucID[3]);
#endif
while (ucLen--)
{
dev->writereg(dev, TRANSMIT_FRAME_BASE + 5 + j, m->DATA[j]);
j++;
}
txfi |= BUFFER_EFF;
}
else
{
local.dwID <<= 21;
#ifdef __LITTLE_ENDIAN
dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[3]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[2]);
#else
dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, local.ucID[0]);
dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, local.ucID[1]);
#endif
while (ucLen--)
{
dev->writereg(dev, TRANSMIT_FRAME_BASE + 3 + j, m->DATA[j]);
j++;
}
}
if (m->MSGTYPE & MSGTYPE_RTR)
txfi |= BUFFER_RTR;
// release fifo buffer and step forward in fifo
result = pcan_fifo_get(&dev->writeFifo);
if (result)
goto fail;
// finish message construction
dev->writereg(dev, TRANSMIT_FRAME_BASE, txfi);
// request a transmission
dev->writereg(dev, COMMAND, TRANSMISSION_REQUEST);
wmb();
fail:
return result;
}
//----------------------------------------------------------------------------
// handle a interrupt request
void sja1000_irqhandler(int irq, void *dev_id, struct pt_regs *regs)
{
register struct pcandev *dev = (struct pcandev *)dev_id;
u8 status;
int err;
u16 rwakeup = 0;
u16 wwakeup = 0;
int j = MAX_INTERRUPTS_PER_ENTRY;
while ((j--) && (status = dev->readreg(dev, INTERRUPT_STATUS)))
{
// DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(0x%02x)\n", DEVICE_NAME, status);
dev->dwInterruptCounter++;
if (status & TRANSMIT_INTERRUPT)
{
// handle transmission
if ((err = sja1000_write(dev)))
{
if (err == -ENODATA)
wwakeup++;
else
{
dev->nLastError = err;
dev->dwErrorCounter++;
dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error!
}
}
}
if (status & DATA_OVERRUN_INTERRUPT)
{
// handle data overrun
dev->wCANStatus |= CAN_ERR_QOVERRUN;
rwakeup++;
dev->dwErrorCounter++;
dev->writereg(dev, COMMAND, CLEAR_DATA_OVERRUN);
wmb();
}
if (status & RECEIVE_INTERRUPT)
{
// handle receiption
if ((err = sja1000_read(dev)))
{
dev->nLastError = err;
dev->dwErrorCounter++;
dev->wCANStatus |= CAN_ERR_QOVERRUN;
// throw away last message which was refused by fifo
dev->writereg(dev, COMMAND, RELEASE_RECEIVE_BUFFER);
wmb();
}
rwakeup++;
}
if (status & (BUS_ERROR_INTERRUPT | ERROR_PASSIV_INTERRUPT))
{
if (status & ERROR_PASSIV_INTERRUPT)
{
dev->wCANStatus |= CAN_ERR_BUSHEAVY;
dev->dwErrorCounter++;
}
// don't restart sja1000 after Bus Off
if (status & BUS_ERROR_INTERRUPT)
{
dev->wCANStatus |= CAN_ERR_BUSOFF;
dev->dwErrorCounter++;
}
}
}
if (wwakeup)
{
atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready
wake_up_interruptible(&dev->write_queue);
}
if (rwakeup)
wake_up_interruptible(&dev->read_queue);
}
//----------------------------------------------------------------------------
// probe for a sja1000 - use it only in reset mode!
int sja1000_probe(struct pcandev *dev)
{
u8 tmp;
u8 clkdivider;
DPRINTK(KERN_DEBUG "%s: sja1000_probe()\n", DEVICE_NAME);
// clkdivider is depended of of type
switch (dev->wType)
{
case HW_PCI:
clkdivider = (dev->port.pci.ucMasterDevice == CHANNEL_MASTER) ? PELICAN_MASTER : PELICAN_SINGLE;
break;
default:
clkdivider = PELICAN_DEFAULT;
// make a hardware reset
dev->writereg(dev, CLKDIVIDER, CHIP_RESET);
break;
}
// trace the clockdivider register to test for sja1000 / 82c200
tmp = dev->readreg(dev, CLKDIVIDER);
DPRINTK(KERN_DEBUG "%s: CLKDIVIDER traced (0x%02x)\n", DEVICE_NAME, tmp);
if (tmp & 0x10)
goto fail;
// until here, it's either a 82c200 or a sja1000
if (set_reset_mode(dev))
goto fail;
dev->writereg(dev, CLKDIVIDER, clkdivider); // switch to PeliCAN mode
dev->writereg(dev, INTERRUPT_ENABLE, 0); // prospective clear all interrupts
wmb();
DPRINTK(KERN_DEBUG "%s: Hopefully switched to PeliCAN mode\n", DEVICE_NAME);
tmp = dev->readreg(dev, CHIPSTATUS);
DPRINTK(KERN_DEBUG "%s: CHIPSTATUS traced (0x%02x)\n", DEVICE_NAME, tmp);
if ((tmp & 0x30) != 0x30)
goto fail;
tmp = dev->readreg(dev, INTERRUPT_STATUS);
DPRINTK(KERN_DEBUG "%s: INTERRUPT_STATUS traced (0x%02x)\n", DEVICE_NAME, tmp);
if (tmp & 0xfb)
goto fail;
tmp = dev->readreg(dev, RECEIVE_MSG_COUNTER);
DPRINTK(KERN_DEBUG "%s: RECEIVE_MSG_COUNTER traced (0x%02x)\n", DEVICE_NAME, tmp);
if (tmp)
goto fail;
DPRINTK(KERN_DEBUG "%s: sja1000_probe() is OK\n", DEVICE_NAME);
return 0;
fail:
DPRINTK(KERN_DEBUG "%s: sja1000_probe() failed\n", DEVICE_NAME);
return -ENXIO; // no such device or address
}
//----------------------------------------------------------------------------
// calculate BTR0BTR1 for odd bitrates
//
// most parts of this code is from Arnaud Westenberg email:arnaud@wanadoo.nl
// www.home.wanadoo.nl/arnaud
//
// Set communication parameters.
// param rate baud rate in Hz
// param clock frequency of sja1000 clock in Hz
// param sjw synchronization jump width (0-3) prescaled clock cycles
// param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio
// param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP
//
static int sja1000_baud_rate(int rate, int flags)
{
int best_error = 1000000000;
int error;
int best_tseg=0, best_brp=0, best_rate=0, brp=0;
int tseg=0, tseg1=0, tseg2=0;
int clock = CLOCK_HZ / 2;
u16 wBTR0BTR1;
int sjw = 0;
int sampl_pt = 90;
// some heuristic specials
if (rate > ((1000000 + 500000) / 2))
sampl_pt = 75;
if (rate < ((12500 + 10000) / 2))
sampl_pt = 75;
if (rate < ((100000 + 125000) / 2))
sjw = 1;
// tseg even = round down, odd = round up
for (tseg = (0 + 0 + 2) * 2; tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1; tseg++)
{
brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
if ((brp == 0) || (brp > 64))
continue;
error = rate - clock / (brp * (1 + tseg / 2));
if (error < 0)
error = -error;
if (error <= best_error)
{
best_error = error;
best_tseg = tseg/2;
best_brp = brp-1;
best_rate = clock/(brp*(1+tseg/2));
}
}
if (best_error && (rate / best_error < 10))
{
DPRINTK(KERN_ERR "%s: bitrate %d is not possible with %d Hz clock\n", DEVICE_NAME, rate, 2 * clock);
return 0;
}
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
if (tseg2 < 0)
tseg2 = 0;
if (tseg2 > MAX_TSEG2)
tseg2 = MAX_TSEG2;
tseg1 = best_tseg - tseg2 - 2;
if (tseg1 > MAX_TSEG1)
{
tseg1 = MAX_TSEG1;
tseg2 = best_tseg-tseg1-2;
}
wBTR0BTR1 = ((sjw<<6 | best_brp) << 8) | (((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1);
return wBTR0BTR1;
}
//----------------------------------------------------------------------------
// get BTR0BTR1 init values
u16 sja1000_bitrate(u32 dwBitRate)
{
u16 wBTR0BTR1 = 0;;
// get default const values
switch (dwBitRate)
{
case 1000000: wBTR0BTR1 = CAN_BAUD_1M; break;
case 500000: wBTR0BTR1 = CAN_BAUD_500K; break;
case 250000: wBTR0BTR1 = CAN_BAUD_250K; break;
case 125000: wBTR0BTR1 = CAN_BAUD_125K; break;
case 100000: wBTR0BTR1 = CAN_BAUD_100K; break;
case 50000: wBTR0BTR1 = CAN_BAUD_50K; break;
case 20000: wBTR0BTR1 = CAN_BAUD_20K; break;
case 10000: wBTR0BTR1 = CAN_BAUD_10K; break;
case 5000: wBTR0BTR1 = CAN_BAUD_5K; break;
case 0: wBTR0BTR1 = 0; break;
default:
// calculate for exotic values
wBTR0BTR1 = sja1000_baud_rate(dwBitRate, 0);
}
DPRINTK(KERN_DEBUG "%s: sja1000_bitrate(%d) = 0x%04x\n", DEVICE_NAME, dwBitRate, wBTR0BTR1);
return wBTR0BTR1;
}
// end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -