+/*****************************************************************************/
+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");
+ }
+ }
+}
+