//---------------------------------------------------------------------------- // is called at user ioctl() with cmd = PCAN_DIAG int pcan_ioctl_diag_common(struct pcandev *dev, TPDIAG *local) { 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: case HW_USB_FD: case HW_USB_PRO: case HW_USB_PRO_FD: #ifdef USB_SUPPORT local->dwBase = dev->port.usb.usb_if->dwSerialNumber; local->wIrqLevel = dev->port.usb.ucHardcodedDevNr; #endif break; case HW_PCCARD: #ifdef PCCARD_SUPPORT local->dwBase = dev->port.pccard.dwPort; local->wIrqLevel = dev->port.pccard.wIrq; #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_not_full(&dev->writeFifo)) local->wErrorFlag |= CAN_ERR_QXMTFULL; local->nLastError = dev->nLastError; local->nOpenPaths = dev->nOpenPaths; strncpy(local->szVersionString, pcan_drv.szVersionString, VERSIONSTRING_LEN); return 0; }
//---------------------------------------------------------------------------- // is called at user ioctl() with cmd = PCAN_GET_STATUS int pcan_ioctl_status_common(struct pcandev *dev, TPSTATUS *local) { 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_not_full(&dev->writeFifo)) local->wErrorFlag |= CAN_ERR_QXMTFULL; local->nLastError = dev->nLastError; return 0; }
//---------------------------------------------------------------------------- // is called at poll or select static 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_not_full(&dev->writeFifo)) mask |= (POLLOUT | POLLWRNORM); return mask; }
//---------------------------------------------------------------------------- // is called at user ioctl() with cmd = PCAN_GET_EXT_STATUS int pcan_ioctl_extended_status_common(struct pcandev *dev, TPEXTENDEDSTATUS *local) { local->wErrorFlag = dev->wCANStatus; local->nPendingReads = dev->readFifo.nStored; // get infos for friends of polling operation if (pcan_fifo_empty(&dev->readFifo)) local->wErrorFlag |= CAN_ERR_QRCVEMPTY; local->nPendingWrites = (dev->writeFifo.nStored + \ ((atomic_read(&dev->DataSendReady)) ? 0 : 1)); if (!pcan_fifo_not_full(&dev->writeFifo)) local->wErrorFlag |= CAN_ERR_QXMTFULL; local->nLastError = dev->nLastError; return 0; }
static int pcan_write_line(struct file *filep, u8 *ptr, size_t count) { struct fileobj *fobj = (struct fileobj *)filep->private_data; struct pcandev *dev = fobj->dev; u32 amount = (u32)(fobj->pcWritePointer - ptr - 1); u32 offset = (u32)(ptr - fobj->pcWriteBuffer + 1); int err; if ((amount > WRITEBUFFER_SIZE) || (offset > WRITEBUFFER_SIZE)) { #ifdef __LP64__ #warning "Compiling for __LP64__" #endif printk(KERN_ERR "%s: fault in pcan_write() %zu %u, %u: \n", DEVICE_NAME, count, amount, offset); return -EFAULT; } if (pcan_parse_input_idle(fobj->pcWriteBuffer)) { TPCANMsg msg; if (pcan_parse_input_message(fobj->pcWriteBuffer, &msg)) { TPCANInit Init; err = pcan_parse_input_init(fobj->pcWriteBuffer, &Init); if (err) return err; #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; 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_not_full(&dev->writeFifo)) && (!atomic_read(&dev->DataSendReady))) return -EAGAIN; /* if the device is plugged out */ if (!dev->ucPhysicallyInstalled) return -ENODEV; /* sleep until space is available */ err = wait_event_interruptible(dev->write_queue, !dev->ucPhysicallyInstalled || pcan_fifo_not_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 std 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(); err = dev->device_write(dev); if (err) { atomic_set(&dev->DataSendReady, 1); /* * ignore only if the fifo is already * empty */ if (err != -ENODATA) 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; return 0; }
/* * 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 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_not_full(&dev->writeFifo)) && (!atomic_read(&dev->DataSendReady))) return -EAGAIN; /* sleep until space is available */ err = wait_event_interruptible(dev->write_queue, !dev->ucPhysicallyInstalled || pcan_fifo_not_full(&dev->writeFifo) || atomic_read(&dev->DataSendReady)); if (err) goto fail; /* not need to wait for anything if device not plugged! */ 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); /* ignore only if the fifo is already empty */ if (err == -ENODATA) err = 0; } } else { // DPRINTK(KERN_DEBUG "%s: pushed %d items into Fifo\n", DEVICE_NAME, dev->writeFifo.nStored); } } fail: return err; }
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__" #endif printk(KERN_ERR "%s: fault in pcan_write() %zu %u, %u: \n", DEVICE_NAME, count, amount, offset); 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_not_full(&dev->writeFifo)) && (!atomic_read(&dev->DataSendReady))) return -EAGAIN; // sleep until space is available err = wait_event_interruptible(dev->write_queue, (pcan_fifo_not_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); // ignore only if the fifo is already empty if (err != -ENODATA) 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; }