📄 pcan_sja1000.c
字号:
ULCONV localID; u8 dreg; int i; fi = dlc = cf->can_dlc; id = localID.ul = cf->can_id; if (id & CAN_RTR_FLAG) fi |= BUFFER_RTR; if (id & CAN_EFF_FLAG) { dreg = TRANSMIT_FRAME_BASE + 5; fi |= BUFFER_EFF; localID.ul <<= 3; #if defined(__LITTLE_ENDIAN) dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[3]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[2]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, localID.uc[1]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, localID.uc[0]); #elif defined(__BIG_ENDIAN) dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[0]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[1]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, localID.uc[2]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, localID.uc[3]); #else #error "Please fix the endianness defines in <asm/byteorder.h>" #endif // dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, (id & 0x1fe00000) >> (5 + 16)); // dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, (id & 0x001fe000) >> (5 + 8)); // dev->writereg(dev, TRANSMIT_FRAME_BASE + 3, (id & 0x00001fe0) >> 5); // dev->writereg(dev, TRANSMIT_FRAME_BASE + 4, (id & 0x0000001f) << 3); } else { dreg = TRANSMIT_FRAME_BASE + 3; localID.ul <<= 21; #if defined(__LITTLE_ENDIAN) dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[3]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[2]); #elif defined(__BIG_ENDIAN) dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, localID.uc[0]); dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, localID.uc[1]); #else #error "Please fix the endianness defines in <asm/byteorder.h>" #endif // dev->writereg(dev, TRANSMIT_FRAME_BASE + 1, (id & 0x000007f8) >> 3); // dev->writereg(dev, TRANSMIT_FRAME_BASE + 2, (id & 0x00000007) << 5); } for (i = 0; i < dlc; i++) { dev->writereg(dev, dreg++, cf->data[i]); } dev->writereg(dev, TRANSMIT_FRAME_BASE, fi); // request a transmission dev->writereg(dev, COMMAND, TRANSMISSION_REQUEST); wmb(); // strange hack to get write stall managed if ((dev->readreg(dev, CHIPSTATUS) & TRANS_COMPLETE_STATUS)) { DPRINTK(KERN_ERR "%s: Transmission finished early..., minor=%d\n", DEVICE_NAME, dev->nMinor); } return 0;}//----------------------------------------------------------------------------// write CAN-data from FIFO to chip int sja1000_write(SJA1000_METHOD_ARGS){ int result; TPCANMsg msg; struct can_frame cf; // DPRINTK(KERN_DEBUG "%s: sja1000_write() %d\n", DEVICE_NAME, dev->writeFifo.nStored); SJA1000_LOCK_IRQSAVE(out_lock); // get a fifo element and step forward result = pcan_fifo_get(&dev->writeFifo, &msg); SJA1000_WAKEUP_EMPTY(); SJA1000_UNLOCK_IRQRESTORE(out_lock); if (result) return result; /* convert from old style FIFO message until FIFO supports new */ /* struct can_frame and error frames */ msg2frame(&cf, &msg); sja1000_write_frame(dev, &cf); return 0;}//----------------------------------------------------------------------------// handle a interrupt requestint sja1000_irqhandler_common(SJA1000_METHOD_ARGS){ int ret = SJA1000_IRQ_NONE; u8 irqstatus; int err; u16 rwakeup = 0; u16 wwakeup = 0; int j = MAX_INTERRUPTS_PER_ENTRY; struct can_frame ef; memset(&ef, 0, sizeof(ef)); // DPRINTK(KERN_DEBUG "%s: sja1000_base_irqhandler|sja1000_irqhandler_rt()\n", DEVICE_NAME); SJA1000_LOCK_IRQSAVE(sja_lock); while ((j--) && (irqstatus = dev->readreg(dev, INTERRUPT_STATUS))) { // DPRINTK(KERN_DEBUG "%s: sja1000_[base_irqhandler|irqhandler_rt](0x%02x)\n", DEVICE_NAME, irqstatus); dev->dwInterruptCounter++; err = 0; // quick hack to badly workaround write stall // if ((irqstatus & TRANSMIT_INTERRUPT) || (!atomic_read(&dev->DataSendReady) && !pcan_fifo_empty(&dev->writeFifo) && (dev->readreg(dev, CHIPSTATUS) & TRANS_BUFFER_STATUS))) if (irqstatus & TRANSMIT_INTERRUPT) { // handle transmission if ((err = SJA1000_FUNCTION_CALL(sja1000_write))) { if (err == -ENODATA) wwakeup++; else { dev->nLastError = err; dev->dwErrorCounter++; dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error! } } dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer } if (irqstatus & DATA_OVERRUN_INTERRUPT) { // handle data overrun dev->wCANStatus |= CAN_ERR_OVERRUN; ef.can_id |= CAN_ERR_CRTL; ef.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW; rwakeup++; dev->dwErrorCounter++; dev->writereg(dev, COMMAND, CLEAR_DATA_OVERRUN); wmb(); dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer } if (irqstatus & RECEIVE_INTERRUPT) { // handle receiption if ((err = SJA1000_FUNCTION_CALL(sja1000_read_frames)) < 0) /* put to input queues */ { 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(); } if (err > 0) // successfully enqueued into chardev FIFO rwakeup++; dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer } if (irqstatus & (BUS_ERROR_INTERRUPT | ERROR_PASSIV_INTERRUPT | ERROR_WARN_INTERRUPT)) { // DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), irqstatus=0x%02x\n", DEVICE_NAME, irqstatus); if (irqstatus & (ERROR_PASSIV_INTERRUPT | ERROR_WARN_INTERRUPT)) { u8 chipstatus = dev->readreg(dev, CHIPSTATUS); // DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), chipstatus=0x%02x\n", DEVICE_NAME, chipstatus); switch (chipstatus & (BUS_STATUS | ERROR_STATUS)) { case 0x00: // error active, clear only local status dev->busStatus = CAN_ERROR_ACTIVE; DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (1)\n", DEVICE_NAME); dev->wCANStatus &= ~(CAN_ERR_BUSOFF | CAN_ERR_BUSHEAVY | CAN_ERR_BUSLIGHT); break; case BUS_STATUS: case BUS_STATUS | ERROR_STATUS: // bus-off dev->busStatus = CAN_BUS_OFF; dev->wCANStatus |= CAN_ERR_BUSOFF; ef.can_id |= CAN_ERR_BUSOFF_NETDEV; DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_BUS_OFF\n", DEVICE_NAME); break; case ERROR_STATUS: if (irqstatus & ERROR_PASSIV_INTERRUPT) { // either enter or leave error passive status if (dev->busStatus == CAN_ERROR_PASSIVE) { // go back to error active dev->busStatus = CAN_ERROR_ACTIVE; dev->wCANStatus &= ~(CAN_ERR_BUSOFF | CAN_ERR_BUSHEAVY); dev->wCANStatus |= CAN_ERR_BUSLIGHT; DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (2)\n", DEVICE_NAME); } else { // enter error passive state dev->busStatus = CAN_ERROR_PASSIVE; dev->wCANStatus &= ~CAN_ERR_BUSOFF; dev->wCANStatus |= CAN_ERR_BUSHEAVY; ef.can_id |= CAN_ERR_CRTL; ef.data[1] |= (CAN_ERR_CRTL_RX_PASSIVE | CAN_ERR_CRTL_TX_PASSIVE); DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_PASSIVE\n", DEVICE_NAME); } } else { // it was a warning limit reached event dev->busStatus = CAN_ERROR_ACTIVE; dev->wCANStatus |= CAN_ERR_BUSLIGHT; ef.can_id |= CAN_ERR_CRTL; ef.data[1] |= (CAN_ERR_CRTL_RX_WARNING | CAN_ERR_CRTL_TX_WARNING); DPRINTK(KERN_DEBUG "%s: sja1000_irqhandler(), busStatus=CAN_ERROR_ACTIVE (3)\n", DEVICE_NAME); } break; } } // count each error signal even if it does not change any bus or error state dev->dwErrorCounter++; // wake up pending reads or writes rwakeup++; wwakeup++; dev->ucActivityState = ACTIVITY_XMIT; // reset to ACTIVITY_IDLE by cyclic timer } /* if an error condition occurred, send an error frame to the userspace */ if (ef.can_id) { struct timeval tv; DO_GETTIMEOFDAY(tv); /* create timestamp */ ef.can_id |= CAN_ERR_FLAG; ef.can_dlc = CAN_ERR_DLC; SJA1000_LOCK_IRQSAVE(in_lock); if (pcan_xxxdev_rx(dev, &ef, &tv) > 0) // put into specific data sink rwakeup++; SJA1000_UNLOCK_IRQRESTORE(in_lock); memset(&ef, 0, sizeof(ef)); // clear for next loop } ret = SJA1000_IRQ_HANDLED; } SJA1000_UNLOCK_IRQRESTORE(sja_lock); if (wwakeup) { atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready wmb(); SJA1000_WAKEUP_WRITE(); #ifdef NETDEV_SUPPORT if (dev->netdev) netif_wake_queue(dev->netdev); #endif } if (rwakeup) SJA1000_WAKEUP_READ(); return ret;}//----------------------------------------------------------------------------// probe for a sja1000 - use it only in reset mode!int sja1000_probe(struct pcandev *dev){ u8 tmp; u8 _clkdivider= clkdivider(dev); DPRINTK(KERN_DEBUG "%s: sja1000_probe()\n", DEVICE_NAME); // 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 sja1000_irq_disable(dev); // precautionary disable 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 valuesu16 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 + -