/* * 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 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, !dev->ucPhysicallyInstalled || !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_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; }
/* * is called when read from the path */ static 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); /* check whether this device is always linked. */ if (!pcan_is_device_in_list(dev)) return -ENODEV; /* 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, !dev->ucPhysicallyInstalled || !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; }