]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/write.c
The LinCAN driver license unified according to DCE FEE CTU head and superiors request.
[lincan.git] / lincan / src / write.c
1 /**************************************************************************/
2 /* File: write.c - systemcall to send messages through driver FIFOs       */
3 /*                                                                        */
4 /* LinCAN - (Not only) Linux CAN bus driver                               */
5 /* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz>   */
6 /* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz>             */
7 /* Funded by OCERA and FRESCOR IST projects                               */
8 /* Based on CAN driver code by Arnaud Westenberg <arnaud@wanadoo.nl>      */
9 /*                                                                        */
10 /* LinCAN is free software; you can redistribute it and/or modify it      */
11 /* under terms of the GNU General Public License as published by the      */
12 /* Free Software Foundation; either version 2, or (at your option) any    */
13 /* later version.  LinCAN is distributed in the hope that it will be      */
14 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
15 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
16 /* General Public License for more details. You should have received a    */
17 /* copy of the GNU General Public License along with LinCAN; see file     */
18 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
19 /* Cambridge, MA 02139, USA.                                              */
20 /*                                                                        */
21 /* To allow use of LinCAN in the compact embedded systems firmware        */
22 /* and RT-executives (RTEMS for example), main authors agree with next    */
23 /* special exception:                                                     */
24 /*                                                                        */
25 /* Including LinCAN header files in a file, instantiating LinCAN generics */
26 /* or templates, or linking other files with LinCAN objects to produce    */
27 /* an application image/executable, does not by itself cause the          */
28 /* resulting application image/executable to be covered by                */
29 /* the GNU General Public License.                                        */
30 /* This exception does not however invalidate any other reasons           */
31 /* why the executable file might be covered by the GNU Public License.    */
32 /* Publication of enhanced or derived LinCAN files is required although.  */
33 /**************************************************************************/
34
35 #include "../include/can.h"
36 #include "../include/can_sysdep.h"
37 #include "../include/main.h"
38 #include "../include/write.h"
39
40 ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
41 {
42         struct canuser_t *canuser = (struct canuser_t*)(file->private_data);
43         struct msgobj_t *obj;
44         struct canmsg_t msg_buff;
45         struct canque_ends_t *qends;
46         struct canque_edge_t *qedge;
47         struct canque_slot_t *slot;
48         int ret;
49         unsigned bytes_to_copy;
50
51         if(!canuser || (canuser->magic != CAN_USER_MAGIC)){
52                 CANMSG("can_write: bad canuser magic\n");
53                 return -ENODEV;
54         }
55
56         if (length < sizeof(struct canmsg_t)) {
57                 DEBUGMSG("Trying to write less bytes than a CAN message,\n");
58                 DEBUGMSG("this will always return 0 !\n");
59                 return 0;
60         }
61         if (length > INT_MAX) {
62                 CANMSG("Trying to write more than is supported.\n");
63                 return -1;
64         }
65         if (length % sizeof(struct canmsg_t)) {
66                 CANMSG("The number of bytes requested to be written is not a multiple of\n");
67                 CANMSG("'sizeof(struct canmsg_t)', currently this is not allowed.\n");
68                 return -1;
69         } 
70
71         /* Initialize hardware pointers */
72         obj = canuser->msgobj;
73         if (obj == NULL) {
74                 CANMSG("Could not assign buffer structure\n");
75                 return -1;
76         }
77         qends = canuser->qends;
78
79
80         /* Prepare first message */
81         ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
82         if(ret) return -EFAULT;
83
84         /* Automatic selection of extended format if ID>2047 */
85         if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
86         /* has been dependent on "extended" option */
87
88         /* If the output buffer is full, return immediately in case O_NONBLOCK
89          * has been specified or loop until space becomes available.
90          */
91         if ((ret=canque_get_inslot4id(qends, &qedge, &slot, 
92                         0, msg_buff.id, 0))<0){
93                 DEBUGMSG("Buffer is full\n");
94                 if(ret < -1)
95                         return -EIO;
96
97                 if (file->f_flags & O_NONBLOCK)
98                         return -EAGAIN;
99
100                 ret=canque_get_inslot4id_wait_kern(qends, &qedge, &slot, 
101                                                 0, msg_buff.id, 0);
102                 if(ret<0) {
103                         if (signal_pending(current))
104                                 return -EINTR;
105                         /*if (!can_timeout)*/
106                         return -EIO;
107                 }
108         }
109         slot->msg=msg_buff;
110         canque_put_inslot(qends, qedge, slot);
111         buffer += sizeof(struct canmsg_t);
112         bytes_to_copy = length-sizeof(struct canmsg_t);
113
114         /* 
115          * Try to send more messages
116          */
117         while (bytes_to_copy >= sizeof(struct canmsg_t)) {
118                 bytes_to_copy -= sizeof(struct canmsg_t);
119                 /* Prepare first message */
120                 ret = copy_from_user(&msg_buff, buffer, sizeof(struct canmsg_t));
121                 if(ret) return -EFAULT;
122
123                 /* Automatic selection of extended format if ID>2047 */
124                 if (msg_buff.id & ~0x7ffl & MSG_ID_MASK ) msg_buff.flags |= MSG_EXT;
125                 /* has been dependent on "extended" option */
126
127                 /* Get slot */
128                 if(canque_get_inslot4id(qends, &qedge, &slot, 
129                         0, msg_buff.id, 0) < 0) break;
130                 slot->msg=msg_buff;
131                 canque_put_inslot(qends, qedge, slot);
132                 buffer += sizeof(struct canmsg_t);
133         }
134
135         if(file->f_flags & O_SYNC) {
136                 canque_sync_wait_kern(qends, qedge);
137         }
138         return length-bytes_to_copy;
139 }