ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / isdn / tpam / tpam_memory.c
1 /* $Id: tpam_memory.c,v 1.1.2.2 2001/09/23 22:25:03 kai Exp $
2  *
3  * Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access)
4  *
5  * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, AlcĂ´ve
6  *
7  * This software may be used and distributed according to the terms
8  * of the GNU General Public License, incorporated herein by reference.
9  *
10  * For all support questions please contact: <support@auvertech.fr>
11  *
12  */
13
14 #include <linux/pci.h>
15 #include <asm/io.h>
16
17 #include "tpam.h"
18
19 /*
20  * Write a DWORD into the board memory.
21  *
22  *      card: the board
23  *      addr: the address (in the board memory)
24  *      val: the value to put into the memory.
25  */
26 void copy_to_pam_dword(tpam_card *card, const void *addr, u32 val) {
27
28         /* set the page register */
29         writel(((unsigned long)addr) | TPAM_PAGE_SIZE, 
30                card->bar0 + TPAM_PAGE_REGISTER);
31
32         /* write the value */
33         writel(val, card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE));
34 }
35
36 /*
37  * Write n bytes into the board memory. The count of bytes will be rounded
38  * up to a multiple of 4.
39  *
40  *      card: the board
41  *      to: the destination address (in the board memory)
42  *      from: the source address (in the kernel memory)
43  *      n: number of bytes
44  */
45 void copy_to_pam(tpam_card *card, void *to, const void *from, u32 n) {
46         u32 page, offset, count;
47
48         /* need to write in dword ! */
49         while (n & 3) n++;
50
51         while (n) {
52                 page = ((u32)to) | TPAM_PAGE_SIZE;
53                 offset = ((u32)to) & TPAM_PAGE_SIZE;
54                 count = n < TPAM_PAGE_SIZE - offset
55                                 ? n
56                                 : TPAM_PAGE_SIZE - offset;
57
58                 /* set the page register */
59                 writel(page, card->bar0 + TPAM_PAGE_REGISTER);
60
61                 /* copy the data */
62                 memcpy_toio((void *)(card->bar0 + offset), from, count);
63                 
64                 from += count;
65                 to += count;
66                 n -= count;
67         }
68 }
69
70 /*
71  * Read a DWORD from the board memory.
72  *
73  *      card: the board
74  *      addr: the address (in the board memory)
75  *
76  * Return: the value read into the memory.
77  */
78 u32 copy_from_pam_dword(tpam_card *card, const void *addr) {
79
80         /* set the page register */
81         writel(((u32)addr) | TPAM_PAGE_SIZE, 
82                card->bar0 + TPAM_PAGE_REGISTER);
83
84         /* read the data */
85         return readl(card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE));
86 }
87
88 /*
89  * Read n bytes from the board memory.
90  *
91  *      card: the board
92  *      to: the destination address (in the kernel memory)
93  *      from: the source address (in the board memory)
94  *      n: number of bytes
95  */
96 void copy_from_pam(tpam_card *card, void *to, const void *from, u32 n) {
97         u32 page, offset, count;
98
99         while (n) {
100                 page = ((u32)from) | TPAM_PAGE_SIZE;
101                 offset = ((u32)from) & TPAM_PAGE_SIZE;
102                 count = n < TPAM_PAGE_SIZE - offset 
103                                 ? n 
104                                 : TPAM_PAGE_SIZE - offset;
105
106                 /* set the page register */
107                 writel(page, card->bar0 + TPAM_PAGE_REGISTER);
108
109                 /* read the data */
110                 memcpy_fromio(to, (void *)(card->bar0 + offset), count);
111                 
112                 from += count;
113                 to += count;
114                 n -= count;
115         }
116 }
117
118 /*
119  * Read n bytes from the board memory and writes them into the user memory.
120  *
121  *      card: the board
122  *      to: the destination address (in the userspace memory)
123  *      from: the source address (in the board memory)
124  *      n: number of bytes
125  *
126  * Return: 0 if OK, <0 if error.
127  */
128 int copy_from_pam_to_user(tpam_card *card, void *to, const void *from, u32 n) {
129         void *page;
130         u32 count;
131
132         /* allocate a free page for the data transfer */
133         if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
134                 printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): "
135                        "get_free_page failed\n");
136                 return -ENOMEM;
137         }
138
139         while (n) {
140                 count = n < PAGE_SIZE ? n : PAGE_SIZE;
141
142                 /* copy data from the board into the kernel memory */
143                 spin_lock_irq(&card->lock);
144                 copy_from_pam(card, page, from, count);
145                 spin_unlock_irq(&card->lock);
146
147                 /* copy it from the kernel memory into the user memory */
148                 if (copy_to_user(to, page, count)) {
149                         
150                         /* this can fail... */
151                         free_page((u32)page);
152                         return -EFAULT;
153                 }
154                 from += count;
155                 to += count;
156                 n -= count;
157         }
158
159         /* release allocated memory */
160         free_page((u32)page);
161         return 0;
162 }
163
164 /*
165  * Read n bytes from the user memory and writes them into the board memory.
166  *
167  *      card: the board
168  *      to: the destination address (in the board memory)
169  *      from: the source address (in the userspace memory)
170  *      n: number of bytes
171  *
172  * Return: 0 if OK, <0 if error.
173  */
174 int copy_from_user_to_pam(tpam_card *card, void *to, const void *from, u32 n) {
175         void *page;
176         u32 count;
177
178         /* allocate a free page for the data transfer */
179         if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
180                 printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): "
181                        "get_free_page failed\n");
182                 return -ENOMEM;
183         }
184
185         while (n) {
186                 count = n < PAGE_SIZE ? n : PAGE_SIZE;
187
188                 /* copy data from the user memory into the kernel memory */
189                 if (copy_from_user(page, from, count)) {
190                         /* this can fail... */
191                         free_page((u32)page);
192                         return -EFAULT;
193                 }
194
195                 /* copy it from the kernel memory into the board memory */
196                 spin_lock_irq(&card->lock);
197                 copy_to_pam(card, to, page, count);
198                 spin_unlock_irq(&card->lock);
199
200                 from += count;
201                 to += count;
202                 n -= count;
203         }
204
205         /* release allocated memory */
206         free_page((u32)page);
207         return 0;
208 }
209
210 /*
211  * Verify if we have the permission to read or writes len bytes at the
212  * address address from/to the board memory.
213  *
214  *      address: the start address (in the board memory)
215  *      len: number of bytes
216  *
217  * Return: 0 if OK, <0 if error.
218  */
219 int tpam_verify_area(u32 address, u32 len) {
220
221         if (address < TPAM_RESERVEDAREA1_START)
222                 return (address + len <= TPAM_RESERVEDAREA1_START) ? 0 : -1;
223
224         if (address <= TPAM_RESERVEDAREA1_END)
225                 return -1;
226
227         if (address < TPAM_RESERVEDAREA2_START)
228                 return (address + len <= TPAM_RESERVEDAREA2_START) ? 0 : -1;
229
230         if (address <= TPAM_RESERVEDAREA2_END)
231                 return -1;
232
233         if (address < TPAM_RESERVEDAREA3_START)
234                 return (address + len <= TPAM_RESERVEDAREA3_START) ? 0 : -1;
235
236         if (address <= TPAM_RESERVEDAREA3_END)
237                 return -1;
238
239         if (address < TPAM_RESERVEDAREA4_START)
240                 return (address + len <= TPAM_RESERVEDAREA4_START) ? 0 : -1;
241
242         if (address <= TPAM_RESERVEDAREA4_END)
243                 return -1;
244
245         return 0;
246 }
247