File: /usr/src/linux/drivers/isdn/tpam/tpam_memory.c
1 /* $Id: tpam_memory.c,v 1.1.2.1 2001/06/05 19:45: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 * For all support questions please contact: <support@auvertech.fr>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24 #include <linux/config.h>
25 #include <linux/pci.h>
26 #include <asm/io.h>
27
28 #include "tpam.h"
29
30 /*
31 * Write a DWORD into the board memory.
32 *
33 * card: the board
34 * addr: the address (in the board memory)
35 * val: the value to put into the memory.
36 */
37 void copy_to_pam_dword(tpam_card *card, const void *addr, u32 val) {
38
39 /* set the page register */
40 writel(((unsigned long)addr) | TPAM_PAGE_SIZE,
41 card->bar0 + TPAM_PAGE_REGISTER);
42
43 /* write the value */
44 writel(val, card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE));
45 }
46
47 /*
48 * Write n bytes into the board memory. The count of bytes will be rounded
49 * up to a multiple of 4.
50 *
51 * card: the board
52 * to: the destination address (in the board memory)
53 * from: the source address (in the kernel memory)
54 * n: number of bytes
55 */
56 void copy_to_pam(tpam_card *card, void *to, const void *from, u32 n) {
57 u32 page, offset, count;
58
59 /* need to write in dword ! */
60 while (n & 3) n++;
61
62 while (n) {
63 page = ((u32)to) | TPAM_PAGE_SIZE;
64 offset = ((u32)to) & TPAM_PAGE_SIZE;
65 count = n < TPAM_PAGE_SIZE - offset
66 ? n
67 : TPAM_PAGE_SIZE - offset;
68
69 /* set the page register */
70 writel(page, card->bar0 + TPAM_PAGE_REGISTER);
71
72 /* copy the data */
73 memcpy_toio((void *)(card->bar0 + offset), from, count);
74
75 from += count;
76 to += count;
77 n -= count;
78 }
79 }
80
81 /*
82 * Read a DWORD from the board memory.
83 *
84 * card: the board
85 * addr: the address (in the board memory)
86 *
87 * Return: the value read into the memory.
88 */
89 u32 copy_from_pam_dword(tpam_card *card, const void *addr) {
90
91 /* set the page register */
92 writel(((u32)addr) | TPAM_PAGE_SIZE,
93 card->bar0 + TPAM_PAGE_REGISTER);
94
95 /* read the data */
96 return readl(card->bar0 + (((u32)addr) & TPAM_PAGE_SIZE));
97 }
98
99 /*
100 * Read n bytes from the board memory.
101 *
102 * card: the board
103 * to: the destination address (in the kernel memory)
104 * from: the source address (in the board memory)
105 * n: number of bytes
106 */
107 void copy_from_pam(tpam_card *card, void *to, const void *from, u32 n) {
108 u32 page, offset, count;
109
110 while (n) {
111 page = ((u32)from) | TPAM_PAGE_SIZE;
112 offset = ((u32)from) & TPAM_PAGE_SIZE;
113 count = n < TPAM_PAGE_SIZE - offset
114 ? n
115 : TPAM_PAGE_SIZE - offset;
116
117 /* set the page register */
118 writel(page, card->bar0 + TPAM_PAGE_REGISTER);
119
120 /* read the data */
121 memcpy_fromio(to, (void *)(card->bar0 + offset), count);
122
123 from += count;
124 to += count;
125 n -= count;
126 }
127 }
128
129 /*
130 * Read n bytes from the board memory and writes them into the user memory.
131 *
132 * card: the board
133 * to: the destination address (in the userspace memory)
134 * from: the source address (in the board memory)
135 * n: number of bytes
136 *
137 * Return: 0 if OK, <0 if error.
138 */
139 int copy_from_pam_to_user(tpam_card *card, void *to, const void *from, u32 n) {
140 void *page;
141 u32 count;
142
143 /* allocate a free page for the data transfer */
144 if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
145 printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): "
146 "get_free_page failed\n");
147 return -ENOMEM;
148 }
149
150 while (n) {
151 count = n < PAGE_SIZE ? n : PAGE_SIZE;
152
153 /* copy data from the board into the kernel memory */
154 spin_lock_irq(&card->lock);
155 copy_from_pam(card, page, from, count);
156 spin_unlock_irq(&card->lock);
157
158 /* copy it from the kernel memory into the user memory */
159 if (copy_to_user(to, page, count)) {
160
161 /* this can fail... */
162 free_page((u32)page);
163 return -EFAULT;
164 }
165 from += count;
166 to += count;
167 n -= count;
168 }
169
170 /* release allocated memory */
171 free_page((u32)page);
172 return 0;
173 }
174
175 /*
176 * Read n bytes from the user memory and writes them into the board memory.
177 *
178 * card: the board
179 * to: the destination address (in the board memory)
180 * from: the source address (in the userspace memory)
181 * n: number of bytes
182 *
183 * Return: 0 if OK, <0 if error.
184 */
185 int copy_from_user_to_pam(tpam_card *card, void *to, const void *from, u32 n) {
186 void *page;
187 u32 count;
188
189 /* allocate a free page for the data transfer */
190 if (!(page = (void *)__get_free_page(GFP_KERNEL))) {
191 printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): "
192 "get_free_page failed\n");
193 return -ENOMEM;
194 }
195
196 while (n) {
197 count = n < PAGE_SIZE ? n : PAGE_SIZE;
198
199 /* copy data from the user memory into the kernel memory */
200 if (copy_from_user(page, from, count)) {
201 /* this can fail... */
202 free_page((u32)page);
203 return -EFAULT;
204 }
205
206 /* copy it from the kernel memory into the board memory */
207 spin_lock_irq(&card->lock);
208 copy_to_pam(card, to, page, count);
209 spin_unlock_irq(&card->lock);
210
211 from += count;
212 to += count;
213 n -= count;
214 }
215
216 /* release allocated memory */
217 free_page((u32)page);
218 return 0;
219 }
220
221 /*
222 * Verify if we have the permission to read or writes len bytes at the
223 * address address from/to the board memory.
224 *
225 * address: the start address (in the board memory)
226 * len: number of bytes
227 *
228 * Return: 0 if OK, <0 if error.
229 */
230 int tpam_verify_area(u32 address, u32 len) {
231
232 if (address < TPAM_RESERVEDAREA1_START)
233 return (address + len <= TPAM_RESERVEDAREA1_START) ? 0 : -1;
234
235 if (address <= TPAM_RESERVEDAREA1_END)
236 return -1;
237
238 if (address < TPAM_RESERVEDAREA2_START)
239 return (address + len <= TPAM_RESERVEDAREA2_START) ? 0 : -1;
240
241 if (address <= TPAM_RESERVEDAREA2_END)
242 return -1;
243
244 if (address < TPAM_RESERVEDAREA3_START)
245 return (address + len <= TPAM_RESERVEDAREA3_START) ? 0 : -1;
246
247 if (address <= TPAM_RESERVEDAREA3_END)
248 return -1;
249
250 if (address < TPAM_RESERVEDAREA4_START)
251 return (address + len <= TPAM_RESERVEDAREA4_START) ? 0 : -1;
252
253 if (address <= TPAM_RESERVEDAREA4_END)
254 return -1;
255
256 return 0;
257 }
258
259