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

📄 pcan_pccard_kernel.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 2 页
字号:
  card->activity_timer.data     = (unsigned long)card;  card->activity_timer.expires  = jiffies + HZ; // one second    card->run_activity_timer_cyclic = 1;  add_timer(&card->activity_timer);}static void pccard_stop_activity_scanner(PCAN_PCCARD *card){  DPRINTK(KERN_DEBUG "%s: pccard_stop_activity_scanner(%p)\n", DEVICE_NAME, card);    card->run_activity_timer_cyclic = 0;  del_timer_sync(&card->activity_timer);}//****************************************************************************// all about interrupt handling// make a special irqhandler since PCCARD irqs are ISA likestatic irqreturn_t IRQHANDLER(pcan_pccard_irqhandler, int irq, void *dev_id, struct pt_regs *regs){  struct pcandev *dev = (struct pcandev *)dev_id;  PCAN_PCCARD *card   = dev->port.pccard.card;  int ret             = 0;  u16 stop_count      = 100; // prevent to loop infinitely to get all shared interrupts cleared  u16 loop_count;  u16 index;    // DPRINTK(KERN_DEBUG "%s: pcan_pccard_irqhandler(%p)\n", DEVICE_NAME, dev_id);    for (index = 0, loop_count = 0; loop_count < PCCARD_CHANNELS; index++)  {    if ((dev = card->dev[index % PCCARD_CHANNELS])) // consider singel channel cards, too    {/* XXX TODO */      int tmpret = IRQHANDLER(sja1000_base_irqhandler, irq, dev, regs);      if (!tmpret)        	loop_count++;      else      {	ret = 1;         loop_count = 0; // restart, since all channels must respond in one pass with no interrupt pending      }              if (!stop_count--)      {        printk(KERN_ERR "%s: Too much PCCARD interrupt load, processing halted!\n", DEVICE_NAME);                break;      }          }    else      loop_count++;          if (loop_count == PCCARD_CHANNELS)      break;  }    return PCAN_IRQ_RETVAL(ret);}static int pccard_req_irq(struct pcandev *dev){  int err;    DPRINTK(KERN_DEBUG "%s: pccard_req_irq()\n", DEVICE_NAME);    if (dev->wInitStep == 4)  {    if ((err = request_irq(dev->port.pccard.wIrq, pcan_pccard_irqhandler, IRQF_DISABLED | IRQF_SHARED, "pcan", dev)))      return err;     dev->wInitStep = 5;  }    return 0;}static void pccard_free_irq(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pccard_free_irq()\n", DEVICE_NAME);    if (dev->wInitStep >= 5)  {    free_irq(dev->port.pccard.wIrq, dev);      dev->wInitStep = 4;  }}//****************************************************************************// free allocated resourcesstatic int pccard_cleanup(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pccard_cleanup()\n", DEVICE_NAME);    if (dev)  {    switch(dev->wInitStep)    {      case 5: pccard_free_irq(dev);       case 4: dev->ucActivityState = ACTIVITY_NONE; // temporary              #ifdef NETDEV_SUPPORT              pcan_netdev_unregister(dev);              #endif      case 3: pcan_drv.wDeviceCount--;              pccard_devices--;       case 2: dev->ucPhysicallyInstalled = 0;              list_del(&dev->list);      case 1:               #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)              DPRINTK(KERN_DEBUG "%s: release_region(PCCARD_PORT_SIZE)\n", DEVICE_NAME);              release_region(dev->port.pccard.dwPort, PCCARD_PORT_SIZE);              #endif      case 0: pcan_delete_filter_chain(dev->filter);              dev->filter = NULL;              dev->wInitStep = 0;              DPRINTK(KERN_DEBUG "%s: kfree(PCANDEV=0x%p)\n", DEVICE_NAME, dev);              kfree(dev);               dev = NULL;    }  }   return 0;}//****************************************************************************// interface depended open and closestatic int pccard_open(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pccard_open()\n", DEVICE_NAME);    dev->ucActivityState = ACTIVITY_IDLE;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)  dev->port.pccard.card->pcc_dev->open++;  #else  dev->port.pccard.card->link.open++;  #endif  return 0;}static int pccard_release(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pccard_release()\n", DEVICE_NAME);    dev->ucActivityState = ACTIVITY_INITIALIZED;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)  if (dev->port.pccard.card->pcc_dev->open > 0)    dev->port.pccard.card->pcc_dev->open--;  #else  if (dev->port.pccard.card->link.open > 0)    dev->port.pccard.card->link.open--;  #endif  return 0;}//****************************************************************************// create and init a single pccard pcan device structurestatic struct pcandev *pccard_create_single_device(PCAN_PCCARD *card, int nChannel, u32 dwPort, u16  wIrq){  struct pcandev *dev;  PCCARD_PORT    *p;  int err = 0;    DPRINTK(KERN_DEBUG "%s: pccard_create_single_device(%d, 0x%04x, %d)\n", DEVICE_NAME, nChannel, dwPort, wIrq);    // allocate memory for my device  if ((dev = (struct pcandev *)kmalloc(sizeof(struct pcandev), GFP_ATOMIC)) == NULL)  {    printk(KERN_ERR "%s: pccard_create_single_device - memory allocation failed!\n", DEVICE_NAME);    err = -ENOMEM;    goto fail;  }  DPRINTK(KERN_DEBUG "%s: kmalloc() = 0x%p\n", DEVICE_NAME, dev);  memset(dev, 0x00, sizeof(*dev));  dev->wInitStep = 0;  // init structure elements to defaults  pcan_soft_init(dev, "pccard", HW_PCCARD);  // device handling standards for sja1000 driven parts  dev->device_open      = sja1000_open;  dev->device_release   = sja1000_release;  dev->device_write     = sja1000_write;  #ifdef NETDEV_SUPPORT  dev->netdevice_write  = sja1000_write_frame;  #endif    // init process wait queues  init_waitqueue_head(&dev->read_queue);  init_waitqueue_head(&dev->write_queue);      // set this before any instructions, fill struct pcandev, part 1   dev->readreg     = pccard_readreg;  dev->writereg    = pccard_writereg;  dev->cleanup     = pccard_cleanup;  dev->req_irq     = pccard_req_irq;  dev->free_irq    = pccard_free_irq;  dev->open        = pccard_open;  dev->release     = pccard_release;  dev->nMinor      = PCCARD_MINOR_BASE + pccard_devices;   dev->filter      = pcan_create_filter_chain();    dev->props.ucExternalClock = 1;  dev->props.ucMasterDevice  = (nChannel) ? CHANNEL_SLAVE : CHANNEL_MASTER;             // reject illegal combination  if (!dwPort || !wIrq)  {    err = -EINVAL;    goto fail;  }    // fill struct pcandev, hardware specfic parts  p           = &dev->port.pccard;  p->dwPort   = dwPort;  p->wIrq     = wIrq;  p->nChannel = nChannel;  p->card     = card;  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)  // allocating io resources  DPRINTK(KERN_DEBUG "%s: ___request_region(PCCARD_PORT_SIZE)\n", DEVICE_NAME);  err = ___request_region(dev->port.pccard.dwPort, PCCARD_PORT_SIZE, DEVICE_NAME);  if (err)    goto fail;  #endif  dev->wInitStep = 1;  // base init of hardware - reset channel  pccard_channel_reset(card, nChannel);     // probe hardware  if ((err = sja1000_probe(dev)))    goto fail;      // add into list of devices and assign the device as plugged in  dev->ucPhysicallyInstalled = 1;  list_add_tail(&dev->list, &pcan_drv.devices);  // add this device to the list         dev->wInitStep = 2;    // increment device counts  pcan_drv.wDeviceCount++;  pccard_devices++;   dev->wInitStep = 3;      dev->ucActivityState = ACTIVITY_INITIALIZED;  dev->wInitStep = 4;    printk(KERN_INFO "%s: pccard device minor %d found\n", DEVICE_NAME, dev->nMinor);  return dev;  fail:  pccard_cleanup(dev);  DPRINTK(KERN_INFO "%s: pccard_create_single_device(%d) failed! (%d)\n", DEVICE_NAME, nChannel, err);    return NULL;}//****************************************************************************// allocate resources and common io area and initialize hardware of devicesint pccard_create_all_devices(PCAN_PCCARD *card){  int err = 0;    DPRINTK(KERN_DEBUG "%s: pccard_create_all_devices()\n", DEVICE_NAME);      if (card)  {    int    chn  = 0;    struct pcandev *dev;    int    i;        // fill card structure    card->commonPort = card->basePort + PCCARD_COMMON;      #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)    // request commonly used io area        DPRINTK(KERN_DEBUG "%s: ___request_region(PCCARD_COMMON_SIZE)\n", DEVICE_NAME);    err = ___request_region(card->commonPort, PCCARD_COMMON_SIZE, DEVICE_NAME);    if (err)      goto fail;    #endif          // init common registers    pccard_initreg_common(card);          for (i = 0; i < PCCARD_CHANNELS; i++)    {      card->dev[i] = NULL;            // probe devices and if successfully create device structues - channel 0      dev = pccard_create_single_device(card, i, card->basePort + i * PCCARD_CHANNEL_OFF, card->commonIrq);      if (dev)       {        chn++;        card->dev[i] = dev;                #ifdef NETDEV_SUPPORT        pcan_netdev_register(dev);        #endif      }    }        // no usable channel found    if (!chn)    {      printk(KERN_ERR "%s: pccard with no channels found!\n", DEVICE_NAME);      err = -ENODEV;      goto fail;    }    // get version of hardware to log    pccard_show_firmware_version(card);        // enable power to connector    pccard_enable_CAN_power(card);      pccard_start_activity_scanner(card); // start scanning card's acitvity to control LEDs          return 0;  }    fail:  DPRINTK(KERN_DEBUG "%s: pccard_create_all_devices(%d) failed!\n", DEVICE_NAME, err);  return err;}//****************************************************************************// deinit devices and release allocted resources of devices and common io areavoid pccard_release_all_devices(PCAN_PCCARD *card){  DPRINTK(KERN_DEBUG "%s: pccard_release_all_devices(0x%p)\n", DEVICE_NAME, card);    if (card)  {    struct pcandev *dev;    int i;        pccard_stop_activity_scanner(card);  // stop scanning card's acitvity to control LEDs       if (pccard_plugged(card))       pccard_disable_CAN_power(card);    for (i = 0; i < PCCARD_CHANNELS; i++)    {      // 1. release associated devices      dev = card->dev[i];      pccard_cleanup(dev);      card->dev[i] = NULL;    }        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)    DPRINTK(KERN_DEBUG "%s: release_region(PCCARD_COMMON_SIZE)\n", DEVICE_NAME);    release_region(card->commonPort, PCCARD_COMMON_SIZE);    #endif  }}

⌨️ 快捷键说明

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