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