//---------------------------------------------------------------------------- // is called at user ioctl() with cmd = PCAN_INIT static 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(local))) { 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; }
int pcan_fifo_init(register FIFO_MANAGER *anchor, void *bufferBegin, void *bufferEnd, int nCount, u16 wCopySize) { anchor->wCopySize = wCopySize; anchor->wStepSize = (bufferBegin == bufferEnd) ? 0 : ((bufferEnd - bufferBegin) / (nCount - 1)); anchor->nCount = nCount; anchor->bufferBegin = bufferBegin; anchor->bufferEnd = bufferEnd; // check for fatal program errors if ((anchor->wStepSize < anchor->wCopySize) || (anchor->bufferBegin > anchor->bufferEnd) || (nCount <= 1)) return -EINVAL; INIT_LOCK(&anchor->lock); return pcan_fifo_reset(anchor); }
//---------------------------------------------------------------------------- // is called by pcan_open() and pcan_netdev_open() int pcan_open_path(PCAN_OPEN_PATH_ARGS) { int err = 0; DPRINTK(KERN_DEBUG "%s: pcan_open_path, minor = %d, path = %d.\n", DEVICE_NAME, dev->nMinor, dev->nOpenPaths); // only the 1st open to this device makes a default init on this device if (!dev->nOpenPaths) { // empty all FIFOs err = pcan_fifo_reset(&dev->writeFifo); if (err) return err; err = pcan_fifo_reset(&dev->readFifo); if (err) return err; // open the interface special parts err = dev->open(dev); if (err) { DPRINTK(KERN_DEBUG "%s: can't open interface special parts!\n", DEVICE_NAME); return err; } /* * special handling: probe here only for dongle devices, * connect after init is possible */ if ((dev->wType == HW_DONGLE_SJA) || (dev->wType == HW_DONGLE_SJA_EPP)) { err = sja1000_probe(dev); // no usb here, generic sja1000 call for dongle if (err) { DPRINTK(KERN_ERR "%s: %s-dongle device minor %d not found (io=0x%04x,irq=%d)\n", DEVICE_NAME, dev->type, dev->nMinor, dev->port.dng.dwPort, dev->port.dng.wIrq); dev->release(dev); return err; } } // install irq err = dev->req_irq(REQ_IRQ_ARG); if (err) { DPRINTK(KERN_DEBUG "%s: can't request irq from device!\n", DEVICE_NAME); return err; } // open the device itself err = dev->device_open(dev, dev->wBTR0BTR1, dev->ucCANMsgType, dev->ucListenOnly); if (err) { DPRINTK(KERN_DEBUG "%s: can't open device hardware itself!\n", DEVICE_NAME); return err; } } dev->nOpenPaths++; DPRINTK(KERN_DEBUG "%s: pcan_open_path() is OK\n", DEVICE_NAME); 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; }
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; }