📄 pcan_fops_linux.c
字号:
//****************************************************************************// Copyright (C) 2001-2007 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:// Edouard Tisserant (edouard.tisserant@lolitech.fr) XENOMAI// Laurent Bessard (laurent.bessard@lolitech.fr) XENOMAI// Oliver Hartkopp (oliver.hartkopp@volkswagen.de) socketCAN// // Contributions: Marcel Offermans (marcel.offermans@luminis.nl)// Arno (a.vdlaan@hccnet.nl)// John Privitera (JohnPrivitera@dciautomation.com)//****************************************************************************//****************************************************************************//// pcan_fops_linux.c - all file operation functions, exports only struct fops//// $Id: pcan_fops_linux.c $////****************************************************************************#define PCAN_OPEN_PATH_ARGS struct pcandev *dev#define PCAN_RELEASE_PATH_ARGS struct pcandev *dev#define REQ_IRQ_ARG dev#define WAIT_UNTIL_FIFO_EMPTY() wait_until_fifo_empty(dev, MAX_WAIT_UNTIL_CLOSE)//****************************************************************************// 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; int err = 0; struct fileobj *fobj = (struct fileobj *)NULL; int _minor = minor(inode->i_rdev); DPRINTK(KERN_DEBUG "%s: pcan_open(), minor = %d.\n", DEVICE_NAME, _minor); dev = pcan_search_dev(_minor); if (!dev) return -ENODEV; // create file object fobj = kmalloc(sizeof(struct fileobj), GFP_KERNEL); if (!fobj) { DPRINTK(KERN_DEBUG "%s: can't allocate kernel memory!\n", DEVICE_NAME); return -ENOMEM; } // 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; err = pcan_open_path(dev); if (err && fobj) /* oops */ kfree(fobj); return err;}static 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; pcan_release_path(dev); kfree(fobj); } return 0;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_READ_MSGstatic int pcan_ioctl_read(struct file *filep, struct pcandev *dev, TPCANRdMsg *usr){ int err = 0; TPCANRdMsg msg; // 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 data out of fifo err = pcan_fifo_get(&dev->readFifo, (void *)&msg); if (err){ goto fail; } if (copy_to_user(usr, &msg, sizeof(*usr))) err = -EFAULT; fail: return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_WRITE_MSGstatic int pcan_ioctl_write(struct file *filep, struct pcandev *dev, TPCANMsg *usr){ int err = 0; TPCANMsg msg; // 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; // get from user space if (copy_from_user(&msg, usr, sizeof(msg))) { err = -EFAULT; goto fail; } // filter extended data if initialized to standard only if (!(dev->bExtended) && ((msg.MSGTYPE & MSGTYPE_EXTENDED) || (msg.ID > 2047))) { err = -EINVAL; goto fail; } // put data into fifo err = pcan_fifo_put(&dev->writeFifo, &msg); if (!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(); err = dev->device_write(dev); if (err) atomic_set(&dev->DataSendReady, 1); } else { // DPRINTK(KERN_DEBUG "%s: pushed %d items into Fifo\n", DEVICE_NAME, dev->writeFifo.nStored); } } fail: return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_GET_EXT_STATUS int pcan_ioctl_extended_status(struct pcandev *dev, TPEXTENDEDSTATUS *status){ int err = 0; TPEXTENDEDSTATUS local; DPRINTK(KERN_DEBUG "%s: pcan_ioctl(PCAN_GET_EXT_STATUS)\n", DEVICE_NAME); local = pcan_ioctl_extended_status_common(dev); if (copy_to_user(status, &local, sizeof(local))) { err = -EFAULT; goto fail; } dev->wCANStatus = 0; dev->nLastError = 0; fail: return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_GET_STATUSstatic 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 = pcan_ioctl_status_common(dev); if (copy_to_user(status, &local, sizeof(local))) { err = -EFAULT; goto fail; } dev->wCANStatus = 0; dev->nLastError = 0; fail: return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_DIAGstatic 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 = pcan_ioctl_diag_common(dev); if (copy_to_user(diag, &local, sizeof(local))) err = -EFAULT; return err;}//----------------------------------------------------------------------------// is called at user ioctl() with cmd = PCAN_INIT static 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(local))) { 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -