Added support for Unicontrols PCI CAN card.
[lincan.git] / lincan / src / write_rtl.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 #ifdef CAN_WITH_RTL
11
12 #include "../include/can.h"
13 #include "../include/can_sysdep.h"
14 #include "../include/main.h"
15
16 #include <rtl_posixio.h>
17 #include "../include/can_iortl.h"
18
19 ssize_t can_write_rtl_posix(struct rtl_file *fptr, const char *buffer,
20                                  size_t length, loff_t *ppos)
21 {
22         struct canuser_t *canuser =
23                 (struct canuser_t *)can_get_rtl_file_private_data(fptr);
24         const struct canmsg_t *msg_buff = (struct canmsg_t *)buffer;
25         struct canque_ends_t *qends;
26         struct canque_edge_t *qedge;
27         struct canque_slot_t *slot;
28         int      msg_flags;
29         int      ret;
30         size_t   bytes_to_copy;
31
32         if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
33                 CANMSG("can_write_rtl_posix: bad canuser magic\n");
34                 return -ENODEV;
35         }
36
37         if (length < sizeof(struct canmsg_t)) {
38                 DEBUGMSG("Trying to write less bytes than a CAN message,\n");
39                 DEBUGMSG("this will always return 0 !\n");
40                 return 0;
41         }
42         if (length > INT_MAX) {
43                 CANMSG("Trying to write more than is supported.\n");
44                 return -1;
45         }
46
47         qends = canuser->qends;
48
49         msg_flags=msg_buff->flags;
50
51         /* Automatic selection of extended format if ID>2047 */
52         if (msg_buff->id & ~0x7ffl & MSG_ID_MASK ) msg_flags |= MSG_EXT;
53         /* has been dependent on "extended" option */
54
55         /* If the output buffer is full, return immediately in case O_NONBLOCK
56          * has been specified or loop until space becomes available.
57          */
58         if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
59                         0, msg_buff->id, 0))<0){
60                 DEBUGMSG("Buffer is full\n");
61                 if(ret < -1)
62                         return -EIO;
63
64                 if (fptr->f_flags & O_NONBLOCK)
65                         return -EAGAIN;
66
67                 ret=canque_get_inslot4id_wait_rtl(qends, &qedge, &slot, 
68                                                 0, msg_buff->id, 0);
69                 if (ret == -1)
70                         return -EINTR;
71                 
72                 if(ret<0) {
73                         return -EIO;
74                 }
75         }
76         slot->msg=*(msg_buff++);
77         slot->msg.flags=msg_flags;
78         canque_put_inslot(qends, qedge, slot);
79         bytes_to_copy = length-sizeof(struct canmsg_t);
80
81         /* 
82          * Try to send more messages
83          */
84         while (bytes_to_copy >= sizeof(struct canmsg_t)) {
85                 bytes_to_copy -= sizeof(struct canmsg_t);
86                 msg_flags=msg_buff->flags;
87
88                 /* Automatic selection of extended format if ID>2047 */
89                 if (msg_buff->id & ~0x7ffl & MSG_ID_MASK ) msg_flags |= MSG_EXT;
90                 /* has been dependent on "extended" option */
91
92                 /* Get slot */
93                 if(canque_get_inslot4id(qends, &qedge, &slot, 
94                         0, msg_buff->id, 0) < 0) break;
95                 slot->msg=*(msg_buff++);
96                 slot->msg.flags=msg_flags;
97                 canque_put_inslot(qends, qedge, slot);
98         }
99
100         if(fptr->f_flags & O_SYNC) {
101                 canque_sync_wait_rtl(qends, qedge);
102         }
103         return length-bytes_to_copy;
104 }       
105
106 #endif /*CAN_WITH_RTL*/