📄 pcan_fops_linux.c
字号:
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 + -