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

📄 pcan_fops.c

📁 CAN 驱动编程
💻 C
📖 第 1 页 / 共 2 页
字号:
//****************************************************************************// Copyright (C) 2001,2002,2003  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)//****************************************************************************//****************************************************************************//// pcan_fops.c - all file operation functions, exports only struct fops//// $Log: pcan_fops.c,v $// Revision 1.30  2003/03/02 10:58:07  klaus// merged USB thread into main path//// Revision 1.29  2003/03/02 10:58:07  klaus// merged USB thread into main path//// Revision 1.28.2.27  2003/02/25 20:25:02  klaus// correction for core dump in 'receivetest -t=pci'//// Revision 1.28.2.26  2003/02/23 19:33:06  klaus// tried to fix "not possible to stop" bug//// Revision 1.28.2.25  2003/02/21 23:26:55  klaus// obfuscation for pcan_usb_kernel.c improved//// Revision 1.28.2.24  2003/02/16 16:36:16  klaus// pcan_usb_kernel.c returned to main modules//// Revision 1.28.2.23  2003/02/08 17:32:43  klaus// modified to use pcan_usb_kernel as proprietary module//// Revision 1.28.2.22  2003/02/05 23:12:19  klaus// adapted to RedHat 7.2//// Revision 1.28.2.21  2003/01/29 20:34:20  klaus// release_20030129_a and release_20030129_u released//// Revision 1.28.2.20  2003/01/29 20:34:20  klaus// release_20030129_a and release_20030129_u released//// Revision 1.28.2.19  2003/01/28 23:28:26  klaus// reorderd pcan_usb.c and pcan_usb_kernel.c, tidied up////****************************************************************************//****************************************************************************// INCLUDES#include <src/pcan_common.h>// must always be the 1st include#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>   // DPRINTK()#include <linux/slab.h>     // kmalloc()#include <linux/fs.h>       // everything...#include <linux/errno.h>    // error codes#include <linux/types.h>    // size_t#include <linux/proc_fs.h>  // proc #include <linux/fcntl.h>    // O_ACCMODE#include <linux/pci.h>      // all about pci#include <linux/capability.h> // all about restrictions#include <asm/system.h>     // cli(), *_flags#include <asm/uaccess.h>    // copy_...#include <linux/delay.h>    // mdelay()#include <linux/poll.h>     // poll() and select()#include <pcan.h>#include <src/pcan_main.h>#include <src/pcan_pci.h>#include <src/pcan_isa.h>#include <src/pcan_dongle.h>#include <src/pcan_sja1000.h>#include <src/pcan_fifo.h>#include <src/pcan_fops.h>#include <src/pcan_parse.h>#include <src/pcan_usb.h>//****************************************************************************// DEFINESMODULE_AUTHOR("klaus.hitschler@gmx.de");MODULE_DESCRIPTION("Driver for PEAK-Systems CAN interfaces.");#ifdef USB_SUPPORTMODULE_SUPPORTED_DEVICE("PCAN-ISA, PCAN-PC/104, PCAN-Dongle, PCAN-PCI, PCAN-USB");#elseMODULE_SUPPORTED_DEVICE("PCAN-ISA, PCAN-PC/104, PCAN-Dongle, PCAN-PCI");#endif#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)#ifdef USB_SUPPORTMODULE_LICENSE("Proprietary");#elseMODULE_LICENSE("GPL");#endif#endifMODULE_PARM(type, "0-8s");MODULE_PARM_DESC(type, "The type of PCAN interface (isa, sp, epp)");MODULE_PARM(io, "0-8h");MODULE_PARM_DESC(io, "The io-port address for either PCAN-ISA, PC/104 or Dongle");MODULE_PARM(irq, "0-8b");MODULE_PARM_DESC(irq, "The interrupt number for either PCAN-ISA, PC/104 or Dongle");// wait this time in msec at max after releasing the device - give fifo a chance to flush#define MAX_WAIT_UNTIL_CLOSE 1000   //****************************************************************************// GLOBALSEXPORT_NO_SYMBOLS;//****************************************************************************// LOCALS//****************************************************************************// CODE  //----------------------------------------------------------------------------// wait until write fifo is empty, max time in msecstatic void wait_until_fifo_empty(struct pcandev *dev, u32 mTime){  u32 dwStart = get_mtime();    while (!atomic_read(&dev->DataSendReady) && ((get_mtime() - dwStart) < mTime))     schedule();    // force it    atomic_set(&dev->DataSendReady, 1);} //----------------------------------------------------------------------------// is called when the path is openedstatic int pcan_open(struct inode *inode, struct file *filep){  struct pcandev *dev  = (struct pcandev *)NULL;   struct fileobj *fobj = (struct fileobj *)NULL;  struct list_head *ptr;  int    err = 0;  int minor = MINOR(inode->i_rdev);    DPRINTK(KERN_DEBUG "%s: pcan_open(), minor = %d.\n", DEVICE_NAME, minor);    // no devices in list  err = -ENODEV;  if (list_empty(&pcan_drv.devices))  {    DPRINTK(KERN_DEBUG "%s: no devices to select from!\n", DEVICE_NAME);    goto out;  }      // loop trough my devices  for (ptr = pcan_drv.devices.next; ptr != &pcan_drv.devices; ptr = ptr->next)  {    dev = (struct pcandev *)ptr;          if (dev->nMinor == minor)      break;  }    // didn't find my minor  err = -ENODEV;  if (dev->nMinor != minor)  {    DPRINTK(KERN_DEBUG "%s: didn't find my minor!\n", DEVICE_NAME);    goto out;  }  // create file object  err = -ENOMEM;  fobj = kmalloc(sizeof(struct fileobj), GFP_KERNEL);  if (!fobj)  {    DPRINTK(KERN_DEBUG "%s: can't allocate kernel memory!\n", DEVICE_NAME);    goto out;  }      // fill file object and init read and write method buffers  fobj->dev = dev;  if (filep->f_mode & FMODE_READ)  {    fobj->nReadRest = 0;    fobj->nTotalReadCount = 0;    fobj->pcReadPointer = fobj->pcReadBuffer;  }    if (filep->f_mode & FMODE_WRITE)  {    fobj->nWriteCount = 0;    fobj->pcWritePointer = fobj->pcWriteBuffer;  }      filep->private_data = (void *)fobj;    // only the first open to this device makes a default init on this device  if (!dev->nOpenPaths)  {    // empty all FIFOs		err = pcan_fifo_reset(&dev->writeFifo);		if (err)		  goto out;		  		err = pcan_fifo_reset(&dev->readFifo);		if (err)		  goto out;				  // open the interface special parts    err = dev->open(dev);    if (err)    {      DPRINTK(KERN_DEBUG "%s: can't open interface special parts!\n", DEVICE_NAME);      goto out;    }      // special handling: probe here only for dongle devices, connect after init is possible    if ((dev->wType == HW_DONGLE_SJA) || (dev->wType == HW_DONGLE_SJA_EPP))    {      err = sja1000_probe(dev); // no usb here, generic sja1000 call for dongle      if (err)      {        printk(KERN_ERR "%s: %s-dongle device minor %d not found (io=0x%04x,irq=%d)\n", DEVICE_NAME,                                   dev->type, dev->nMinor, dev->port.dng.dwPort, dev->port.dng.wIrq);        dev->release(dev);        goto out;      }    }       // install irq        err = dev->req_irq(dev);    if (err)    {      DPRINTK(KERN_DEBUG "%s: can't request irq from device!\n", DEVICE_NAME);      goto out;    }        // open the device itself    err = dev->device_open(dev, dev->wBTR0BTR1, dev->ucCANMsgType, dev->ucListenOnly);    if (err)    {      DPRINTK(KERN_DEBUG "%s: can't open device hardware itself!\n", DEVICE_NAME);      goto out;    }  }    dev->nOpenPaths++;  MOD_INC_USE_COUNT;        DPRINTK(KERN_DEBUG "%s: pcan_open() is OK\n", DEVICE_NAME);    return 0;              out:  if (fobj)    kfree(fobj);  return err;}//----------------------------------------------------------------------------// is called when the path is closedstatic int pcan_release(struct inode *inode, struct file *filep){  struct fileobj *fobj = (struct fileobj *)filep->private_data;  struct pcandev *dev;   DPRINTK(KERN_DEBUG "%s: pcan_release()\n", DEVICE_NAME);    // free the associated irq and allocated memory  if (fobj && fobj->dev)  {    dev = fobj->dev;          // if it's the last release: init the chip for non-intrusive operation    if (dev->nOpenPaths > 1)      dev->nOpenPaths--;    else    {      // 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 itself      dev->device_release(dev);      dev->release(dev);      dev->nOpenPaths = 0;            // release the interface depended irq, after this 'dev' is not valid      dev->free_irq(fobj->dev);      }          kfree(fobj);  }      MOD_DEC_USE_COUNT;    return 0;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_READ_MSG static int pcan_ioctl_read(struct file *filep, struct pcandev *dev, TPCANRdMsg *usr){  int err = 0;  TPCANRdMsg *m;  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_READ_MSG)\n", DEVICE_NAME);    // 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)		goto fail;  // if the device is plugged out  if (!dev->ucPhysicallyInstalled)    return -ENODEV;  // get new data out of fifo	err = pcan_fifo_claim_for_get(&dev->readFifo, (void *)&m);	if (err)		goto fail;			// signal a pending status	if (dev->wCANStatus)		m->Msg.MSGTYPE |= MSGTYPE_STATUS;  if (copy_to_user(usr, m, sizeof(*m)))	{	  err = pcan_fifo_get_reject(&dev->readFifo);		err = -EFAULT;		goto fail;	}			// free fifo	err = pcan_fifo_get(&dev->readFifo);		    		  fail:  return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_WRITE_MSG static int pcan_ioctl_write(struct file *filep, struct pcandev *dev, TPCANMsg *usr){  int err = 0;  TPCANMsg *m;	  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_WRITE_MSG)\n", DEVICE_NAME);  // 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)		goto fail;  // if the device is plugged out  if (!dev->ucPhysicallyInstalled)    return -ENODEV;	// put message into write FIFO	err = pcan_fifo_claim_for_put(&dev->writeFifo, (void *)&m);	if (err)		goto fail;	if (copy_from_user(m, usr, sizeof(*m)))	{		err = -EFAULT;		pcan_fifo_put_reject(&dev->writeFifo);		goto fail;	}		// filter extended data if initialized to standard only	if (!(dev->bExtended) && ((m->MSGTYPE & MSGTYPE_EXTENDED) || (m->ID > 2047)))	{		err = -EINVAL;		pcan_fifo_put_reject(&dev->writeFifo);		goto fail;	}	// free fifo	err = pcan_fifo_put(&dev->writeFifo);	if (err)		goto fail;			// pull new transmission	if (atomic_read(&dev->DataSendReady))	{  	atomic_set(&dev->DataSendReady, 0);		if ((err = dev->device_write(dev)))		{  		atomic_set(&dev->DataSendReady, 1);			goto fail;		}	}	else	{		// DPRINTK(KERN_DEBUG "%s: pushed %d item into Fifo\n", DEVICE_NAME, dev->writeFifo.nStored);  }		  fail:  return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_GET_STATUS static int pcan_ioctl_status(struct pcandev *dev, TPSTATUS *status){  int err = 0; 	TPSTATUS local;	  DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_GET_STATUS)\n", DEVICE_NAME);	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;		if (copy_to_user(status, &local, sizeof(local)))	{		err = -EFAULT;		goto fail;	}	dev->wCANStatus = 0;	dev->nLastError = 0;		fail:	return err;

⌨️ 快捷键说明

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