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

📄 pcan_fops_linux.c

📁 linux下的CAN BUS驱动代码。适合在arm平台使用。
💻 C
📖 第 1 页 / 共 2 页
字号:
    goto fail;  }  if (copy_to_user(BTR0BTR1, &local, sizeof(*BTR0BTR1)))    err = -EFAULT;  fail:  return err;}//----------------------------------------------------------------------------// add a message filter_element into the filter chain or delete all filter_elementsint pcan_ioctl_msg_filter(struct pcandev *dev, TPMSGFILTER *filter){  TPMSGFILTER local_filter;  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_MSG_FILTER)\n", DEVICE_NAME);  // filter == NULL -> delete the filter_elements in the chain  if (!filter)  {    pcan_delete_filter_all(dev->filter);    return 0;  }  if (copy_from_user(&local_filter, filter, sizeof(local_filter)))    return -EFAULT;  return pcan_add_filter(dev->filter, local_filter.FromID, local_filter.ToID, local_filter.MSGTYPE);}//----------------------------------------------------------------------------// is called at user ioctl() callint pcan_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg){  int err;  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;  // if the device is plugged out  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  switch(cmd)  {    case PCAN_READ_MSG:      err = pcan_ioctl_read(filep, dev, (TPCANRdMsg *)arg); // support blocking and nonblocking IO      break;    case PCAN_WRITE_MSG:      err = pcan_ioctl_write(filep, dev, (TPCANMsg *)arg);  // support blocking and nonblocking IO      break;    case PCAN_GET_EXT_STATUS:      err = pcan_ioctl_extended_status(dev, (TPEXTENDEDSTATUS *)arg);      break;    case PCAN_GET_STATUS:      err = pcan_ioctl_status(dev, (TPSTATUS *)arg);      break;    case PCAN_DIAG:      err = pcan_ioctl_diag(dev, (TPDIAG *)arg);      break;    case PCAN_INIT:       err = pcan_ioctl_init(dev, (TPCANInit *)arg);      break;    case PCAN_BTR0BTR1:      err = pcan_ioctl_BTR0BTR1(dev, (TPBTR0BTR1 *)arg);      break;    case PCAN_MSG_FILTER:      err = pcan_ioctl_msg_filter(dev, (TPMSGFILTER *)arg);      break;    default:      DPRINTK(KERN_DEBUG "%s: pcan_ioctl(%d)\n", DEVICE_NAME, cmd);        err = -ENOTTY;      break;  }  // DPRINTK(KERN_DEBUG "%s: pcan_ioctl() = %d\n", DEVICE_NAME, err);  return err;}//----------------------------------------------------------------------------// is called when read from the pathstatic ssize_t pcan_read(struct file *filep, char *buf, size_t count, loff_t *f_pos){  int    err;  int    len = 0;  TPCANRdMsg msg;  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;   // DPRINTK(KERN_DEBUG "%s: pcan_read().\n", DEVICE_NAME);  // if the device is plugged out  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  if (fobj->nReadRest <= 0)  {    // support nonblocking read if requested    if ((filep->f_flags & O_NONBLOCK) && (!pcan_fifo_empty(&dev->readFifo)))      return -EAGAIN;    // sleep until data are available    err = wait_event_interruptible(dev->read_queue, (pcan_fifo_empty(&dev->readFifo)));    if (err)      return err;    // if the device is plugged out    if (!dev->ucPhysicallyInstalled)      return -ENODEV;    // get read data out of FIFO    err = pcan_fifo_get(&dev->readFifo, &msg);    if (err)      return err;    fobj->nReadRest = pcan_make_output(fobj->pcReadBuffer, &msg);    fobj->pcReadPointer = fobj->pcReadBuffer;  }  // give the data to the user  if (count > fobj->nReadRest)  {    // put all data to user    len = fobj->nReadRest;    fobj->nReadRest = 0;    if (copy_to_user(buf, fobj->pcReadPointer, len))      return -EFAULT;    fobj->pcReadPointer = fobj->pcReadBuffer;   }  else  {    // put only partial data to user    len = count;    fobj->nReadRest -= count;    if (copy_to_user(buf, fobj->pcReadPointer, len))      return -EFAULT;    fobj->pcReadPointer = (u8 *)((u8*)fobj->pcReadPointer + len);  }  *f_pos += len;  fobj->nTotalReadCount += len;  // DPRINTK(KERN_DEBUG "%s: pcan_read() is OK\n", DEVICE_NAME);  return len;}static ssize_t pcan_write(struct file *filep, const char *buf, size_t count, loff_t *f_pos){  int err = 0;   u32 dwRest;  u8 *ptr;  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;  // DPRINTK(KERN_DEBUG "%s: pcan_write().\n", DEVICE_NAME);  // if the device is plugged out  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  // calculate remaining buffer space  dwRest = WRITEBUFFER_SIZE - (fobj->pcWritePointer - fobj->pcWriteBuffer); // nRest > 0!  count  = (count > dwRest) ? dwRest : count;  if (copy_from_user(fobj->pcWritePointer, buf, count))    return -EFAULT;  // adjust working pointer to end  fobj->pcWritePointer += count;  // iterate search blocks ending with '\n'  while (1)  {    // search first '\n' from begin of buffer    ptr = fobj->pcWriteBuffer;     while ((*ptr != '\n') && (ptr < fobj->pcWritePointer))      ptr++;    // parse input when a CR was found    if ((*ptr == '\n') && (ptr < fobj->pcWritePointer))    {      u32 amount = (u32)(fobj->pcWritePointer - ptr - 1);      u32 offset = (u32)(ptr - fobj->pcWriteBuffer + 1);      if ((amount > WRITEBUFFER_SIZE) || (offset > WRITEBUFFER_SIZE))      {        #ifdef __LP64__        #warning "Compiling for __LP64__"        printk(KERN_ERR "%s: fault in pcan_write() %ld %u, %u: \n", DEVICE_NAME, count, amount, offset);        #else        printk(KERN_ERR "%s: fault in pcan_write() %d %u, %u: \n", DEVICE_NAME, count, amount, offset);        #endif        return -EFAULT;      }      if (pcan_parse_input_idle(fobj->pcWriteBuffer))      {        TPCANMsg msg;        if (pcan_parse_input_message(fobj->pcWriteBuffer, &msg))        {          TPCANInit Init;          if ((err = pcan_parse_input_init(fobj->pcWriteBuffer, &Init)))            return err;          else          {          #if 0            DPRINTK(KERN_DEBUG "%s: ***** Init 0x%04x 0x%02x 0x%02x\n", DEVICE_NAME,              Init.wBTR0BTR1, Init.ucCANMsgType, Init.ucListenOnly);          #endif            // init the associated chip and the fifos again with new parameters            err = dev->device_open(dev, Init.wBTR0BTR1, Init.ucCANMsgType, Init.ucListenOnly);            if (err)              return err;            else            {              dev->wBTR0BTR1    = Init.wBTR0BTR1;              dev->ucCANMsgType = Init.ucCANMsgType;              dev->ucListenOnly = Init.ucListenOnly;            }            err = pcan_fifo_reset(&dev->writeFifo);            if (err)              return err;            err = pcan_fifo_reset(&dev->readFifo);            if (err)              return err;          }        }        else        {          #if 0 // ------- print out message, begin -----------          int i = 0;          DPRINTK(KERN_DEBUG "%s: *** 0x%08x 0x%02x %d . ",            DEVICE_NAME, msg.ID, Message.MSGTYPE, msg.LEN);          while (i++ < Message.LEN)            DPRINTK(KERN_DEBUG "0x%02x ", msg.DATA[i]);          DPRINTK(KERN_DEBUG " ***\n");          #endif // ------- print out message, end ------------          // support nonblocking write if requested          if ((filep->f_flags & O_NONBLOCK) && (!pcan_fifo_near_full(&dev->writeFifo)) && (!atomic_read(&dev->DataSendReady)))            return -EAGAIN;          // sleep until space is available          err = wait_event_interruptible(dev->write_queue,                     (pcan_fifo_near_full(&dev->writeFifo) || atomic_read(&dev->DataSendReady)));          if (err)            return err;          // if the device is plugged out          if (!dev->ucPhysicallyInstalled)            return -ENODEV;          // filter extended data if initialized to standard only          if (!(dev->bExtended) && ((msg.MSGTYPE & MSGTYPE_EXTENDED) || (msg.ID > 2047)))            return -EINVAL;          err = pcan_fifo_put(&dev->writeFifo, &msg);          if (err)            return err;          // push a new transmission trough ioctl() only if interrupt triggered push was stalled          mb();          if (atomic_read(&dev->DataSendReady))          {            atomic_set(&dev->DataSendReady, 0);            mb();            if ((err = dev->device_write(dev)))            {              atomic_set(&dev->DataSendReady, 1);              return err;            }          }          else          {            // DPRINTK(KERN_DEBUG "%s: pushed %d items into Fifo\n", DEVICE_NAME, dev->writeFifo.nStored);          }        }      }      // move rest of amount data in buffer offset steps to left      memmove(fobj->pcWriteBuffer, ptr + 1, amount);      fobj->pcWritePointer -= offset;    }    else      break; // no CR found  }  if (fobj->pcWritePointer >= (fobj->pcWriteBuffer + WRITEBUFFER_SIZE))  {    fobj->pcWritePointer = fobj->pcWriteBuffer; // reject all    return -EFAULT;  }  // DPRINTK(KERN_DEBUG "%s: pcan_write() is OK\n", DEVICE_NAME);  return count;}//----------------------------------------------------------------------------// is called at poll or selectstatic unsigned int pcan_poll(struct file *filep, poll_table *wait){  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;  unsigned int mask = 0;  poll_wait(filep, &dev->read_queue,  wait);  poll_wait(filep, &dev->write_queue, wait);  // return on ops that could be performed without blocking  if (pcan_fifo_empty(&dev->readFifo))      mask |= (POLLIN  | POLLRDNORM);  if (pcan_fifo_near_full(&dev->writeFifo)) mask |= (POLLOUT | POLLWRNORM);  return mask;}//****************************************************************************// GLOBALS//----------------------------------------------------------------------------// this structure is used in init_module(void)struct file_operations pcan_fops ={  // marrs:  added owner, which is used to implement a use count that disallows  //         rmmod calls when the driver is still in use (as suggested by  //         Duncan Sands on the linux-kernel mailinglist)  owner:      THIS_MODULE,  open:       pcan_open,  release:    pcan_release,  read:       pcan_read,  write:      pcan_write,  ioctl:      pcan_ioctl,  poll:       pcan_poll,};// end of file

⌨️ 快捷键说明

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