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

📄 pcan_usb.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 2 页
字号:
//****************************************************************************// Copyright (C) 2003-2008  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://                Oliver Hartkopp   (oliver.hartkopp@volkswagen.de) socketCAN//                     // Contributions: Philipp Baer (philipp.baer@informatik.uni-ulm.de)//                Tom Heinrich//                John Privitera (JohnPrivitera@dciautomation.com)//****************************************************************************//****************************************************************************//// pcan_usb.c - the outer usb parts for pcan-usb support//// $Id: pcan_usb.c 534 2008-02-04 21:34:07Z khitschler $////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h>     // must always be the 1st include#include <linux/stddef.h>        // NULL#include <linux/errno.h>#include <linux/slab.h>          // kmalloc()#include <linux/module.h>        // MODULE_DEVICE_TABLE()#include <linux/usb.h>#include <src/pcan_main.h>#include <src/pcan_fops.h>#include <src/pcan_usb.h>#include <src/pcan_usb_kernel.h>#include <src/pcan_filter.h>#ifdef NETDEV_SUPPORT#include <src/pcan_netdev.h>     // for hotplug pcan_netdev_(un)register()#endif//****************************************************************************// DEFINES#define PCAN_USB_MINOR_BASE 32           // starting point of minors for USB devices#define PCAN_USB_VENDOR_ID  0x0c72#define PCAN_USB_PRODUCT_ID 0x000c#define URB_READ_BUFFER_SIZE      1024   // buffer for read URB data (IN)#define URB_READ_BUFFER_SIZE_OLD    64   // used length for revision < 7#define URB_WRITE_BUFFER_SIZE      128   // buffer for write URB (OUT)#define URB_WRITE_BUFFER_SIZE_OLD   64   // used length for hardware < 7#define MAX_CYCLES_TO_WAIT_FOR_RELEASE 100  // max no. of schedules before release#define STARTUP_WAIT_TIME            2   // wait this time at startup to get first messages//****************************************************************************// GLOBALSstatic struct usb_device_id pcan_usb_ids[] ={  { USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID) },  { }            // Terminating entry};MODULE_DEVICE_TABLE (usb, pcan_usb_ids);#ifdef LINUX_26static struct usb_class_driver pcan_class ={  .name = "usb/pcan%d",  .fops = &pcan_fops,  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)  .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,  #endif  .minor_base = PCAN_USB_MINOR_BASE,};#endif//****************************************************************************// LOCALSstatic u16 usb_devices = 0;        // the number of accepted usb_devices//****************************************************************************// CODE//****************************************************************************// get cyclic data from endpoint 2#ifdef LINUX_26static void pcan_usb_write_notify(struct urb *purb, struct pt_regs *pregs);#elsestatic void pcan_usb_write_notify(purb_t purb);#endifstatic int pcan_usb_write(struct pcandev *dev){  int err = 0;  USB_PORT *u = &dev->port.usb;  int nDataLength;  int m_nCurrentLength;  DPRINTK(KERN_DEBUG "%s: pcan_usb_write()\n", DEVICE_NAME);  // don't do anything with non-existent hardware  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  // improvement to control 128 bytes buffers  m_nCurrentLength    = URB_WRITE_BUFFER_SIZE_OLD;  err = pcan_hw_EncodeMessage(dev, u->pucWriteBuffer, &m_nCurrentLength);  if (err || (u->ucRevision < 7))    nDataLength = m_nCurrentLength;  else  {    m_nCurrentLength     = URB_WRITE_BUFFER_SIZE_OLD;    err = pcan_hw_EncodeMessage(dev, u->pucWriteBuffer + 64, &m_nCurrentLength);    nDataLength          = URB_WRITE_BUFFER_SIZE_OLD + m_nCurrentLength;      }    // fill the URB and submit  if (nDataLength)  {    FILL_BULK_URB(u->write_data, u->usb_dev,                  usb_sndbulkpipe(u->usb_dev, u->Endpoint[3].ucNumber),                  u->pucWriteBuffer, nDataLength, pcan_usb_write_notify, dev);    // start next urb    if ((err = __usb_submit_urb(u->write_data)))    {      dev->nLastError = err;      dev->dwErrorCounter++;       DPRINTK(KERN_ERR "%s: pcan_usb_write() can't submit! (%d)",DEVICE_NAME, err);    }    else      atomic_inc(&dev->port.usb.active_urbs);  }  // it's no error if I can't get more data but still a packet was sent  if ((err == -ENODATA) && (nDataLength))    err = 0;  return err;}#ifdef NETDEV_SUPPORTstatic int pcan_usb_write_frame(struct pcandev *dev, struct can_frame *cf){  int err = 0;  USB_PORT *u = &dev->port.usb;  int nDataLength;  int m_nCurrentLength;  DPRINTK(KERN_DEBUG "%s: %s\n", DEVICE_NAME, __FUNCTION__);  // don't do anything with non-existent hardware  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  // improvement to control 128 bytes buffers  m_nCurrentLength    = URB_WRITE_BUFFER_SIZE_OLD;  err = pcan_hw_EncodeMessage_frame(dev, cf, u->pucWriteBuffer, &m_nCurrentLength);  if (err || (u->ucRevision < 7))    nDataLength = m_nCurrentLength;  else  {    m_nCurrentLength     = URB_WRITE_BUFFER_SIZE_OLD;    err = pcan_hw_EncodeMessage_frame(dev, cf, u->pucWriteBuffer + 64, &m_nCurrentLength);    nDataLength          = URB_WRITE_BUFFER_SIZE_OLD + m_nCurrentLength;      }    // fill the URB and submit  if (nDataLength)  {    FILL_BULK_URB(u->write_data, u->usb_dev,                  usb_sndbulkpipe(u->usb_dev, u->Endpoint[3].ucNumber),                  u->pucWriteBuffer, nDataLength, pcan_usb_write_notify, dev);    // start next urb    if ((err = __usb_submit_urb(u->write_data)))    {      dev->nLastError = err;      dev->dwErrorCounter++;       DPRINTK(KERN_ERR "%s: pcan_usb_write_frame() can't submit! (%d)",DEVICE_NAME, err);    }    else      atomic_inc(&dev->port.usb.active_urbs);  }  // it's no error if I can't get more data but still a packet was sent  if ((err == -ENODATA) && (nDataLength))    err = 0;  return err;}#endif//****************************************************************************// notify functions for read and write data#ifdef LINUX_26static void pcan_usb_write_notify(struct urb *purb, struct pt_regs *pregs)#elsestatic void pcan_usb_write_notify(purb_t purb)#endif{  int err     = 0;  u16 wwakeup = 0;  struct pcandev *dev = purb->context;  // DPRINTK(KERN_DEBUG "%s: pcan_usb_write_notify() (%d)\n", DEVICE_NAME, purb->status);  // un-register outstanding urb  atomic_dec(&dev->port.usb.active_urbs);  // don't count interrupts - count packets  dev->dwInterruptCounter++;                                  // do write  if (!purb->status) // stop with first error    err = pcan_usb_write(dev);  if (err)  {   if (err == -ENODATA)     wwakeup++;   else   {     DPRINTK(KERN_DEBUG "%s: unexpected error %d from pcan_usb_write()\n", DEVICE_NAME, err);     dev->nLastError = err;     dev->dwErrorCounter++;     dev->wCANStatus |= CAN_ERR_QXMTFULL; // fatal error!   }  }  if (wwakeup)  {    atomic_set(&dev->DataSendReady, 1); // signal to write I'm ready    wake_up_interruptible(&dev->write_queue);    #ifdef NETDEV_SUPPORT    netif_wake_queue(dev->netdev);    #endif  }}#ifdef LINUX_26static void pcan_usb_read_notify(struct urb *purb, struct pt_regs *pregs)#elsestatic void pcan_usb_read_notify(purb_t purb)#endif{  int err = 0;  struct pcandev *dev = purb->context;  USB_PORT *u = &dev->port.usb;  // DPRINTK(KERN_DEBUG "%s: pcan_usb_read_notify() (%d)\n", DEVICE_NAME, purb->status);  // un-register outstanding urb  atomic_dec(&dev->port.usb.active_urbs);  // don't count interrupts - count packets  dev->dwInterruptCounter++;                                  // do interleaving read  if (!purb->status && dev->ucPhysicallyInstalled) // stop with first error  {    u8  *m_pucTransferBuffer = purb->transfer_buffer;    int m_nCurrentLength     = purb->actual_length;    // buffer interleave to increase speed    if (m_pucTransferBuffer == u->pucReadBuffer[0])    {      FILL_BULK_URB(purb, u->usb_dev,                    usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber),                    u->pucReadBuffer[1], u->wReadBufferLength, pcan_usb_read_notify, dev);    }    else    {      FILL_BULK_URB(purb, u->usb_dev,                    usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber),                    u->pucReadBuffer[0], u->wReadBufferLength, pcan_usb_read_notify, dev);    }    // start next urb    if ((err = __usb_submit_urb(purb)))    {      dev->nLastError = err;       dev->dwErrorCounter++;      printk(KERN_ERR "%s: pcan_usb_read_notify() can't submit! (%d)",DEVICE_NAME, err);    }    else      atomic_inc(&dev->port.usb.active_urbs);    do    {      err = pcan_hw_DecodeMessage(dev, m_pucTransferBuffer, m_nCurrentLength);      if (err < 0)      {        dev->nLastError = err;         dev->wCANStatus |=  CAN_ERR_QOVERRUN;        dev->dwErrorCounter++;        DPRINTK(KERN_DEBUG "%s: error %d from pcan_hw_DecodeMessage()\n", DEVICE_NAME, err);      }      m_pucTransferBuffer += 64;      m_nCurrentLength    -= 64;    } while (m_nCurrentLength > 0);  }  else  {    if (purb->status != -ENOENT)    {      printk(KERN_ERR "%s: read data stream torn off caused by ", DEVICE_NAME);      if (!dev->ucPhysicallyInstalled)        printk("device plug out!\n");      else        printk("err %d!\n", purb->status);    }  }}//****************************************************************************// usb resource allocation //static int pcan_usb_allocate_resources(struct pcandev *dev){  int err = 0;  USB_PORT *u = &dev->port.usb;  DPRINTK(KERN_DEBUG "%s: pcan_usb_allocate_resources()\n", DEVICE_NAME);  // allocate PCAN_USB_TIME data for comparison  // TODO: integrate PCAN_USB_TIME in USB_PORT  if (!u->pUSBtime)  {    if (!(u->pUSBtime = kmalloc(sizeof(PCAN_USB_TIME), GFP_ATOMIC)))    {      err = -ENOMEM;      goto fail;    }  }  dev->wInitStep = 4;  // make param URB  u->param_urb = __usb_alloc_urb(0);  if (!u->param_urb)    err = -ENOMEM;  dev->wInitStep = 5;  // allocate write buffer  if (u->ucRevision < 7)    u->pucWriteBuffer =  kmalloc(URB_WRITE_BUFFER_SIZE_OLD, GFP_ATOMIC);  else    u->pucWriteBuffer =  kmalloc(URB_WRITE_BUFFER_SIZE, GFP_ATOMIC);  if (!u->pucWriteBuffer)  {    err = -ENOMEM;    goto fail;  }  dev->wInitStep = 6;  // make write urb  u->write_data = __usb_alloc_urb(0);  if (!u->write_data)  {    err = -ENOMEM;    goto fail;  }  dev->wInitStep = 7;  // reset telegram count  u->dwTelegramCount = 0;  // allocate both read buffers for URB  u->pucReadBuffer[0] =  kmalloc(URB_READ_BUFFER_SIZE * 2, GFP_ATOMIC);  if (!u->pucReadBuffer[0])  {    err = -ENOMEM;    goto fail;  }  u->pucReadBuffer[1] = u->pucReadBuffer[0] + URB_READ_BUFFER_SIZE;  dev->wInitStep = 8;  // make read urb  u->read_data = __usb_alloc_urb(0);  if (!u->read_data)  {    err = -ENOMEM;    goto fail;  }  dev->wInitStep = 9;  // different revisions use different buffer sizes  if (u->ucRevision < 7)    u->wReadBufferLength = URB_READ_BUFFER_SIZE_OLD;  else    u->wReadBufferLength = URB_READ_BUFFER_SIZE;  fail:  return err;}//****************************************************************************// usb resource de-allocation //static int pcan_usb_free_resources(struct pcandev *dev){  int err = 0;  USB_PORT *u = &dev->port.usb;  DPRINTK(KERN_DEBUG "%s: pcan_usb_free_resources()\n", DEVICE_NAME);  // at this point no URB must be pending  // this is forced at pcan_usb_stop  switch (dev->wInitStep)  {    case 9:      // free read URB      usb_free_urb(u->read_data);    case 8:      kfree(u->pucReadBuffer[0]);    case 7:      // free write urb      usb_free_urb(u->write_data);    case 6:      kfree(u->pucWriteBuffer);    case 5:      // free param urb      usb_free_urb(u->param_urb);    case 4:      // remove PCAN_USB_TIME information      if (u->pUSBtime)      {        kfree(u->pUSBtime);        u->pUSBtime = NULL;      }      dev->wInitStep = 3;  }  return err;}//****************************************************************************// start and stop functions for CAN data IN and OUTstatic int pcan_usb_start(struct pcandev *dev){  int err = 0;  USB_PORT *u = &dev->port.usb;  DPRINTK(KERN_DEBUG "%s: pcan_usb_start(), minor = %d.\n", DEVICE_NAME, dev->nMinor);  FILL_BULK_URB(u->read_data, u->usb_dev,                usb_rcvbulkpipe(u->usb_dev, u->Endpoint[2].ucNumber),                u->pucReadBuffer[0], u->wReadBufferLength, pcan_usb_read_notify, dev);  // submit urb  if ((err = __usb_submit_urb(u->read_data)))    printk(KERN_ERR "%s: pcan_usb_start() can't submit! (%d)\n",DEVICE_NAME, err);  else    atomic_inc(&dev->port.usb.active_urbs);  return err;}static int pcan_kill_sync_urb(struct urb *urb){  int err = 0;    if (urb->status == -EINPROGRESS)  {    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)    usb_kill_urb(urb);    #else    err = usb_unlink_urb(urb);    #endif    DPRINTK(KERN_DEBUG "%s: pcan_kill_sync_urb done ...\n", DEVICE_NAME);  }    return err;}static int pcan_usb_stop(struct pcandev *dev){  int err = 0;  USB_PORT *u = &dev->port.usb;  int i = MAX_CYCLES_TO_WAIT_FOR_RELEASE;  DPRINTK(KERN_DEBUG "%s: pcan_usb_stop(), minor = %d.\n", DEVICE_NAME, dev->nMinor);  err = pcan_hw_SetCANOff(dev);  // wait until all has settled  mdelay(5);  // unlink URBs  pcan_kill_sync_urb(u->read_data);  pcan_kill_sync_urb(u->write_data);  pcan_kill_sync_urb(u->param_urb);  // wait until all urbs returned to sender  // (I hope) this should be no problem because all urb's are unlinked   while ((atomic_read(&u->active_urbs) > 0) && (i--))    schedule();  if (i <= 0)  {    DPRINTK(KERN_ERR "%s: have still active URBs: %d!\n", DEVICE_NAME, atomic_read(&u->active_urbs));  }  return err;}//****************************************************************************// remove device resources //static int pcan_usb_cleanup(struct pcandev *dev){  DPRINTK(KERN_DEBUG "%s: pcan_usb_cleanup()\n", DEVICE_NAME);  if (dev)  {    pcan_usb_free_resources(dev);    switch(dev->wInitStep)    {      case 4:               #ifdef NETDEV_SUPPORT              pcan_netdev_unregister(dev);              #endif      case 3: usb_devices--;              pcan_drv.wDeviceCount--;      case 2: list_del(&dev->list);      case 1:       case 0: pcan_delete_filter_chain(dev->filter);              dev->filter = NULL;

⌨️ 快捷键说明

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