コード例 #1
0
ファイル: pcan_fops_linux.c プロジェクト: kralf/libpcan
/*
 * 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;
}
コード例 #2
0
ファイル: pcan_fops_linux.c プロジェクト: kralf/libpcan
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;
}
コード例 #3
0
ファイル: pcan_fops_linux.c プロジェクト: ESE519/LemonAid
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;
}