]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/write.c
The first enhanced version of Linux CAN-bus driver for OCERA project
[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  * This software is released under the GPL-License.
5  * Version 0.7  6 Aug 2001
6  */
7
8 #include <linux/autoconf.h>
9 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
10 #define MODVERSIONS
11 #endif
12
13 #if defined (MODVERSIONS)
14 #include <linux/modversions.h>
15 #endif
16
17 #define __NO_VERSION__
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <linux/delay.h>
22 #include <asm/irq.h>
23 #include <asm/uaccess.h>
24
25 #include "../include/main.h"
26
27 ssize_t can_write(struct file *file, const char *buffer, size_t length, loff_t *offset)
28 {
29         struct msgobj_t *obj;
30         struct chip_t *chip;
31         struct canmsg_t *write_msg;
32         struct canfifo_t *fifo;
33         int ret = 0;
34         int space = 0;
35         int written = 0;
36         int bytes_to_copy = 0;
37         long can_timeout = 1;
38
39         if (length < sizeof(struct canmsg_t)) {
40                 DEBUGMSG("Trying to write less bytes than a CAN message,\n");
41                 DEBUGMSG("this will always return 0 !\n");
42                 return 0;
43         }
44         if (length > 8 * sizeof(struct canmsg_t)) {
45                 CANMSG("Trying to write more than is supported.\n");
46                 return -1;
47         }
48         if (length % sizeof(struct canmsg_t)) {
49                 CANMSG("The number of bytes requested to be written is not a multiple of\n");
50                 CANMSG("'sizeof(struct canmsg_t)', currently this is not allowed.\n");
51                 return -1;
52         } 
53
54         /* Initialize hardware pointers */
55         if ( (obj = objects_p[MINOR_NR]) == NULL) {
56                 CANMSG("Could not assign buffer structure\n");
57                 return -1;
58         }
59         if ( (chip = obj->hostchip) == NULL) {
60                 CANMSG("Device is not correctly configured,\n");
61                 CANMSG("please reload the driver\n");
62                 return -1;
63         }
64         if ( (fifo = obj->fifo) == NULL) {
65                 CANMSG("Could not assign buffer memory\n");
66                 return -1;
67         }
68
69         /* Initialize pointer to the first message to be sent */
70         write_msg = fifo->tx_writep;
71
72         /* Calculate free buffer space */
73         cli();
74         space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ? 
75                         ((int)fifo->tx_readp - (int)fifo->tx_writep) : 
76                         ((int)fifo->tx_readp - (int)fifo->tx_writep + 
77                                                         (int)fifo->tx_size);
78         sti();
79
80         /* If the output buffer is full, return immediately in case O_NONBLOCK
81          * has been specified or loop until space becomes available.
82          */
83         while (space < sizeof(struct canmsg_t)) {
84                 DEBUGMSG("Buffer is full\n");
85                 if (file->f_flags & O_NONBLOCK)
86                         return -EAGAIN;
87                 can_timeout = interruptible_sleep_on_timeout(&fifo->writeq, 
88                                                                 CANTIMEOUT);
89                 if (signal_pending(current))
90                         return -EINTR;
91                 if (!can_timeout)
92                         return -EIO;
93                 cli();
94                 space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ? 
95                         ((int)fifo->tx_readp - (int)fifo->tx_writep) : 
96                         ((int)fifo->tx_readp - (int)fifo->tx_writep + 
97                                                         (int)fifo->tx_size);
98                 sti();
99         }
100
101         /* There's space available in the kernel output buffer.
102          * Find out wich is smaller: 'length', the number of bytes requested to
103          * be written or 'space', the number of bytes available in the kernel 
104          * buffer. We copy the least of the two to kernel space.
105          */
106 //      space = space - (space % sizeof(struct canmsg_t)); // round it
107         bytes_to_copy = space < length ? space : length;
108         copy_from_user(fifo->tx_writep, buffer, bytes_to_copy);
109         written = bytes_to_copy;
110         while (bytes_to_copy > 0) {
111                 fifo->tx_writep++;
112                 if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
113                         fifo->tx_writep = fifo->buf_tx_entry;
114                 bytes_to_copy -= sizeof(struct canmsg_t);
115         }
116
117         /* Copy the data to be transmitted into the output buffer */
118 /*      while ( (written < length) && (space >= sizeof(struct canmsg_t)) ) {
119                 copy_from_user(fifo->tx_writep,buffer, sizeof(struct canmsg_t));
120                 cli();
121                 fifo->tx_writep++;
122                 if (fifo->tx_writep >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
123                         fifo->tx_writep = fifo->buf_tx_entry;
124                 buffer += sizeof(struct canmsg_t);
125                 written += sizeof(struct canmsg_t);
126                 space = ((int)fifo->tx_writep < (int)fifo->tx_readp) ?
127                         ((int)fifo->tx_readp - (int)fifo->tx_writep) :
128                         ((int)fifo->tx_readp - (int)fifo->tx_writep + 
129                                                         (int)fifo->tx_size);
130                 sti();
131         } */
132
133         /* Initiate transmission in case we are not already transmitting */
134         cli();
135         if (!fifo->tx_in_progress) {
136                 fifo->tx_in_progress = 1;
137                 sti();
138                 if ( (ret = chip->chipspecops->pre_write_config(chip, obj, 
139                                                         write_msg)) < 0) {
140                         CANMSG("Error initializing hardware for sending\n");
141                         return -EIO;
142                 }
143                 obj->ret = 0;
144                 if ( (ret = chip->chipspecops->send_msg(chip, obj, 
145                                                         write_msg)) < 0) {
146                         CANMSG("Error sending message\n");
147                         return -EIO;
148                 }
149                 /* If O_SYNC is specified wait for successfull transmission */
150 /*              while (1) {
151                         cli();
152                         if ( (!file->f_flags & O_SYNC) || 
153                                                 (!fifo->tx_in_progress)) {
154                                 sti();
155                                 if (obj->ret < 0)
156                                         return obj->ret;
157                                 else
158                                         return written;
159                         }
160                         cli();
161                         if (fifo->tx_in_progress) {
162                                 can_timeout = interruptible_sleep_on_timeout(
163                                                 &fifo->writeq, CANTIMEOUT);
164                         }
165                         sti();
166                         if (signal_pending(current))
167                                 return -EINTR;
168                         if (!can_timeout)
169                                 return -EIO;
170                 } */
171         }
172         sti();
173
174         return written;
175 }