📄 mcp2515funcs.c
字号:
canmsg_t rx;int minor = 0; /* only one device at the moment */ /* DBGin(); */ RxFifo = &Rx_Buf[minor][0]; down(&priv->spi_lock); /* The Read RX Buffer instruction provides * a means to quickly address a receive buffer for reading. * This instruction further reduces the SPI overhead * by automatically clearing the associated receive flag * (CANINTF.RXnIF) when CS is raised at the end of the command. */ tx_buf[0] = INSTRUCTION_READ_RXB(buf_idx); at91_spihw_rwn(priv->spi_tx_buf, priv->spi_rx_buf, 14); rx.flags = 0; if ((rx_buf[2] >> 3) & 0x1) { /* Extended ID format */ rx.flags |= MSG_EXT; rx.id = (rx_buf[1] << 21) + ((rx_buf[2] &0xe0) << 13) + ((rx_buf[2] & 3) << 16) + (rx_buf[3] << 8) + rx_buf[4]; } else { /* Standard ID format */ rx.id = (rx_buf[1] << 3) | (rx_buf[2] >> 5); } if ((rx_buf[5] >> 6) & 0x1) { /* Remote transmission request */ rx.flags |= MSG_RTR; } /* Data length */ rx.length = rx_buf[5] & 0x0f; rx.timestamp.tv_sec = tv->tv_sec; rx.timestamp.tv_usec = tv->tv_usec; memcpy( &rx.data[0], rx_buf + 6, rx.length); insert_rxfifo(minor, &rx); /* put the received frame in all rx queues */ up(&priv->spi_lock);}/* handling the CAN if ISR was called is done here */static void mcp251x_irq_work_handler(void){struct mcp251x_priv *priv = &realone;struct spi_device *spi = priv->spi;int irqsrc;msg_fifo_t *TxFifo; /* pointer to the active tx fifo used */msg_fifo_t *RxFifo; /* pointer to the active rx fifo used */struct timeval timestamp;int rx_fifo; /* loopindex for different rx queues */static int state = 0; /* CAN Controller state */ int newstate = 0;int minor = 0; /* only one device supported */ /* RxFifo = &Rx_Buf[minor][0]; */ TxFifo = &Tx_Buf[minor]; /* DBGin(); */ for (;;) { /* Read out Interrupt sources and reset Int Flags */ irqsrc = mcp251x_read_reg(CANINTF); /* reset INTF interrupt flags */ mcp251x_write_reg(CANINTF, 0); /* fill timestamp as first action. * Getting a precises time takes a lot of time * (additional 7 祍 of ISR time ) * if a time stamp is not needed, it can be switched of * by ioctl() */ if (use_timestamp[minor]) { do_gettimeofday(×tamp); } else { timestamp.tv_sec = 0; timestamp.tv_usec = 0; }#if 0 dev_info(&priv->dev, "interrupt:%s%s%s%s%s%s%s%s\n", (irqsrc & CANINTF_MERRF) ? " MERR" : "", (irqsrc & CANINTF_WAKIF) ? " WAK" : "", (irqsrc & CANINTF_ERRIF) ? " ERR" : "", (irqsrc & CANINTF_TX2IF) ? " TX2" : "", (irqsrc & CANINTF_TX1IF) ? " TX1" : "", (irqsrc & CANINTF_TX0IF) ? " TX0" : "", (irqsrc & CANINTF_RX1IF) ? " RX1" : "", (irqsrc & CANINTF_RX0IF) ? " RX0" : "");#endif if (irqsrc == 0x00) { /* dev_info(&priv->dev, "nothing\n"); */ break; } if (irqsrc & CANINTF_WAKIF) { dev_info(&priv->dev, "WAKIF\n"); } /* message error interrupt flag * any error while transmitting or receiving */ if (irqsrc & CANINTF_MERRF) { u8 txbnctrl; canmsg_t frame; /* temporary CAN from for error signaling */ u8 eflag = mcp251x_read_reg(EFLG); frame.flags = MSG_ACTIVE; /* CAN frame flags */ /* if there are no pending Tx buffers, restart queue */ dev_info(&priv->dev, "MERRF, 0x%x\n", eflag); txbnctrl = mcp251x_read_reg(TXBCTRL(0)); if (!(txbnctrl & TXBCTRL_TXREQ)) /* No pending tx request */ /* pending tx request */ ; /* Set error frame flags according to bus state */ if (eflag & EFLG_TXBO) { frame.flags |= MSG_BUSOFF; } else if (eflag & EFLG_TXEP) { frame.flags |= MSG_PASSIVE; } else if (eflag & EFLG_RXEP) { frame.flags |= MSG_PASSIVE; } else if (eflag & EFLG_TXWAR) { frame.flags |= MSG_WARNING; } else if (eflag & EFLG_RXWAR) { frame.flags |= MSG_WARNING; } frame.id = CANDRIVERERROR; frame.length = 0; insert_rxfifo(minor, &frame); } /* When the error interrupt is enabled (CANINTE.ERRIE = 1), an interrupt is generated on the INT pin if an overflow condition occurs or if the error state of the transmitter or receiver has changed. The Error Flag (EFLG) register will indicate one of the following conditions. */ if (irqsrc & CANINTF_ERRIF) { u8 eflag = mcp251x_read_reg(EFLG); canmsg_t frame; /* temporary CAN from for error signaling */ frame.flags = MSG_ACTIVE; /* CAN frame flags */ /* dev_info(&priv->dev, "EFLG = 0x%02x\n", eflag); */ newstate = eflag; if(state != newstate){ /* printk("== State change\n"); */ state = newstate; } /* Set error frame flags according to bus state */ if (eflag & EFLG_TXBO) { frame.flags |= MSG_BUSOFF; ; } else if (eflag & EFLG_TXEP) { frame.flags |= MSG_PASSIVE; ; } else if (eflag & EFLG_RXEP) { frame.flags |= MSG_PASSIVE; ; } else if (eflag & EFLG_TXWAR) { frame.flags |= MSG_WARNING; ; } else if (eflag & EFLG_RXWAR) { frame.flags |= MSG_WARNING; ; } if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) { if (eflag & EFLG_RX0OVR) { ; } if (eflag & EFLG_RX1OVR) { ; } mcp251x_write_reg(EFLG, 0x00); } /* generate an error CAN frame for the rx queue */ frame.id = CANDRIVERERROR; frame.length = 0; insert_rxfifo(minor, &frame); } /*========== transmit interrupt */ if (irqsrc & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) { /* CAN frame successfully sent */ /* use time stamp sampled with last INT */ last_Tx_object[minor].timestamp = timestamp; /* depending on the number of open processes * the TX data has to be copied in different * rx fifos */ for(rx_fifo = 0; rx_fifo < CAN_MAX_OPEN; rx_fifo++) { /* for every rx fifo */ if (CanWaitFlag[minor][rx_fifo] == 1) { /* this FIFO is in use */ /* * Don't copy the message in the receive queue * of the process that sent the message unless * this process requested selfreception. */ if ((last_Tx_object[minor].cob == rx_fifo) && (selfreception[minor][rx_fifo] == 0)) { continue; } /* prepare buffer to be used */ RxFifo = &Rx_Buf[minor][rx_fifo]; memcpy( (void *)&RxFifo->data[RxFifo->head], (void *)&last_Tx_object[minor], sizeof(canmsg_t)); /* Mark message as 'self sent/received' */ RxFifo->data[RxFifo->head].flags |= MSG_SELF; /* increment write index */ RxFifo->status = BUF_OK; RxFifo->head = ++(RxFifo->head) % MAX_BUFSIZE; if(RxFifo->head == RxFifo->tail) { printk("CAN[%d][%d] RX: FIFO overrun\n", minor, rx_fifo); RxFifo->status = BUF_OVERRUN; } /*---------- kick the select() call -*/ /* This function will wake up all processes that are waiting on this event queue, that are in interruptible sleep */ wake_up_interruptible(&CanWait[minor][rx_fifo]); } /* this FIFO is in use */ } /* end for loop filling all rx-fifos */ if( TxFifo->free[TxFifo->tail] == BUF_EMPTY ) { /* TX FIFO empty, nothing more to sent */ /* printk("TXE\n"); */ TxFifo->status = BUF_EMPTY; TxFifo->active = 0; /* This function will wake up all processes that are waiting on this event queue, that are in interruptible sleep */ wake_up_interruptible(&CanOutWait[minor]); goto Tx_done; } else { /* The TX message FIFO contains other CAN frames to be sent * The next frame in the FIFO is copied into the last_Tx_object * and directly into the hardware of the CAN controller */ /* The TX message FIFO contains other CAN frames to be sent * The next frame in the FIFO is copied into the last_Tx_object * and directly into the hardware of the CAN controller */ /* dev_info(&priv->dev, "schedule next frame for transmission\n"); */ memcpy( (void *)&last_Tx_object[minor], (void *)&TxFifo->data[TxFifo->tail], sizeof(canmsg_t)); CAN_SendMessage(0, &last_Tx_object[minor]); /* now this entry is EMPTY */ TxFifo->free[TxFifo->tail] = BUF_EMPTY; TxFifo->tail = ++(TxFifo->tail) % MAX_BUFSIZE; } goto Tx_done; } /* tx interrupt */Tx_done: if (irqsrc & CANINTF_RX0IF) { /* DBGprint(DBG_BRANCH, ("RX 0\n")); */ mcp251x_hw_rx(spi, 0, ×tamp); /* CANINTF_RXnIF is cleared already automatically */ } if (irqsrc & CANINTF_RX1IF) { /* DBGprint(DBG_BRANCH, ("RX 1\n")); */ mcp251x_hw_rx(spi, 1, ×tamp); /* CANINTF_RXnIF is cleared already automatically */ } } mcp251x_read_reg(CANSTAT); /* dev_info(&priv->dev, "interrupt ended\n"); */ /* DBGout(); */}/* On the SSV Board, CAN2, the MCP2515, INT_2 is connected to PIO PB24 another signal, CAN2_SOF is connected to PB25, which (hopefully) is not needed (yet) From the Manual The MCP2515 has eight sources of interrupts. The CANINTE register contains the individual interrupt enable bits for each interrupt source. - If the message started to transmit but encoun- tered an error condition, the TXBnCTRL.TXERR and the CANINTF.MERRF bits will be set and an interrupt will be generated on the INT pin if the CANINTE.MERRE bit is set - If the CANINTE.RXnIE bit is set, an interrupt will be generated on the INT pin to indicate that a valid message has been received. - Transmit Interrupt When the transmit interrupt is enabled (CANINTE.TXnIE = 1), an interrupt will be generated on the INT pin once the associated transmit buffer becomes empty and is ready to be loaded with a new message. The CANINTF.TXnIF bit will be set to indicate the source of the interrupt. The interrupt is cleared by clearing the TXnIF bit. - Receive Interrupt When receive interrupt is enabled (CANINTE.RXnIE = 1), an interrupt will be generated on the INT pin once a message has been successfully received and loaded into the associated receive buffer. This interrupt is activated immediately after receiving the EOF field. The CANINTF.RXnIF bit will be set to indicate the source of the interrupt. The interrupt is cleared by clearing the RXnIF bit. - Message Error Interrupt When an error occurs during the transmission or reception of a message, the message error flag (CANINTF.MERRF) will be set and, if the CANINTE.MERRE bit is set, an interrupt will be generated on the INT pin. This is intended to be used to facilitate baud rate determination when used in conjunction with Listen-only mode. When the error interrupt is enabled (CANINTE.ERRIE = 1), an interrupt is generated on the INT pin if an overflow condition occurs or if the error state of the transmitter or receiver has changed. The Error Flag (EFLG) register will indicate one of the following conditions. - Interrupt Acknowledge Interrupts are directly associated with one or more status flags in the CANINTF register. Interrupts are pending as long as one of the flags is set. Once an interrupt flag is set by the device, the flag can not be reset by the MCU until the interrupt condition is removed. The SSV board is using a standard GPIO pin with edge sensitive interrupt. The CAN controller is issuing an interrupt with a high/low edge. The kernel is not able to differnciate, therfore the first thing we do in the ISR is checking the current level of the IO pin. If it is low, the interrupt has to be handled. */irqreturn_t CAN_Interrupt(int irq, void *dev_id) {#ifdef CANSPI_USEKTHREAD struct mcp251x_priv *priv = &realone;#endif /* printk("----------- > CAN - ISR\n"); */ /* Test GPIO line */ if( at91_get_gpio_value(AT91_PIN_PB24) == 0) {#ifdef CANSPI_USEKTHREAD /* Schedule bottom half */ queue_work(priv->wq, &priv->irq_work);#else mcp251x_irq_work_handler();#endif } return IRQ_HANDLED;}int __devinit mcp251x_can_probe(void){ struct mcp251x_priv *priv; int ret = -ENODEV; priv = &realone; init_MUTEX(&priv->spi_lock); dev_dbg(&priv->dev, "%s, allocate memory %d for tx and rx\n", __FUNCTION__, SPI_TRANSFER_BUF_LEN); priv->spi_tx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL); if (!priv->spi_tx_buf) { ret = -ENOMEM; goto error_tx_buf; } priv->spi_rx_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL); if (!priv->spi_tx_buf) { ret = -ENOMEM; goto error_rx_buf; } if (at91_spihw_init()) { ret = -ENOMEM; goto error_rx_buf; }#ifdef CANSPI_USEKTHREAD /* ISR only schedules a task to the work queu */ priv->wq = create_singlethread_workqueue("mcp251x_wq"); INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler); init_completion(&priv->awake);#endif /* error free return */ return 0;error_rx_buf: kfree(priv->spi_tx_buf);error_tx_buf: dev_err(&priv->dev, "probe failed\n"); return ret;}int __devexit mcp251x_can_remove(void){ struct mcp251x_priv *priv = &realone; kfree(priv->spi_tx_buf); kfree(priv->spi_rx_buf); at91_spihw_deinit(); return 0;} /* ---------------- E N D E ---------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -