📄 pcan_fops.c
字号:
}//----------------------------------------------------------------------------// 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 + -