⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcan_pccard_kernel.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 2 页
字号:
//****************************************************************************// Copyright (C) 2006-2007  PEAK System-Technik GmbH//// linux@peak-system.com// www.peak-system.com//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.//// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)//// Major contributions by://                Edouard Tisserant (edouard.tisserant@lolitech.fr) XENOMAI//                Laurent Bessard   (laurent.bessard@lolitech.fr)   XENOMAI//                Oliver Hartkopp   (oliver.hartkopp@volkswagen.de) socketCAN//                     //****************************************************************************//***************************************************************************//// all parts to handle the interface specific parts of pcan-pccard//// $Id: pcan_pccard_kernel.c 541 2008-02-18 17:48:03Z edouard $////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h>     // must always be the 1st include#include <linux/errno.h>#include <linux/sched.h>#include <linux/delay.h>#include <asm/io.h>#include <linux/types.h>#include <linux/timer.h>         // to support activity scan#include <linux/slab.h>#include <src/pcan_main.h>#include <src/pcan_pccard.h>#include <src/pcan_sja1000.h>#include <src/pcan_fifo.h>#ifdef NETDEV_SUPPORT#include <src/pcan_netdev.h>     // for hotplug pcan_netdev_register()#endif#include <src/pcan_pccard_kernel.h>#include <src/pcan_filter.h>//****************************************************************************// DEFINES#define PCCARD_PORT_SIZE   0x20         // range of a channels port#define PCCARD_COMMON_SIZE 0x40         // range of channels common ports#define PCCARD_CHANNEL_OFF 0x20         // port offset of sja1000 channel #2#define PCCARD_COMMON      0x40         // port offset of common area                                        // offsets from base of common area#define CCR                0x00         // CAN control register#define CSR                0x02         // CAN status register#define CPR                0x04         // CAN power register#define SPIDATI            0x06         // SPI data in#define SPIDATO            0x08         // SPI data out#define SPIADR             0x0A         // SPI address register#define SPIINS             0x0C         // SPI instruction register#define FW_MAJOR           0x10         // firmware major number (local)#define FW_MINOR           0x12         // firmware minor number (local)#define CCR_CLK_MASK       0x03         // mask for clock code#define CCR_CLK16          0x00         // clk code#define CCR_CLK10          0x01         // #define CCR_CLK21          0x02         // #define CCR_CLK8           0x03         // #define CCR_CLK_DEFAULT    CCR_CLK16    // set default clock       #define CCR_RESET_MASK     0x01#define CCR_RESET          0x01         // put channel into reset#define CCR_RESET0_SHIFT      2         // shift for channel 0#define CCR_RESET1_SHIFT      3         // shift for channel 1#define CCR_LED_MASK       0x03         // mask for LED channel 0 code#define CCR_LED_ON         0x00         // switch LED permanently on#define CCR_LED_FAST       0x01         // switch LED to 4 Hz flash#define CCR_LED_SLOW       0x02         // switch LED to 1 Hz flash#define CCR_LED_OFF        0x03         // switch LED off#define CCR_LED0_SHIFT        4         // shift for channel 1#define CCR_LED1_SHIFT        6         // shift for channel 1#define CCR_DEFAULT       ((((u8)CCR_LED_OFF) << CCR_LED0_SHIFT) | (((u8)CCR_LED_OFF) << CCR_LED1_SHIFT) | CCR_CLK_DEFAULT) #define CSR_SPIBUSY        0x04         // set when SPI transaction is busy#define SPI_MAX_WAIT_CYCLES 100#define MAX_LOOP_CYCLES    1000         // cycles to wait if card is plugged out or damaged//****************************************************************************// helper macros//****************************************************************************// GLOBALS//****************************************************************************// LOCALSstatic u16 pccard_devices = 0;//****************************************************************************// CODE// it seems that even when called after 'pccardctl eject' the card is seen as// already plugged out. So this function allways return 0.// BTW this does not matter since PCCARDs power is switched off during// plug out or 'pccardctl eject'. Therefore no de-initialisation of hardware // components are necessary.static inline int pccard_plugged(PCAN_PCCARD *card){  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)  return (pcmcia_dev_present(card->pcc_dev) != NULL);  #else    #if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,16)    return DEV_OK(card->link.handle);    #else    return DEV_OK((&card->link));    #endif  #endif}//****************************************************************************// read channel individual registerstatic u8 pccard_readreg(struct pcandev *dev, u8 port) // read a register{  return inb(dev->port.pccard.dwPort + port);}// write channel individual registerstatic void pccard_writereg(struct pcandev *dev, u8 port, u8 data) // write a register{  outb(data, dev->port.pccard.dwPort + port) ; }// read common register to both channels of a cardstatic inline u8 pccard_readreg_common(PCAN_PCCARD *card, u8 port) // read a register{  return inb(card->commonPort + port);}// write common register to both channels of a cardstatic inline void pccard_writereg_common(PCAN_PCCARD *card, u8 port, u8 data) // write a register{  outb(data, card->commonPort + port); }//****************************************************************************// SPI enginestatic int wait_while_spi_engine_busy(PCAN_PCCARD *card){  int counter = SPI_MAX_WAIT_CYCLES;  do    schedule();  while ((pccard_readreg_common(card, CSR) & CSR_SPIBUSY) && counter--);  if (counter <= 0)    return -EIO;  else    return 0;}static int pccard_write_eeprom(PCAN_PCCARD *card, u16 addr, u8 val){  u16 status;  int err = 0;  int counter;  DPRINTK(KERN_DEBUG "%s: pccard_write_eeprom()\n", DEVICE_NAME);  // Instruction WRITE  pccard_writereg_common(card, SPIINS, 0x06); // WREN  if ((err = wait_while_spi_engine_busy(card)) < 0)    goto fail;      // warte, bis WEL gesetzt ist  counter = MAX_LOOP_CYCLES;  do   {    pccard_writereg_common(card, SPIINS, 0x05); // RDSR == Read status    if ((err = wait_while_spi_engine_busy(card)) < 0)      goto fail;    status = pccard_readreg_common(card, SPIDATI);  } while ((!(status & 0x02)) && counter--); // warte, bis WEL (write enable) 1.  if (counter <= 0)  {    err = -EIO;    goto fail;  }  // Adresse und Data setzen  pccard_writereg_common(card, SPIADR, addr & 0xff);  pccard_writereg_common(card, SPIDATO, val);    // Instruction WRITE  pccard_writereg_common(card, SPIINS, ((addr & 0x100) ? 8 : 0) | 0x02); // WRITE mit bit3 = Addr8  if ((err = wait_while_spi_engine_busy(card)) < 0)    goto fail;  // warte, bis Schreiben abgeschlossen  counter = MAX_LOOP_CYCLES;  do   {    pccard_writereg_common(card, SPIINS, 0x05); // RDSR == Read status    if ((err = wait_while_spi_engine_busy(card)) < 0)      goto fail;    status = pccard_readreg_common(card, SPIDATI);  } while ((status & 0x01) && counter--); // warte, bis WIP (Write In Progress) 0.  if (counter <= 0)    err = -EIO;    fail:  if (err)  {    DPRINTK(KERN_DEBUG "%s: pccard_write_eeprom(0x%04x, 0x%02x) failed!\n", DEVICE_NAME, addr, val);  }  return err;}//****************************************************************************// helper functions// get firmware number of PCCstatic inline void pccard_show_firmware_version(PCAN_PCCARD *card){  u8 fw_major = pccard_readreg_common(card, FW_MAJOR);  u8 fw_minor = pccard_readreg_common(card, FW_MINOR);    printk(KERN_INFO "%s: pccard firmware %d.%d\n", DEVICE_NAME, fw_major, fw_minor);}// init CCR settingsstatic inline void pccard_initreg_common(PCAN_PCCARD *card){  pccard_writereg_common(card, CCR, CCR_DEFAULT);  }// hard reset only one channel to its default settingsstatic inline void pccard_channel_reset(PCAN_PCCARD *card, int nChannel){  u8 data;  u8 shift = (nChannel) ? CCR_RESET1_SHIFT : CCR_RESET0_SHIFT;    DPRINTK(KERN_DEBUG "%s: pccard_channel_reset(%d)\n", DEVICE_NAME, nChannel);        data = pccard_readreg_common(card, CCR);  data &= ~(CCR_RESET_MASK << shift);  data |=  (CCR_RESET      << shift);  pccard_writereg_common(card, CCR, data);  mdelay(2);  data = pccard_readreg_common(card, CCR);  data &= ~(CCR_RESET_MASK << shift);  data &= ~(CCR_RESET      << shift);  pccard_writereg_common(card, CCR, data);    mdelay(10); // wait until reset has settled}// set LEDstatic inline void pccard_set_LED(PCAN_PCCARD *card, int nChannel, u8 mode){  u8 data;  u8 shift = (nChannel) ? CCR_LED1_SHIFT : CCR_LED0_SHIFT;    mode &= CCR_LED_MASK;    data = pccard_readreg_common(card, CCR);    // write only if something has changed  if (((data >> shift) & CCR_LED_MASK) != mode)  {      data &= ~(CCR_LED_MASK << shift);    data |=  (mode         << shift);    pccard_writereg_common(card, CCR, data);  }}// enable CAN powerstatic inline void pccard_enable_CAN_power(PCAN_PCCARD *card){  DPRINTK(KERN_DEBUG "%s: pccard_enable_CAN_power()\n", DEVICE_NAME);  pccard_write_eeprom(card, 0, 1);}// disable CAN powerstatic inline void pccard_disable_CAN_power(PCAN_PCCARD *card){  DPRINTK(KERN_DEBUG "%s: pccard_disable_CAN_power()\n", DEVICE_NAME);  pccard_write_eeprom(card, 0, 0);}//****************************************************************************// activity scanner to control LEDsstatic void pccard_activity_scanner(unsigned long ptr){  PCAN_PCCARD *card = (PCAN_PCCARD *)ptr;  struct pcandev *dev;  int i;    // DPRINTK(KERN_DEBUG "%s: pccard_activity_scanner(%p)\n", DEVICE_NAME, card);  for (i = 0; i < PCCARD_CHANNELS; i++)  {    dev = card->dev[i];    if (dev)    {      u8 state = dev->ucActivityState;            switch(state)      {        case ACTIVITY_XMIT:          dev->ucActivityState = ACTIVITY_IDLE;          pccard_set_LED(card, i, CCR_LED_FAST);              break;        case ACTIVITY_IDLE:          pccard_set_LED(card, i, CCR_LED_SLOW);              break;        case ACTIVITY_INITIALIZED:          pccard_set_LED(card, i, CCR_LED_ON);              break;        default:          pccard_set_LED(card, i, CCR_LED_OFF);              break;      }    }    else      pccard_set_LED(card, i, CCR_LED_OFF);  }  // restart timer  if (card->run_activity_timer_cyclic)  {    card->activity_timer.expires  = jiffies + HZ;     add_timer(&card->activity_timer);  }}static void pccard_start_activity_scanner(PCAN_PCCARD *card){  DPRINTK(KERN_DEBUG "%s: pccard_start_activity_scanner(%p)\n", DEVICE_NAME, card);    init_timer(&card->activity_timer);  card->activity_timer.function = pccard_activity_scanner;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -