1 /* $Id: tpam_memory.c,v 1.1.2.1 2001/11/20 14:19:37 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 */
copy_to_pam_dword(tpam_card * card,const void * addr,u32 val)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 */
copy_to_pam(tpam_card * card,void * to,const void * from,u32 n)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 */
copy_from_pam_dword(tpam_card * card,const void * addr)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 */
copy_from_pam(tpam_card * card,void * to,const void * from,u32 n)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 */
copy_from_pam_to_user(tpam_card * card,void * to,const void * from,u32 n)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 */
copy_from_user_to_pam(tpam_card * card,void * to,const void * from,u32 n)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 */
tpam_verify_area(u32 address,u32 len)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
248