]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/write.c
The original version of Arnaud Westenberg Linux CAN-bus driver
[lincan.git] / lincan / src / write.c
diff --git a/lincan/src/write.c b/lincan/src/write.c
new file mode 100644 (file)
index 0000000..98ad046
--- /dev/null
@@ -0,0 +1,175 @@
+/* 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;
+}