]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/write.c
2f32b2ead2fb30ba9e7fdb6530ff92f3f47763c4
[lincan.git] / lincan / src / write.c
1 /* write.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.2  9 Jul 2003
8  */
9
10 #include <linux/autoconf.h>
11
12 #define __NO_VERSION__
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/delay.h>
17 #include <asm/irq.h>
18 #include <asm/uaccess.h>
19
20 #include "../include/main.h"
21
22 ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
23 {
24         struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
25         struct msgobj_t *obj;
26         struct canmsg_t msg_buff;
27         struct canque_ends_t *qends;
28         struct canque_edge_t *qedge;
29         struct canque_slot_t *slot;
30         int ret = 0;
31         int bytes_to_copy = 0;
32
33         if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
34                 CANMSG("can_close: bad canuser magic\n");
35                 return -ENODEV;
36         }
37
38         if (length < sizeof(struct canmsg_t)) {
39                 DEBUGMSG("Trying to write less bytes than a CAN message,\n");
40                 DEBUGMSG("this will always return 0 !\n");
41                 return 0;
42         }
43         if (length > 8 * sizeof(struct canmsg_t)) {
44                 CANMSG("Trying to write more than is supported.\n");
45                 return -1;
46         }
47         if (length % sizeof(struct canmsg_t)) {
48                 CANMSG("The number of bytes requested to be written is not a multiple of\n");
49                 CANMSG("'sizeof(struct canmsg_t)', currently this is not allowed.\n");
50                 return -1;
51         } 
52
53         /* Initialize hardware pointers */
54         obj = canuser->msgobj;
55         if (obj == NULL) {
56                 CANMSG("Could not assign buffer structure\n");
57                 return -1;
58         }
59         qends = canuser->qends;
60
61
62         /* Prepare first message */
63         copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
64         /* Automatic selection of extended format if "extended" set and ID>2047 */
65         if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT;
66
67         /* If the output buffer is full, return immediately in case O_NONBLOCK
68          * has been specified or loop until space becomes available.
69          */
70         if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
71                         0, msg_buff.id, 0))<0){
72                 DEBUGMSG("Buffer is full\n");
73                 if (file->f_flags & O_NONBLOCK)
74                         return -EAGAIN;
75                 if(ret < -1)
76                         return -EIO;
77
78                 ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot, 
79                                                 0, msg_buff.id, 0);
80                 if(ret<0) {
81                         if (signal_pending(current))
82                                 return -EINTR;
83                         /*if (!can_timeout)*/
84                         return -EIO;
85                 }
86         }
87         slot->msg=msg_buff;
88         canque_put_inslot(qends, qedge, slot);
89         buffer += sizeof(struct canmsg_t);
90         bytes_to_copy = length-sizeof(struct canmsg_t);
91
92         /* 
93          * Try to send more messages
94          */
95         while (bytes_to_copy > 0) {
96                 /* Prepare first message */
97                 copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
98                 /* Automatic selection of extended format if "extended" set and ID>2047 */
99                 if (extended) if (msg_buff.id & ~0x7ffl ) msg_buff.flags |= MSG_EXT;
100                 /* Get slot */
101                 if(canque_get_inslot4id(qends, &qedge, &slot, 
102                         0, msg_buff.id, 0) < 0) break;
103                 slot->msg=msg_buff;
104                 canque_put_inslot(qends, qedge, slot);
105                 buffer += sizeof(struct canmsg_t);
106                 bytes_to_copy -= sizeof(struct canmsg_t);
107         }
108
109         if(file->f_flags & O_SYNC) {
110                 canque_sync_wait_kern(qends, qedge);
111         }
112         return length-bytes_to_copy;
113 }