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