/* write.c
* Linux CAN-bus device driver.
* Written by Arnaud Westenberg email:arnaud@wanadoo.nl
+ * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
+ * email:pisa@cmp.felk.cvut.cz
* This software is released under the GPL-License.
- * Version 0.7 6 Aug 2001
+ * Version lincan-0.3 17 Jun 2004
*/
-#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/can.h"
+#include "../include/can_sysdep.h"
#include "../include/main.h"
+#include "../include/write.h"
ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
{
+ struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
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;
+ struct canmsg_t msg_buff;
+ struct canque_ends_t *qends;
+ struct canque_edge_t *qedge;
+ struct canque_slot_t *slot;
+ int ret;
+ unsigned bytes_to_copy;
+
+ if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
+ CANMSG("can_write: bad canuser magic\n");
+ return -ENODEV;
+ }
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)) {
+ if (length > INT_MAX) {
CANMSG("Trying to write more than is supported.\n");
return -1;
}
}
/* Initialize hardware pointers */
- if ( (obj = objects_p[MINOR_NR]) == NULL) {
+ obj = canuser->msgobj;
+ if (obj == 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;
- }
+ qends = canuser->qends;
+
- /* Initialize pointer to the first message to be sent */
- write_msg = fifo->tx_writep;
+ /* Prepare first message */
+ ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
+ if(ret) return -EFAULT;
- /* 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();
+ /* Automatic selection of extended format if ID>2047 */
+ if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
+ /* has been dependent on "extended" option */
/* 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)) {
+ if ((ret=canque_get_inslot4id(qends, &qedge, &slot,
+ 0, msg_buff.id, 0))<0){
DEBUGMSG("Buffer is full\n");
+ if(ret < -1)
+ return -EIO;
+
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)
+
+ ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot,
+ 0, msg_buff.id, 0);
+ if(ret<0) {
+ 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();
+ }
}
+ slot->msg=msg_buff;
+ canque_put_inslot(qends, qedge, slot);
+ buffer += sizeof(struct canmsg_t);
+ bytes_to_copy = length-sizeof(struct canmsg_t);
- /* 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.
+ /*
+ * Try to send more messages
*/
-// 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;
+ while (bytes_to_copy >= sizeof(struct canmsg_t)) {
bytes_to_copy -= sizeof(struct canmsg_t);
- }
+ /* Prepare first message */
+ ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
+ if(ret) return -EFAULT;
- /* 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();
- } */
+ /* Automatic selection of extended format if ID>2047 */
+ if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
+ /* has been dependent on "extended" option */
- /* 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;
- } */
+ /* Get slot */
+ if(canque_get_inslot4id(qends, &qedge, &slot,
+ 0, msg_buff.id, 0) < 0) break;
+ slot->msg=msg_buff;
+ canque_put_inslot(qends, qedge, slot);
+ buffer += sizeof(struct canmsg_t);
}
- sti();
- return written;
+ if(file->f_flags & O_SYNC) {
+ canque_sync_wait_kern(qends, qedge);
+ }
+ return length-bytes_to_copy;
}