#define RESET_CMD 0xc0
#define READ_CMD 0x03
#define WRITE_CMD 0x02
+#define READ_RX0_CMD 0x90
+#define READ_RX1_CMD 0x94
#define BITMOD_CMD 0x05
+#define MCP2515_SPI_ASYNC
+
+enum MCP2515_OPS {
+ NOOP,
+ READ_RX0,
+ READ_RX1,
+ READ_CANINTF,
+ READ_ERR
+};
+
+static struct workqueue_struct *mcp2515_wq;
+
+static void mcp2515_async_callback(void *data, uint8_t count);
+static void tx_handler(struct canchip_t *chip, struct msgobj_t *obj);
/*****************************************************************************/
/* SPI ACCESS FUNCTIONS */
}
+/*****************************************************************************/
+static void bitmod_reg_async(struct canchip_t *chip, unsigned addr,
+ unsigned char mask, unsigned char data, uint8_t opcode)
+{
+ struct can_spi_async_t async;
+
+ async.chip = chip;
+ async.opcode = opcode;
+ async.tx_buf[0] = BITMOD_CMD;
+ async.tx_buf[1] = addr;
+ async.tx_buf[2] = mask;
+ async.tx_buf[3] = data;
+ async.len = 4;
+ can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+
+#if DEBUG
+ DEBUGMSG("reg[0x%02x]<=0x%02x mask=0x%02x\n",addr,(unsigned)data,(unsigned)mask);
+#endif
+}
+
+/*****************************************************************************/
+static void read_async(struct canchip_t *chip, unsigned startAddr, size_t len, uint8_t opcode)
+{
+ struct can_spi_async_t async[2];
+
+ async[0].chip = chip;
+ async[0].opcode = opcode;
+ async[0].tx_buf[0] = READ_CMD;
+ async[0].tx_buf[1] = startAddr;
+ async[0].len = len+2;
+
+ if (opcode == READ_CANINTF){
+ async[1].chip = chip;
+ async[1].opcode = opcode;
+ async[1].tx_buf[0] = READ_CMD;
+ async[1].tx_buf[1] = startAddr;
+ async[1].len = len+2;
+ can_spi_async_transfer(chip, mcp2515_async_callback, async, 2, 1);
+ }
+ else
+ can_spi_async_transfer(chip, mcp2515_async_callback, async, 1, 0);
+}
+
+/*****************************************************************************/
+inline void read_rx_async(struct canchip_t *chip, unsigned rxbuf,struct msgobj_t *obj)
+{
+ struct can_spi_async_t async = {
+ .chip = chip,
+ .opcode = rxbuf?READ_RX1:READ_RX0,
+ .tx_buf[0] = rxbuf?READ_RX1_CMD:READ_RX0_CMD,
+ .len = sizeof(MCP2515_FRAME)+1,
+ .obj = obj,
+ };
+
+ can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+}
+
+/*****************************************************************************/
+inline void read_err_async(struct canchip_t *chip)
+{
+ struct can_spi_async_t async;
+
+ async.chip = chip;
+ async.opcode = READ_ERR;
+ async.tx_buf[0] = READ_CMD;
+ async.tx_buf[1] = MCP2515_EFLG;
+ async.len = 3;
+
+ can_spi_async_transfer(chip, mcp2515_async_callback, &async, 1, 0);
+}
+
+/*****************************************************************************/
+static void txwq_handler(struct work_struct *work)
+{
+ MCP2515_PRIV *priv = container_of(work,MCP2515_PRIV,txwq_handler);
+ struct canchip_t *chip = priv->chip;
+ int n;
+ if (chip == NULL)
+ return;
+ n = find_first_bit(priv->txfree, MCP2515_TXBUF_NUM);
+ while (n<MCP2515_TXBUF_NUM){
+ clear_bit(n,priv->txfree);
+ tx_handler(chip,chip->msgobj[n]);
+ n = find_first_bit(priv->txfree, MCP2515_TXBUF_NUM);
+ }
+}
+
+
+static int mcp2515_async_canintf_reread = 0;
+/*****************************************************************************/
+static void mcp2515_async_callback(void *data,uint8_t count){
+ struct can_spi_async_t *async = (struct can_spi_async_t *)data;
+ struct canchip_t *chip;
+ struct msgobj_t *obj;
+ int i;
+ if (async == NULL)
+ return;
+
+ for (i=0;i<count;i++){
+ switch (async[i].opcode){
+ case NOOP : break;
+ case READ_RX0 :
+ case READ_RX1 : {
+ uint8_t len;
+ MCP2515_FRAME *frame = NULL;
+
+ chip = async[i].chip;
+ if (chip == NULL) return;
+ obj = async[i].obj;
+ if (obj == NULL) return;
+
+ if (async[i].rx_buf == NULL)
+ panic("async[%d].rx_buf is null",i);
+ frame = (MCP2515_FRAME *)(async[i].rx_buf+1); //The received data is 1 byte late
+
+ if(frame->sidl & mcpIDE) {
+ DEBUGMSG("extended frame\n");
+ obj->rx_msg.id =
+ ((uint32_t)frame->eid0) |
+ ((uint32_t)frame->eid8) << 8 |
+ ((uint32_t)frame->sidl & 0x03) << 16 |
+ ((uint32_t)frame->sidl & 0xe0) << 13 |
+ ((uint32_t)frame->sidh) << 21;
+ obj->rx_msg.flags = MSG_EXT | ((frame->dlc & mcpRTR) ? MSG_RTR : 0);
+ }
+ else {
+ DEBUGMSG("standard frame\n");
+ obj->rx_msg.id =
+ ((uint32_t)frame->sidl) >> 5 |
+ ((uint32_t)frame->sidh) << 3;
+ obj->rx_msg.flags = ((frame->sidl & mcpSRR) ? MSG_RTR : 0);
+ }
+
+ len = frame->dlc & mcpDLC_MASK;
+ if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
+ obj->rx_msg.length = len;
+
+ memcpy(obj->rx_msg.data,frame->data,len);
+
+ /* fill CAN message timestamp */
+// can_filltimestamp(&obj->rx_msg.timestamp);
+ memcpy(&obj->rx_msg.timestamp, &async->timestamp, sizeof(canmsg_tstamp_t));
+ canque_filter_msg2edges(obj->qends, &obj->rx_msg);
+ break;
+ }
+ case READ_CANINTF : {
+ uint8_t flags = async[i].rx_buf[2];
+ MCP2515_PRIV *priv;
+
+ chip = async[i].chip;
+ if (chip == NULL) break;
+ priv=(MCP2515_PRIV *)(chip->chip_data);
+ if (priv == NULL) break;
+
+ if ((count > i+1) && (async[i+1].opcode == READ_CANINTF) && (async[++i].rx_buf[2] ^ flags)){
+ DEBUGMSG("Found differences in two consequent interrupt flag readings. Reading again...\n");
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+ break;
+ }
+
+ if((flags == 0) && (mcp2515_async_canintf_reread)){
+ mcp2515_async_canintf_reread = 0;
+ enable_irq(chip->chip_irq);
+ break;
+ }
+ else if((flags == 0)){
+ mcp2515_async_canintf_reread++;
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+ break;
+ }
+ mcp2515_async_canintf_reread = 0;
+
+ DEBUGMSG("mcp251x_irq_work_handler:%s%s%s%s%s%s%s%s\n",
+ (flags & mcpRX0INT) ? " RX0":"",
+ (flags & mcpRX1INT) ? " RX1":"",
+ (flags & mcpTX0INT) ? " TX0":"",
+ (flags & mcpTX1INT) ? " TX1":"",
+ (flags & mcpTX2INT) ? " TX2":"",
+ (flags & mcpERRINT) ? " ERR":"",
+ (flags & mcpWAKINT) ? " WAK":"",
+ (flags & mcpMERREINT) ? " MERRE":"");
+
+
+ if(flags & mcpRX0INT) read_rx_async(chip,0,chip->msgobj[0]);
+ if(flags & mcpRX1INT) read_rx_async(chip,1,chip->msgobj[0]);
+ if(flags & mcpTX0INT) {
+ set_bit(0,priv->txfree);
+ queue_work(mcp2515_wq,&priv->txwq_handler);
+ }
+ if(flags & mcpTX1INT) {
+ set_bit(1,priv->txfree);
+ queue_work(mcp2515_wq,&priv->txwq_handler);
+ }
+ if(flags & mcpTX2INT) {
+ set_bit(2,priv->txfree);
+ queue_work(mcp2515_wq,&priv->txwq_handler);
+ }
+
+ if(flags & mcpERRINT) read_err_async(chip);
+ if(flags & mcpMERREINT) (priv->errcnt.merre)++;
+ if(flags & mcpWAKINT) (priv->wakeint_cnt)++;
+
+ bitmod_reg_async(chip, MCP2515_CANINTF, flags & ~(mcpRX0INT|mcpRX1INT), 0, NOOP);
+
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+ break;
+ }
+ case READ_ERR : {
+ uint8_t error = async[i].rx_buf[2];
+ MCP2515_PRIV *priv;
+
+ chip = async[i].chip;
+ if (chip == NULL) break;
+ priv=(MCP2515_PRIV *)(chip->chip_data);
+ if (priv == NULL) break;
+
+ if(error & mcpRX0OVR) {
+ (priv->errcnt.rx0ovr)++;
+ CANMSG("can: RX0OVR\n");
+ }
+ if(error & mcpRX1OVR) (priv->errcnt.rx1ovr)++;
+ if(error & mcpTXBO) (priv->errcnt.txbo)++;
+ if(error & mcpTXEP) (priv->errcnt.txep)++;
+ if(error & mcpRXEP) (priv->errcnt.rxep)++;
+ if(error & mcpTXWAR) (priv->errcnt.txwar)++;
+ if(error & mcpRXWAR) (priv->errcnt.rxwar)++;
+ if(error & mcpEWARN) (priv->errcnt.ewarn)++;
+
+ break;
+ }
+ default : CANMSG("OMAP2_SPICAN got unknown asynchronous response");
+ }
+ }
+}
+
/*****************************************************************************/
/* PROC INTERFACE */
/*****************************************************************************/
if(chip == NULL) panic("rx_handler: chip==NULL");
if(obj == NULL) panic("rx_handler: obj==NULL");
-
/* get all frame data */
if(bufNo == 0){
read_block(chip,MCP2515_RXB0SIDH,sizeof(MCP2515_FRAME),&frame);
if(frame.sidl & mcpIDE) {
DEBUGMSG("extended frame\n");
obj->rx_msg.id =
- ((uint32_t)frame.eid0) |
- ((uint32_t)frame.eid8) << 8 |
- ((uint32_t)frame.sidl & 0x03) << 16 |
- ((uint32_t)frame.sidl & 0xe0) << 13 |
- ((uint32_t)frame.sidh) << 21;
+ ((uint32_t)frame.sidl & 0xe0) >> 5 |
+ ((uint32_t)frame.sidh) << 3 |
+ ((uint32_t)frame.eid0) << 11 |
+ ((uint32_t)frame.eid8) << 19 |
+ ((uint32_t)frame.sidl & 0x03) << 27;
obj->rx_msg.flags = MSG_EXT | ((frame.dlc & mcpRTR) ? MSG_RTR : 0);
}
else {
DEBUGMSG("standard frame\n");
obj->rx_msg.id =
- ((uint32_t)frame.sidl) >> 5 |
- ((uint32_t)frame.sidh) << 3;
+ ((uint32_t)frame.sidl & 0xe0) >> 5 |
+ ((uint32_t)frame.sidh) << 3;
obj->rx_msg.flags = ((frame.sidl & mcpSRR) ? MSG_RTR : 0);
}
int cmd;
if(chip == NULL) panic("tx_handler: chip==NULL");
- if(obj == NULL) panic("tx_handler: obj==NULL");
-
+ if(obj == NULL) panic("tx_handler: obj==NULL");
+#ifndef MCP2515_SPI_ASYNC
bitmod_reg(chip,MCP2515_CANINTF, mcpTX0INT, ~mcpTX0INT);
-
+#endif
if(obj->tx_slot) {
/* Do local transmitted message distribution if enabled */
priv=(MCP2515_PRIV *)(chip->chip_data);
if (priv == NULL)
return;
+
+#ifdef MCP2515_SPI_ASYNC
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
while(1) {
flags = read_reg(chip, MCP2515_CANINTF);
// bitmod_reg(chip, MCP2515_CANINTF, flags, 0);
}
-
enable_irq(chip->chip_irq);
+#endif /* MCP2515_SPI_ASYNC */
}
/*****************************************************************************/
write_block(chip,MCP2515_TXB0DATA,8,pat0);
for (i=0;i<10;i++){
read_block(chip,MCP2515_TXB0DATA,8,pat1);
-// *(pat1) = read_reg(chip,MCP2515_TXB0DATA);
-// *(pat1+1) = read_reg(chip,MCP2515_TXB0DATA+1);
-// *(pat1+2) = read_reg(chip,MCP2515_TXB0DATA+2);
-// *(pat1+3) = read_reg(chip,MCP2515_TXB0DATA+3);
-// *(pat1+4) = read_reg(chip,MCP2515_TXB0DATA+4);
-// *(pat1+5) = read_reg(chip,MCP2515_TXB0DATA+5);
-// *(pat1+6) = read_reg(chip,MCP2515_TXB0DATA+6);
-// *(pat1+7) = read_reg(chip,MCP2515_TXB0DATA+7);
if(memcmp(pat0,pat1,8)) {
CANMSG("mcp2515_chip_config: chip #%d not found\n",
chip->chip_idx);
CANMSG("Requested: Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X\n",pat0[0],pat0[1],pat0[2],pat0[3],pat0[4],pat0[5],pat0[6],pat0[7]);
CANMSG("Obtained : Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X Ox%X\n",pat1[0],pat1[1],pat1[2],pat1[3],pat1[4],pat1[5],pat1[6],pat1[7]);
-// return -ENODEV;
}
else
break;
CANMSG("Found mcp2515:%d\n",chip->chip_idx);
- if (mcp2515_extended_mask(chip,0x00000000, 0xffffffff))
+ // Accept only most the dominant message
+ if (mcp2515_extended_mask(chip,0xffffffff, 0xffffffff))
return -ENODEV;
+/* // Accept only most the dominant message
+ if (mcp2515_extended_mask(chip,0xffffffff, 0x00000000))
+ return -ENODEV;*/
if (!chip->baudrate) chip->baudrate=1000000;
if (mcp2515_baud_rate(chip,chip->baudrate,chip->clock,0,75,0))
*/
int mcp2515_extended_mask(struct canchip_t *chip, unsigned long code, unsigned long mask)
{
+ char c_filter[4],c_mask[4];
DEBUGMSG("mcp2515_extended_mask\n");
-#if 0
+// #if 0
if (mcp2515_enable_configuration(chip))
return -ENODEV;
-// LSB to +3, MSB to +0
- for(i=SJA_PeliCAN_AC_LEN; --i>=0;) {
- can_write_reg(chip,code&0xff,SJAACR0+i);
- can_write_reg(chip,mask&0xff,SJAAMR0+i);
- code >>= 8;
- mask >>= 8;
- }
-
- DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
- DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+ c_filter[0] = (code >> 3) & 0xFF;
+ c_filter[1] = ((code << 5) & 0xE0 ) | 1<<3 | ((code >> 16) & 0x03);
+ c_filter[2] = (code >> 8) & 0xFF;
+ c_filter[3] = (code) & 0xFF;
+ write_block(chip, MCP2515_RXF0SIDH, 4, c_filter);
+ write_block(chip, MCP2515_RXF2SIDH, 4, c_filter);
+ write_block(chip, MCP2515_RXF3SIDH, 4, c_filter);
+ write_block(chip, MCP2515_RXF4SIDH, 4, c_filter);
+ write_block(chip, MCP2515_RXF5SIDH, 4, c_filter);
+ c_filter[1] = ((code << 5) & 0xE0 ) | 0<<3 | ((code >> 16) & 0x03);
+ write_block(chip, MCP2515_RXF1SIDH, 4, c_filter);
+ c_mask[0] = (mask >> 3) & 0xFF;
+ c_mask[1] = ((mask << 5) & 0xE0 ) | ((mask >> 16) & 0x03);
+ c_mask[2] = (mask >> 8) & 0xFF;
+ c_mask[3] = (mask) & 0xFF;
+ write_block(chip, MCP2515_RXM0SIDH, 4, c_mask);
+ write_block(chip, MCP2515_RXM1SIDH, 4, c_mask);
+
+ CANMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
+ CANMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
+// DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
+// DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
mcp2515_disable_configuration(chip);
-#endif
+// #endif
return 0;
}
continue;
}
readreg = read_reg(chip, MCP2515_CNF3);
- if (readreg & CNF3_PHSEG2_MASK != (u8)((ps2-1))){
+ if ((readreg & CNF3_PHSEG2_MASK) != (u8)((ps2-1))){
CANMSG("Wrong value in CNF3 - sent: 0x%X, received: 0x%X\n",(ps2-1) | brp,readreg & CNF3_PHSEG2_MASK);
continue;
}
return 0;
}
-#define MAX_TRANSMIT_WAIT_LOOPS 10
+#define MAX_TRANSMIT_WAIT_LOOPS 20
/**
* mcp2515_pre_write_config: - prepares message object for message transmission
* @chip: pointer to chip state structure
return -EIO;
}
-
- frame.sidl = (msg->id << 5) ||
- ((msg->flags & MSG_EXT) ? mcpEXIDE : 0) ||
- ((msg->id >> 16) & mcpEID_MASK);
-
len = msg->length;
if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
if(msg->flags & MSG_EXT) {
- frame.sidh = msg->id >> 21;
- frame.sidl = (msg->id << 5) | ((msg->id >> 27) & 0x3) | mcpEXIDE;
- frame.eid8 = msg->id >> 19;
- frame.eid0 = 13;
+ frame.sidh = (msg->id >> 3) & 0xFF;
+ frame.sidl = ((msg->id << 5) | ((msg->id >> 27) & mcpEID_MASK) | mcpEXIDE) & 0xFF;
+ frame.eid8 = (msg->id >> 19) & 0xFF;
+ frame.eid0 = (msg->id >> 11) & 0xFF;
frame.dlc = len | ((msg->flags & MSG_RTR) ? mcpRTR : 0);
memcpy(frame.data, msg->data, len);
}
else {
- frame.sidh = msg->id >> 21;
- frame.sidl = (msg->id << 5) | ((msg->id >> 27) & 0x3);
- frame.eid8 = msg->id >> 19;
- frame.eid0 = 13;
+ frame.sidh = (msg->id >> 3) & 0xFF;
+ frame.sidl = ((msg->id << 5) | ((msg->id >> 27) & mcpEID_MASK)) & 0xFF;
+ frame.eid8 = (msg->id >> 19) & 0xFF;
+ frame.eid0 = (msg->id >> 11) & 0xFF;
frame.dlc = len | ((msg->flags & MSG_RTR) ? mcpRTR : 0);
memcpy(frame.data, msg->data, len);
}
- write_block(chip, MCP2515_TXB0SIDH, len+5, &frame);
+ if (obj == chip->msgobj[0])
+ write_block(chip, MCP2515_TXB0SIDH, len+5, &frame);
+ if (obj == chip->msgobj[1])
+ write_block(chip, MCP2515_TXB1SIDH, len+5, &frame);
+ if (obj == chip->msgobj[2])
+ write_block(chip, MCP2515_TXB2SIDH, len+5, &frame);
can_spi_release_bus(chip);
DEBUGMSG("mcp2515_send_msg\n");
can_spi_acquire_bus(chip,1);
- bitmod_reg(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ);
+#ifdef MCP2515_SPI_ASYNC
+ if (obj == chip->msgobj[0])
+ bitmod_reg_async(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+ if (obj == chip->msgobj[1])
+ bitmod_reg_async(chip, MCP2515_TXB1CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+ if (obj == chip->msgobj[2])
+ bitmod_reg_async(chip, MCP2515_TXB2CTRL, mcpTXREQ, mcpTXREQ, NOOP);
+#else
+ if (obj == chip->msgobj[0])
+ bitmod_reg(chip, MCP2515_TXB0CTRL, mcpTXREQ, mcpTXREQ);
+ if (obj == chip->msgobj[1])
+ bitmod_reg(chip, MCP2515_TXB1CTRL, mcpTXREQ, mcpTXREQ);
+ if (obj == chip->msgobj[2])
+ bitmod_reg(chip, MCP2515_TXB2CTRL, mcpTXREQ, mcpTXREQ);
+#endif
can_spi_release_bus(chip);
return 0;
{
DEBUGMSG("mcp2515_attach_to_chip\n");
/* Initialize delayed interrupt processing */
+ mcp2515_wq = create_singlethread_workqueue("lincan_mcp2515");
+ if (mcp2515_wq == NULL)
+ return -1;
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler),
workqueue_handler,
- NULL);
+ &(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
+ INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler),
+ txwq_handler,
+ &(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler);
#else
INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler),
workqueue_handler);
+ INIT_WORK(&(((MCP2515_PRIV *)(chip->chip_data))->txwq_handler),
+ txwq_handler);
#endif
tasklet_init(&(((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler),
chip->flags &= ~CHIP_ATTACHED;
DEBUGMSG("Flush workqueue.\n");
+ cancel_delayed_work(&((MCP2515_PRIV *)(chip->chip_data))->txwq_handler);
cancel_delayed_work(&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
- flush_scheduled_work();
+ flush_workqueue(mcp2515_wq);
DEBUGMSG("Kill tasklets.\n");
tasklet_kill(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
mcp2515_stop_chip(chip);
can_write_reg(chip, sjaDISABLE_INTERRUPTS, SJAIER);
#endif
+ destroy_workqueue(mcp2515_wq);
+
return 0;
}
if (~chip->flags & CHIP_ATTACHED)
return CANCHIP_IRQ_ACCEPTED;
+ if(can_spi_acquire_bus(chip, 0)){
+#ifdef MCP2515_SPI_ASYNC
+ /* let the SPI subsystem read interrupt status immediately - the response runs in callbacks */
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
/* do work in tasklet if bus is immediately available */
- if(can_spi_acquire_bus(chip, 0))
- tasklet_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+ tasklet_hi_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+#endif /* MCP2515_SPI_ASYNC */
+ }
else /* do work in workqueue */
- schedule_work(&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
+ queue_work(mcp2515_wq,&((MCP2515_PRIV *)(chip->chip_data))->workqueue_handler);
disable_irq(chip->chip_irq);
return CANCHIP_IRQ_HANDLED;
obj->tx_retry_cnt=0;
tx_handler(chip, obj);
}
+ else{
+#ifdef MCP2515_SPI_ASYNC
+ /* let the SPI subsystem read interrupt status immediately - the response runs in callbacks */
+ read_async(chip,MCP2515_CANINTF,1,READ_CANINTF);
+#else
+ /* do work in tasklet if bus is immediately available */
+ tasklet_hi_schedule(&((MCP2515_PRIV *)(chip->chip_data))->tasklet_handler);
+#endif /* MCP2515_SPI_ASYNC */
+ }
+
can_spi_release_bus(chip);
can_msgobj_clear_fl(obj,TX_LOCK);
{
DEBUGMSG("mcp2515_fill_chipspecops\n");
chip->chip_type="mcp2515";
- chip->max_objects=2;
+ chip->max_objects=3;
mcp2515_register(chip->chipspecops);
return 0;
}