--- /dev/null
+/* write.c
+ * Linux CAN-bus device driver.
+ * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * This software is released under the GPL-License.
+ * Version 0.7 6 Aug 2001
+ */
+
+#include <linux/autoconf.h>
+#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
+#define MODVERSIONS
+#endif
+
+#if defined (MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "../include/main.h"
+
+ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
+{
+ struct msgobj_t *obj;
+ struct chip_t *chip;
+ struct canmsg_t *write_msg;
+ struct canfifo_t *fifo;
+ int ret = 0;
+ int space = 0;
+ int written = 0;
+ int bytes_to_copy = 0;
+ long can_timeout = 1;
+
+ if (length < sizeof(struct canmsg_t)) {
+ DEBUGMSG("Trying to write less bytes than a CAN message,\n");
+ DEBUGMSG("this will always return 0 !\n");
+ return 0;
+ }
+ if (length > 8 * sizeof(struct canmsg_t)) {
+ CANMSG("Trying to write more than is supported.\n");
+ return -1;
+ }
+ if (length % sizeof(struct canmsg_t)) {
+ CANMSG("The number of bytes requested to be written is not a multiple of\n");
+ CANMSG("'sizeof(struct canmsg_t)', currently this is not allowed.\n");
+ return -1;
+ }
+
+ /* Initialize hardware pointers */
+ if ( (obj = objects_p[MINOR_NR]) == NULL) {
+ CANMSG("Could not assign buffer structure\n");
+ return -1;
+ }
+ if ( (chip = obj->hostchip) == NULL) {
+ CANMSG("Device is not correctly configured,\n");
+ CANMSG("please reload the driver\n");
+ return -1;
+ }
+ if ( (fifo = obj->fifo) == NULL) {
+ CANMSG("Could not assign buffer memory\n");
+ return -1;
+ }
+
+ /* Initialize pointer to the first message to be sent */
+ write_msg = fifo->tx_writep;
+
+ /* Calculate free buffer space */
+ cli();
+ space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ?
+ ((int)fifo->tx_readp - (int)fifo->tx_writep) :
+ ((int)fifo->tx_readp - (int)fifo->tx_writep +
+ (int)fifo->tx_size);
+ sti();
+
+ /* If the output buffer is full, return immediately in case O_NONBLOCK
+ * has been specified or loop until space becomes available.
+ */
+ while (space < sizeof(struct canmsg_t)) {
+ DEBUGMSG("Buffer is full\n");
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ can_timeout = interruptible_sleep_on_timeout(&fifo->writeq,
+ CANTIMEOUT);
+ if (signal_pending(current))
+ return -EINTR;
+ if (!can_timeout)
+ return -EIO;
+ cli();
+ space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ?
+ ((int)fifo->tx_readp - (int)fifo->tx_writep) :
+ ((int)fifo->tx_readp - (int)fifo->tx_writep +
+ (int)fifo->tx_size);
+ sti();
+ }
+
+ /* There's space available in the kernel output buffer.
+ * Find out wich is smaller: 'length', the number of bytes requested to
+ * be written or 'space', the number of bytes available in the kernel
+ * buffer. We copy the least of the two to kernel space.
+ */
+// space = space - (space % sizeof(struct canmsg_t)); // round it
+ bytes_to_copy = space < length ? space : length;
+ copy_from_user(fifo->tx_writep, buffer, bytes_to_copy);
+ written = bytes_to_copy;
+ while (bytes_to_copy > 0) {
+ fifo->tx_writep++;
+ if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
+ fifo->tx_writep = fifo->buf_tx_entry;
+ bytes_to_copy -= sizeof(struct canmsg_t);
+ }
+
+ /* Copy the data to be transmitted into the output buffer */
+/* while ( (written < length) && (space >= sizeof(struct canmsg_t)) ) {
+ copy_from_user(fifo->tx_writep,buffer, sizeof(struct canmsg_t));
+ cli();
+ fifo->tx_writep++;
+ if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
+ fifo->tx_writep = fifo->buf_tx_entry;
+ buffer += sizeof(struct canmsg_t);
+ written += sizeof(struct canmsg_t);
+ space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ?
+ ((int)fifo->tx_readp - (int)fifo->tx_writep) :
+ ((int)fifo->tx_readp - (int)fifo->tx_writep +
+ (int)fifo->tx_size);
+ sti();
+ } */
+
+ /* Initiate transmission in case we are not already transmitting */
+ cli();
+ if (!fifo->tx_in_progress) {
+ fifo->tx_in_progress = 1;
+ sti();
+ if ( (ret = chip->chipspecops->pre_write_config(chip, obj,
+ write_msg)) < 0) {
+ CANMSG("Error initializing hardware for sending\n");
+ return -EIO;
+ }
+ obj->ret = 0;
+ if ( (ret = chip->chipspecops->send_msg(chip, obj,
+ write_msg)) < 0) {
+ CANMSG("Error sending message\n");
+ return -EIO;
+ }
+ /* If O_SYNC is specified wait for successfull transmission */
+/* while (1) {
+ cli();
+ if ( (!file->f_flags & O_SYNC) ||
+ (!fifo->tx_in_progress)) {
+ sti();
+ if (obj->ret < 0)
+ return obj->ret;
+ else
+ return written;
+ }
+ cli();
+ if (fifo->tx_in_progress) {
+ can_timeout = interruptible_sleep_on_timeout(
+ &fifo->writeq, CANTIMEOUT);
+ }
+ sti();
+ if (signal_pending(current))
+ return -EINTR;
+ if (!can_timeout)
+ return -EIO;
+ } */
+ }
+ sti();
+
+ return written;
+}