]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/sysdep_lnx.c
The system dependent part moved from setup.c into separate file.
[lincan.git] / lincan / src / sysdep_lnx.c
1 /* sysdep_lnx.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.3  17 Jun 2004
8  */ 
9
10 #include "../include/can.h"
11 #include "../include/can_sysdep.h"
12 #include "../include/main.h"
13 #include "../include/devcommon.h"
14 #include "../include/setup.h"
15 #include "../include/finish.h"
16
17 #ifdef CAN_ENABLE_VME_SUPPORT
18 #include "ca91c042.h"
19 /* Modified version of ca91c042 driver can be found in
20  * components/comm/contrib directory. */
21 #endif
22
23
24 /**
25  * can_checked_malloc - memory allocation with registering of requested blocks
26  * @size: size of the requested block
27  *
28  * The function is used in the driver initialization phase to catch possible memory
29  * leaks for future driver finalization or case, that driver initialization fail.
30  * 
31  * Return Value: pointer to the allocated memory or NULL in the case of fail
32  */
33 void *can_checked_malloc(size_t size)
34 {
35         struct mem_addr *mem_new;
36         void *address_p;
37         
38         address_p=kmalloc(size,GFP_KERNEL);
39         if(address_p == NULL) {
40                 CANMSG("can_checked_malloc: out of the memory\n");
41                 return NULL;
42         }
43
44 #ifdef DEBUG_MEM
45         DEBUGMSG("can_checked_malloc: allocated %d bytes at %p, mem_head=%p\n",
46                         (int)size, address_p, mem_head);
47 #endif
48
49         mem_new=(struct mem_addr *)kmalloc(sizeof(struct mem_addr),GFP_KERNEL);
50         if (mem_new == NULL) {
51                 CANMSG("can_checked_malloc: memory list allocation error.\n");
52                 kfree(address_p);
53                 return NULL;
54         }
55         mem_new->next=mem_head;
56         mem_new->address=address_p;
57         mem_new->size=size;
58         mem_head=mem_new;
59
60         return address_p;
61 }
62
63 /**
64  * can_checked_free - free memory allocated by  can_checked_malloc()
65  * @address_p: pointer to the memory block
66  */
67 int can_checked_free(void *address_p)
68 {
69         struct mem_addr **mem_pptr;
70         struct mem_addr *mem_del=NULL;
71
72 #ifdef DEBUG_MEM
73         DEBUGMSG("can_checked_free %p, mem_head=%p\n", address_p, mem_head);
74 #endif
75
76         for(mem_pptr = &mem_head; (mem_del = *mem_pptr); mem_pptr = &mem_del->next) {
77                 if (mem_del->address != address_p)
78                         continue;
79                 *mem_pptr=mem_del->next;
80                 kfree(mem_del);
81                 kfree(address_p);
82                 return 0;
83         }
84         
85         CANMSG("can_checked_free: address %p not found on the mem list\n", address_p);
86         
87         kfree(address_p);
88         return -1;
89 }
90
91
92 /**
93  * can_del_mem_list - check for stale memory allocations at driver finalization
94  *
95  * Checks, if there are still some memory blocks allocated and releases memory
96  * occupied by such blocks back to the system
97  */
98 int can_del_mem_list(void)
99 {
100         struct mem_addr *mem;
101
102 #ifdef DEBUG_MEM
103         DEBUGMSG("can_del_mem_list, mem_head=%p\n", mem_head);
104 #endif
105         if(mem_head == NULL) {
106                 CANMSG("can_del_mem_list: no entries on the list - OK\n");
107                 return 0;
108         }
109
110         while((mem=mem_head) != NULL) {
111                 mem_head=mem->next;
112                 CANMSG("can_del_mem_list: deleting %p with size %d\n",
113                         mem->address, (int)mem->size);
114                 kfree(mem->address);
115                 kfree(mem);
116         }
117         
118         return 0;
119 }
120
121 /**
122  * can_request_io_region - request IO space region
123  * @start: the first IO port address
124  * @n: number of the consecutive IO port addresses
125  * @name: name/label for the requested region
126  *
127  * The function hides system specific implementation of the feature.
128  *
129  * Return Value: returns positive value (1) in the case, that region could
130  *      be reserved for the driver. Returns zero (0) if there is collision with
131  *      other driver or region cannot be taken for some other reason.
132  */
133 int can_request_io_region(unsigned long start, unsigned long n, const char *name)
134 {
135     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
136         if(check_region(start,n)) return 0;
137         request_region(start,n,name);
138         return 1;
139     #else
140         return (request_region(start,n,name))?1:0;
141     #endif
142 }
143
144 /**
145  * can_release_io_region - release IO space region
146  * @start: the first IO port address
147  * @n: number of the consecutive IO port addresses
148  */
149 void can_release_io_region(unsigned long start, unsigned long n)
150 {
151         release_region(start,n);
152 }
153
154 /**
155  * can_request_mem_region - request memory space region
156  * @start: the first memory port physical address
157  * @n: number of the consecutive memory port addresses
158  * @name: name/label for the requested region
159  *
160  * The function hides system specific implementation of the feature.
161  *
162  * Return Value: returns positive value (1) in the case, that region could
163  *      be reserved for the driver. Returns zero (0) if there is collision with
164  *      other driver or region cannot be taken for some other reason.
165  */
166 int can_request_mem_region(unsigned long start, unsigned long n, const char *name)
167 {
168     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
169         return 1;
170     #else
171         return (request_mem_region(start,n,name))?1:0;
172     #endif
173 }
174
175 /**
176  * can_release_mem_region - release memory space region
177  * @start: the first memory port physical address
178  * @n: number of the consecutive memory port addresses
179  */
180 void can_release_mem_region(unsigned long start, unsigned long n)
181 {
182     #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
183         return;
184     #else
185         release_mem_region(start,n);
186     #endif
187 }
188
189 #ifndef CAN_WITH_RTL
190
191 /**
192  * can_default_irq_dispatch - the first level interrupt dispatch handler
193  * @irq: interrupt vector number, this value is system specific
194  * @dev_id: driver private pointer registered at time of request_irq() call.
195  *      The CAN driver uses this pointer to store relationship of interrupt
196  *      to chip state structure - @struct canchip_t
197  * @regs: system dependent value pointing to registers stored in exception frame
198  * 
199  * File: src/setup.c
200  */
201 can_irqreturn_t can_default_irq_dispatch(int irq, void *dev_id, struct pt_regs *regs)
202 {
203         int retval;
204         struct canchip_t *chip=(struct canchip_t *)dev_id;
205
206         retval=chip->chipspecops->irq_handler(irq, chip);
207         return CAN_IRQ_RETVAL(retval);
208 }
209
210 /**
211  * can_chip_setup_irq - attaches chip to the system interrupt processing
212  * @chip: pointer to CAN chip structure
213  *
214  * Return Value: returns negative number in the case of fail
215  */
216 int can_chip_setup_irq(struct canchip_t *chip)
217 {
218         if(chip==NULL)
219                 return -1;
220         if(!chip->chipspecops->irq_handler)
221                 return 0;
222         if(chip->flags & CHIP_IRQ_CUSTOM)
223                 return 1;
224                         
225         if ((chip->flags & CHIP_IRQ_VME) == 0) {
226                 if (request_irq(chip->chip_irq,can_default_irq_dispatch,SA_SHIRQ,DEVICE_NAME,chip))
227                         return -1;
228                 else {
229                         DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
230                         chip->flags |= CHIP_IRQ_SETUP;
231                 }
232         } else {
233 #ifdef CAN_ENABLE_VME_SUPPORT
234                 if (chip->chip_irq < 1 || chip->chip_irq > 255) {
235                         CANMSG("Bad irq parameter. (1 <= irq <= 255).\n");
236                         return -EINVAL;
237                 }
238                 
239                 request_vmeirq(chip->chip_irq, can_default_irq_dispatch, chip);
240                 DEBUGMSG("Registered VME interrupt vector %d\n",chip->chip_irq);
241                 chip->flags |= CHIP_IRQ_SETUP;
242 #endif
243         }
244         return 1;
245 }
246
247
248 /**
249  * can_chip_free_irq - unregisters chip interrupt handler from the system
250  * @chip: pointer to CAN chip structure
251  */
252 void can_chip_free_irq(struct canchip_t *chip)
253 {
254         if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
255                 if(chip->flags & CHIP_IRQ_CUSTOM)
256                         return;
257
258                 if ((chip->flags & CHIP_IRQ_VME) == 0)
259                         free_irq(chip->chip_irq, chip);
260                 else { 
261 #ifdef CAN_ENABLE_VME_SUPPORT
262                         free_vmeirq(chip->chip_irq);
263 #endif
264                 }
265                         chip->flags &= ~CHIP_IRQ_SETUP;
266         }
267 }
268
269 #endif /*CAN_WITH_RTL*/