/* * 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 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; }
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; }