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

📄 pcan_fops.c

📁 CAN 驱动编程
💻 C
📖 第 1 页 / 共 2 页
字号:
}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_DIAG static int pcan_ioctl_diag(struct pcandev *dev, TPDIAG *diag){  int err = 0; 	TPDIAG local;	  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_DIAG)\n", DEVICE_NAME);	local.wType           = dev->wType;	switch (dev->wType)	{	  case HW_ISA_SJA:		  local.dwBase      = dev->port.isa.dwPort;      local.wIrqLevel   = dev->port.isa.wIrq;		  break;		case HW_DONGLE_SJA:		case HW_DONGLE_SJA_EPP:		  local.dwBase      = dev->port.dng.dwPort;      local.wIrqLevel   = dev->port.dng.wIrq;			break;		case HW_PCI:		  local.dwBase      = dev->port.pci.dwPort;      local.wIrqLevel   = dev->port.pci.wIrq;      break;    case HW_USB:      #ifdef USB_SUPPORT      if (pcan_usb_getSerialNumber(dev))        local.dwBase    = 0;      else        local.dwBase    = dev->port.usb.dwSerialNumber;        local.wIrqLevel = dev->port.usb.ucHardcodedDevNr;      #endif			break;	}   local.dwReadCounter   = dev->readFifo.dwTotal;  local.dwWriteCounter  = dev->writeFifo.dwTotal;  local.dwIRQcounter    = dev->dwInterruptCounter;  local.dwErrorCounter  = dev->dwErrorCounter;  local.wErrorFlag      = dev->wCANStatus;  	// get infos for friends of polling operation  if (!pcan_fifo_empty(&dev->readFifo))    local.wErrorFlag |= CAN_ERR_QRCVEMPTY;      if (!pcan_fifo_near_full(&dev->writeFifo))  	local.wErrorFlag |= CAN_ERR_QXMTFULL;	  local.nLastError      = dev->nLastError;  local.nOpenPaths      = dev->nOpenPaths;	strncpy(local.szVersionString, pcan_drv.szVersionString, VERSIONSTRING_LEN);	if (copy_to_user(diag, &local, sizeof(local)))		err = -EFAULT;		return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_INIT int pcan_ioctl_init(struct pcandev *dev, TPCANInit *Init){  int err = 0;	TPCANInit local;	  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_INIT)\n", DEVICE_NAME);	if (copy_from_user(&local, Init, sizeof(*Init)))	{		err = -EFAULT;		goto fail;	}	  // flush fifo contents  err = pcan_fifo_reset(&dev->writeFifo);  if (err)    goto fail;  err = pcan_fifo_reset(&dev->readFifo);  if (err)    goto fail;  // wait until fifo is empty or MAX_WAIT_UNTIL_CLOSE time is elapsed  wait_until_fifo_empty(dev, MAX_WAIT_UNTIL_CLOSE);  // release the device   dev->device_release(dev);  // init again  err = dev->device_open(dev, local.wBTR0BTR1, local.ucCANMsgType, local.ucListenOnly);    if (!err)  {  	dev->wBTR0BTR1    = local.wBTR0BTR1;	  dev->ucCANMsgType = local.ucCANMsgType;	  dev->ucListenOnly = local.ucListenOnly;	}      fail:  return err;}//----------------------------------------------------------------------------// get BTR0BTR1 init valuesstatic int pcan_ioctl_BTR0BTR1(struct pcandev *dev, TPBTR0BTR1 *BTR0BTR1){  int err = 0;	TPBTR0BTR1 local;	  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_BTR0BTR1)\n", DEVICE_NAME);  	if (copy_from_user(&local, BTR0BTR1, sizeof(local)))	{		err = -EFAULT;		goto fail;	}	  // this does not influence hardware settings, only BTR0BTR1 values are calculated	local.wBTR0BTR1 = sja1000_bitrate(local.dwBitRate);		if (!local.wBTR0BTR1)	{		err = -EFAULT;		goto fail;	}			if (copy_to_user(BTR0BTR1, &local, sizeof(*BTR0BTR1)))		err = -EFAULT;   fail:  return err;} //----------------------------------------------------------------------------// is called at user ioctl() call static int 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_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;        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;  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;   int    len = 0;  TPCANRdMsg *m;  TPCANRdMsg Message;  // 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;    // nothing in buffer, get new data out of fifo		err = pcan_fifo_claim_for_get(&dev->readFifo, (void *)&m);		if (err)		  return err;		// signal a pending status		if (dev->wCANStatus)			m->Msg.MSGTYPE |= MSGTYPE_STATUS;			    		memcpy(&Message, m, sizeof(*m));				// free fifo		err = pcan_fifo_get(&dev->readFifo);		if (err)			return err;			    fobj->nReadRest = pcan_make_output(fobj->pcReadBuffer, &Message);    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;}//----------------------------------------------------------------------------// is called when written to the pathstatic ssize_t pcan_write(struct file *filep, const char *buf, size_t count, loff_t *f_pos){  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev  = fobj->dev;   int err = 0;   u32 dwRest;  u8 *ptr;  TPCANInit Init;  TPCANMsg Message;      // 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))	    {        printk(KERN_ERR "%s: fault in pcan_write() %u %u, %u: \n", DEVICE_NAME, count, amount, offset);	      return -EFAULT;	    }        if (pcan_parse_input_idle(fobj->pcWriteBuffer))      {        if (pcan_parse_input_message(fobj->pcWriteBuffer, &Message))        {	        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	      {	        TPCANMsg *m;				      #if 0 // ------- print out message, begin -----------	        int i = 0;			        DPRINTK(KERN_DEBUG "%s: *** 0x%08x 0x%02x %d . ",	          DEVICE_NAME, Message.ID, Message.MSGTYPE, Message.LEN);	      	        while (i++ < Message.LEN)	          DPRINTK(KERN_DEBUG "0x%02x ", Message.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) && ((Message.MSGTYPE & MSGTYPE_EXTENDED) || (Message.ID > 2047)))		        return -EINVAL;      		      // put message into write FIFO		      err = pcan_fifo_claim_for_put(&dev->writeFifo, (void *)&m);		      if (err)		        return err;						    memcpy(m, &Message, sizeof(*m));			    			    err = pcan_fifo_put(&dev->writeFifo);			    if (err)			      return err;			      			    // pull new transmission			    if (atomic_read(&dev->DataSendReady))			    {  			    atomic_set(&dev->DataSendReady, 0);			      if ((err = dev->device_write(dev)))			      {  			      atomic_set(&dev->DataSendReady, 1);			        return err;			      }			    }			    else          {			      // DPRINTK(KERN_DEBUG "%s: pushed %d item 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 = {  open:       pcan_open,  release:    pcan_release,  read:       pcan_read,  write:      pcan_write,  ioctl:      pcan_ioctl,  poll:       pcan_poll,};

⌨️ 快捷键说明

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