Exemplo n.º 1
0
//----------------------------------------------------------------------------
// 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;
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
//----------------------------------------------------------------------------
// 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;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
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;
}