Rev 9 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9 | Rev 11 | ||
---|---|---|---|
1 | //**************************************************************************** |
1 | //**************************************************************************** |
2 | // Copyright (C) 2000-2004 ARW Elektronik Germany |
2 | // Copyright (C) 2000-2004 ARW Elektronik Germany |
3 | // |
3 | // |
4 | // |
4 | // |
5 | // This program is free software; you can redistribute it and/or modify |
5 | // This program is free software; you can redistribute it and/or modify |
6 | // it under the terms of the GNU General Public License as published by |
6 | // it under the terms of the GNU General Public License as published by |
7 | // the Free Software Foundation; either version 2 of the License, or |
7 | // the Free Software Foundation; either version 2 of the License, or |
8 | // (at your option) any later version. |
8 | // (at your option) any later version. |
9 | // |
9 | // |
10 | // This program is distributed in the hope that it will be useful, |
10 | // This program is distributed in the hope that it will be useful, |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | // GNU General Public License for more details. |
13 | // GNU General Public License for more details. |
14 | // |
14 | // |
15 | // You should have received a copy of the GNU General Public License |
15 | // You should have received a copy of the GNU General Public License |
16 | // along with this program; if not, write to the Free Software |
16 | // along with this program; if not, write to the Free Software |
17 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
17 | // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | // |
18 | // |
19 | // This product is not authorized for use as critical component in |
19 | // This product is not authorized for use as critical component in |
20 | // life support systems without the express written approval of |
20 | // life support systems without the express written approval of |
21 | // ARW Elektronik Germany. |
21 | // ARW Elektronik Germany. |
22 | // |
22 | // |
23 | // Please announce changes and hints to ARW Elektronik |
23 | // Please announce changes and hints to ARW Elektronik |
24 | // |
24 | // |
25 | // Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de) |
25 | // Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de) |
26 | // |
26 | // |
27 | //**************************************************************************** |
27 | //**************************************************************************** |
28 | 28 | ||
29 | //**************************************************************************** |
29 | //**************************************************************************** |
30 | // |
30 | // |
31 | // fops.c -- the file operations module for the PCIVME PCI to VME Interface |
31 | // fops.c -- the file operations module for the PCIVME PCI to VME Interface |
32 | // |
32 | // |
33 | // $Log: fops.c,v $ |
33 | // $Log: fops.c,v $ |
34 | // Revision 1.11 2005/03/01 10:56:12 klaus |
34 | // Revision 1.11 2005/03/01 10:56:12 klaus |
35 | // removed warnings with gcc 3.3.3 |
35 | // removed warnings with gcc 3.3.3 |
36 | // |
36 | // |
37 | // Revision 1.10 2004/08/13 19:23:26 klaus |
37 | // Revision 1.10 2004/08/13 19:23:26 klaus |
38 | // conversion to kernel-version 2.6, released version 3.0 |
38 | // conversion to kernel-version 2.6, released version 3.0 |
39 | // |
39 | // |
40 | // Revision 1.9 2003/06/27 17:25:52 klaus |
40 | // Revision 1.9 2003/06/27 17:25:52 klaus |
41 | // incomplete try to get mmap() with nopage() running for automatic page switch |
41 | // incomplete try to get mmap() with nopage() running for automatic page switch |
42 | // |
42 | // |
43 | // Revision 1.8 2002/10/20 18:06:51 klaus |
43 | // Revision 1.8 2002/10/20 18:06:51 klaus |
44 | // changed error handling |
44 | // changed error handling |
45 | // |
45 | // |
46 | // Revision 1.7 2002/10/18 21:56:28 klaus |
46 | // Revision 1.7 2002/10/18 21:56:28 klaus |
47 | // completed functional features, untested |
47 | // completed functional features, untested |
48 | // |
48 | // |
49 | // Revision 1.6 2002/10/18 21:56:28 klaus |
49 | // Revision 1.6 2002/10/18 21:56:28 klaus |
50 | // completed functional features, untested |
50 | // completed functional features, untested |
51 | // |
51 | // |
52 | // Revision 1.5 2002/10/17 19:05:03 klaus |
52 | // Revision 1.5 2002/10/17 19:05:03 klaus |
53 | // VME access is working through test to lib to driver |
53 | // VME access is working through test to lib to driver |
54 | // |
54 | // |
55 | //**************************************************************************** |
55 | //**************************************************************************** |
56 | 56 | ||
57 | /*--- INCLUDES -----------------------------------------------------------------------------------*/ |
57 | /*--- INCLUDES -----------------------------------------------------------------------------------*/ |
58 | #include "common.h" /* must be the first include */ |
58 | #include "common.h" /* must be the first include */ |
59 | 59 | ||
60 | #include <linux/kernel.h> /* printk() */ |
60 | #include <linux/kernel.h> /* printk() */ |
61 | #include <linux/module.h> /* only here ?cause of MAJOR ... */ |
61 | #include <linux/module.h> /* only here ?cause of MAJOR ... */ |
62 | #include <linux/pci.h> |
62 | #include <linux/pci.h> |
63 | #include <linux/list.h> |
63 | #include <linux/list.h> |
64 | #include <asm/errno.h> |
64 | #include <asm/errno.h> |
65 | #include <asm/types.h> |
65 | #include <asm/types.h> |
66 | #include <asm/uaccess.h> |
66 | #include <asm/uaccess.h> |
67 | 67 | ||
68 | #include <linux/sched.h> |
68 | #include <linux/sched.h> |
69 | #include <linux/fs.h> |
69 | #include <linux/fs.h> |
70 | #if HAVE_UNLOCKED_IOCTL |
70 | #if HAVE_UNLOCKED_IOCTL |
71 | #include <linux/mutex.h> |
71 | #include <linux/mutex.h> |
72 | #else |
72 | #else |
73 | #include <linux/smp_lock.h> |
73 | #include <linux/smp_lock.h> |
74 | #endif |
74 | #endif |
75 | 75 | ||
76 | 76 | ||
77 | #include "fops.h" |
77 | #include "fops.h" |
78 | #include "plx9050.h" |
78 | #include "plx9050.h" |
79 | #include "pcivme.h" /* the common ioctl commands and structures between driver and application */ |
79 | #include "pcivme.h" /* the common ioctl commands and structures between driver and application */ |
80 | #include "main.h" |
80 | #include "main.h" |
81 | #include "askpci.h" |
81 | #include "askpci.h" |
82 | #include "pciif.h" |
82 | #include "pciif.h" |
83 | #include "vic.h" |
83 | #include "vic.h" |
84 | #include "vme.h" |
84 | #include "vme.h" |
85 | 85 | ||
86 | /*--- DEFINES ------------------------------------------------------------------------------------*/ |
86 | /*--- DEFINES ------------------------------------------------------------------------------------*/ |
87 | 87 | ||
88 | #ifndef MINOR |
88 | #ifndef MINOR |
89 | #define MINOR(x) minor(x) // since 2.5.? |
89 | #define MINOR(x) minor(x) // since 2.5.? |
90 | #endif |
90 | #endif |
91 | 91 | ||
92 | static PCIVME_INIT_ELEMENT init_element[] = |
92 | static PCIVME_INIT_ELEMENT init_element[] = |
93 | {{LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
93 | {{LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
94 | {LCR, WORD_ACCESS, PLX9050_CNTRL, RELEASE_VMEMM}, // enable interface |
94 | {LCR, WORD_ACCESS, PLX9050_CNTRL, RELEASE_VMEMM}, // enable interface |
95 | 95 | ||
96 | {VIC, BYTE_ACCESS, VIICR, 0xf8+1}, // VIICR |
96 | {VIC, BYTE_ACCESS, VIICR, 0xf8+1}, // VIICR |
97 | 97 | ||
98 | {VIC, BYTE_ACCESS, VICR1, 0x78+1}, // VICR1 |
98 | {VIC, BYTE_ACCESS, VICR1, 0x78+1}, // VICR1 |
99 | {VIC, BYTE_ACCESS, VICR2, 0x78+2}, |
99 | {VIC, BYTE_ACCESS, VICR2, 0x78+2}, |
100 | {VIC, BYTE_ACCESS, VICR3, 0x78+3}, |
100 | {VIC, BYTE_ACCESS, VICR3, 0x78+3}, |
101 | {VIC, BYTE_ACCESS, VICR4, 0x78+4}, |
101 | {VIC, BYTE_ACCESS, VICR4, 0x78+4}, |
102 | {VIC, BYTE_ACCESS, VICR5, 0x78+5}, |
102 | {VIC, BYTE_ACCESS, VICR5, 0x78+5}, |
103 | {VIC, BYTE_ACCESS, VICR6, 0x78+6}, |
103 | {VIC, BYTE_ACCESS, VICR6, 0x78+6}, |
104 | {VIC, BYTE_ACCESS, VICR7, 0x78+7}, // VICR7 |
104 | {VIC, BYTE_ACCESS, VICR7, 0x78+7}, // VICR7 |
105 | 105 | ||
106 | {VIC, BYTE_ACCESS, DSICR, 0xf8+0}, // DSICR |
106 | {VIC, BYTE_ACCESS, DSICR, 0xf8+0}, // DSICR |
107 | 107 | ||
108 | {VIC, BYTE_ACCESS, LICR1, 0xf8+1}, // LICR1 |
108 | {VIC, BYTE_ACCESS, LICR1, 0xf8+1}, // LICR1 |
109 | {VIC, BYTE_ACCESS, LICR2, 0xf8+2}, |
109 | {VIC, BYTE_ACCESS, LICR2, 0xf8+2}, |
110 | {VIC, BYTE_ACCESS, LICR3, 0xf8+3}, |
110 | {VIC, BYTE_ACCESS, LICR3, 0xf8+3}, |
111 | {VIC, BYTE_ACCESS, LICR4, 0xf8+4}, |
111 | {VIC, BYTE_ACCESS, LICR4, 0xf8+4}, |
112 | {VIC, BYTE_ACCESS, LICR5, 0xf8+5}, |
112 | {VIC, BYTE_ACCESS, LICR5, 0xf8+5}, |
113 | {VIC, BYTE_ACCESS, LICR6, 0x38+6}, |
113 | {VIC, BYTE_ACCESS, LICR6, 0x38+6}, |
114 | {VIC, BYTE_ACCESS, LICR7, 0x38+7}, // LICR7 |
114 | {VIC, BYTE_ACCESS, LICR7, 0x38+7}, // LICR7 |
115 | 115 | ||
116 | {VIC, BYTE_ACCESS, ICGSICR, 0xf8+2}, // ICGS |
116 | {VIC, BYTE_ACCESS, ICGSICR, 0xf8+2}, // ICGS |
117 | {VIC, BYTE_ACCESS, ICMSICR, 0xf8+3}, // ICMS |
117 | {VIC, BYTE_ACCESS, ICMSICR, 0xf8+3}, // ICMS |
118 | 118 | ||
119 | {VIC, BYTE_ACCESS, EGICR, 0xf8+6}, // EGICR |
119 | {VIC, BYTE_ACCESS, EGICR, 0xf8+6}, // EGICR |
120 | 120 | ||
121 | {VIC, BYTE_ACCESS, ICGSVBR, 0x08}, // ICGS-IVBR (!) |
121 | {VIC, BYTE_ACCESS, ICGSVBR, 0x08}, // ICGS-IVBR (!) |
122 | {VIC, BYTE_ACCESS, ICMSVBR, 0x0c}, // ICMS-IVBR (!) |
122 | {VIC, BYTE_ACCESS, ICMSVBR, 0x0c}, // ICMS-IVBR (!) |
123 | 123 | ||
124 | {VIC, BYTE_ACCESS, LIVBR, 0x00}, // LIVBR (!) |
124 | {VIC, BYTE_ACCESS, LIVBR, 0x00}, // LIVBR (!) |
125 | 125 | ||
126 | {VIC, BYTE_ACCESS, EGIVBR, 0x10}, // EGIVBR (!) |
126 | {VIC, BYTE_ACCESS, EGIVBR, 0x10}, // EGIVBR (!) |
127 | 127 | ||
128 | {VIC, BYTE_ACCESS, ICSR, 0x00}, // ICSR |
128 | {VIC, BYTE_ACCESS, ICSR, 0x00}, // ICSR |
129 | 129 | ||
130 | {VIC, BYTE_ACCESS, ICR0, 0x00}, // ICR0 |
130 | {VIC, BYTE_ACCESS, ICR0, 0x00}, // ICR0 |
131 | {VIC, BYTE_ACCESS, ICR1, 0x00}, |
131 | {VIC, BYTE_ACCESS, ICR1, 0x00}, |
132 | {VIC, BYTE_ACCESS, ICR2, 0x00}, |
132 | {VIC, BYTE_ACCESS, ICR2, 0x00}, |
133 | {VIC, BYTE_ACCESS, ICR3, 0x00}, |
133 | {VIC, BYTE_ACCESS, ICR3, 0x00}, |
134 | {VIC, BYTE_ACCESS, ICR4, 0x00}, // ICR4 |
134 | {VIC, BYTE_ACCESS, ICR4, 0x00}, // ICR4 |
135 | 135 | ||
136 | {VIC, BYTE_ACCESS, VIRSR, 0xfe}, // VIRSR |
136 | {VIC, BYTE_ACCESS, VIRSR, 0xfe}, // VIRSR |
137 | 137 | ||
138 | {VIC, BYTE_ACCESS, VIVR1, 0x0f}, // VIVR1 |
138 | {VIC, BYTE_ACCESS, VIVR1, 0x0f}, // VIVR1 |
139 | {VIC, BYTE_ACCESS, VIVR2, 0x0f}, |
139 | {VIC, BYTE_ACCESS, VIVR2, 0x0f}, |
140 | {VIC, BYTE_ACCESS, VIVR3, 0x0f}, |
140 | {VIC, BYTE_ACCESS, VIVR3, 0x0f}, |
141 | {VIC, BYTE_ACCESS, VIVR4, 0x0f}, |
141 | {VIC, BYTE_ACCESS, VIVR4, 0x0f}, |
142 | {VIC, BYTE_ACCESS, VIVR5, 0x0f}, |
142 | {VIC, BYTE_ACCESS, VIVR5, 0x0f}, |
143 | {VIC, BYTE_ACCESS, VIVR6, 0x0f}, |
143 | {VIC, BYTE_ACCESS, VIVR6, 0x0f}, |
144 | {VIC, BYTE_ACCESS, VIVR7, 0x0f}, // VIVR7 |
144 | {VIC, BYTE_ACCESS, VIVR7, 0x0f}, // VIVR7 |
145 | 145 | ||
146 | {VIC, BYTE_ACCESS, TTR, 0x3c}, // TTR |
146 | {VIC, BYTE_ACCESS, TTR, 0x3c}, // TTR |
147 | 147 | ||
148 | {VIC, BYTE_ACCESS, ARCR, 0x40}, // ARCR |
148 | {VIC, BYTE_ACCESS, ARCR, 0x40}, // ARCR |
149 | {VIC, BYTE_ACCESS, AMSR, 0x29}, // AMSR |
149 | {VIC, BYTE_ACCESS, AMSR, 0x29}, // AMSR |
150 | {VIC, BYTE_ACCESS, RCR, 0x00}, // RCR |
150 | {VIC, BYTE_ACCESS, RCR, 0x00}, // RCR |
151 | 151 | ||
152 | {IFR, LONG_ACCESS, (u16)ADRHL, 0xF0F0F0F0}, // ADR-H, ADR-L |
152 | {IFR, LONG_ACCESS, (u16)ADRHL, 0xF0F0F0F0}, // ADR-H, ADR-L |
153 | {IFR, WORD_ACCESS, (u16)CSR , 0x0000}, // Contr-Reg |
153 | {IFR, WORD_ACCESS, (u16)CSR , 0x0000}, // Contr-Reg |
154 | 154 | ||
155 | {VIC, BYTE_ACCESS, ICR7, 0x80}, // ICR7 |
155 | {VIC, BYTE_ACCESS, ICR7, 0x80}, // ICR7 |
156 | 156 | ||
157 | {LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
157 | {LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
158 | 158 | ||
159 | {STOP, WORD_ACCESS, 0, 0}}; |
159 | {STOP, WORD_ACCESS, 0, 0}}; |
160 | 160 | ||
161 | static PCIVME_INIT_ELEMENT deinit_element_pre[] = |
161 | static PCIVME_INIT_ELEMENT deinit_element_pre[] = |
162 | {{VIC, BYTE_ACCESS, ICR7, 0x00}, // ICR7 - sysfail |
162 | {{VIC, BYTE_ACCESS, ICR7, 0x00}, // ICR7 - sysfail |
163 | {LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
163 | {LCR, WORD_ACCESS, PLX9050_INTCSR, DISABLE_PCIADA_IRQS}, // disable interrupts |
164 | {STOP, WORD_ACCESS, 0, 0}}; |
164 | {STOP, WORD_ACCESS, 0, 0}}; |
165 | 165 | ||
166 | static PCIVME_INIT_ELEMENT deinit_element_post[] = |
166 | static PCIVME_INIT_ELEMENT deinit_element_post[] = |
167 | {{LCR, WORD_ACCESS, PLX9050_CNTRL, INHIBIT_VMEMM}, // disable interface |
167 | {{LCR, WORD_ACCESS, PLX9050_CNTRL, INHIBIT_VMEMM}, // disable interface |
168 | {STOP, WORD_ACCESS, 0, 0}}; |
168 | {STOP, WORD_ACCESS, 0, 0}}; |
169 | 169 | ||
170 | 170 | ||
171 | /*--- EXTERNALS ----------------------------------------------------------------------------------*/ |
171 | /*--- EXTERNALS ----------------------------------------------------------------------------------*/ |
172 | 172 | ||
173 | /*--- TYPEDEFS -----------------------------------------------------------------------------------*/ |
173 | /*--- TYPEDEFS -----------------------------------------------------------------------------------*/ |
174 | 174 | ||
175 | /*--- FUNCTIONS ----------------------------------------------------------------------------------*/ |
175 | /*--- FUNCTIONS ----------------------------------------------------------------------------------*/ |
176 | static inline void switch_VMEMM_on(DEVICE_OBJ *pd) |
176 | static inline void switch_VMEMM_on(DEVICE_OBJ *pd) |
177 | { |
177 | { |
178 | writew(RELEASE_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */ |
178 | writew(RELEASE_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */ |
179 | } |
179 | } |
180 | 180 | ||
181 | static inline void switch_VMEMM_off(DEVICE_OBJ *pd) |
181 | static inline void switch_VMEMM_off(DEVICE_OBJ *pd) |
182 | { |
182 | { |
183 | writew(INHIBIT_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */ |
183 | writew(INHIBIT_VMEMM, (volatile void *) (pd->pLCR + PLX9050_CNTRL)); /* enable access */ |
184 | } |
184 | } |
185 | 185 | ||
186 | static inline void setPageAddress(DEVICE_OBJ *pd, u32 newPageAddress) |
186 | static inline void setPageAddress(DEVICE_OBJ *pd, u32 newPageAddress) |
187 | { |
187 | { |
188 | PRINTK(KERN_DEBUG "%s : setPageAddress(0x%08x)\n", DEVICE_NAME, newPageAddress); |
188 | PRINTK(KERN_DEBUG "%s : setPageAddress(0x%08x)\n", DEVICE_NAME, newPageAddress); |
189 | 189 | ||
190 | writel(newPageAddress, (volatile void *) pd->pAdrReg); |
190 | writel(newPageAddress, (volatile void *) pd->pAdrReg); |
191 | pd->dwCurrentPageAddress = newPageAddress; |
191 | pd->dwCurrentPageAddress = newPageAddress; |
192 | } |
192 | } |
193 | 193 | ||
194 | static inline void setModifier(DEVICE_OBJ *pd, u8 newModifier) |
194 | static inline void setModifier(DEVICE_OBJ *pd, u8 newModifier) |
195 | { |
195 | { |
196 | PRINTK(KERN_DEBUG "%s : setModifier(0x%02x)\n", DEVICE_NAME, newModifier); |
196 | PRINTK(KERN_DEBUG "%s : setModifier(0x%02x)\n", DEVICE_NAME, newModifier); |
197 | 197 | ||
198 | writeb(newModifier, (volatile void *) pd->pAdrMod); |
198 | writeb(newModifier, (volatile void *) pd->pAdrMod); |
199 | pd->bCurrentModifier = newModifier; |
199 | pd->bCurrentModifier = newModifier; |
200 | } |
200 | } |
201 | 201 | ||
202 | /* read and write functions -----------------------------------------------------------------------*/ |
202 | /* read and write functions -----------------------------------------------------------------------*/ |
203 | static inline u8 *increment8(void **pvBuffer) |
203 | static inline u8 *increment8(void **pvBuffer) |
204 | { |
204 | { |
205 | u8 *tmp = (u8*)*pvBuffer; |
205 | u8 *tmp = (u8*)*pvBuffer; |
206 | 206 | ||
207 | *pvBuffer += sizeof(u8); |
207 | *pvBuffer += sizeof(u8); |
208 | 208 | ||
209 | return tmp; |
209 | return tmp; |
210 | } |
210 | } |
211 | 211 | ||
212 | static inline u16 *increment16(void **pvBuffer) |
212 | static inline u16 *increment16(void **pvBuffer) |
213 | { |
213 | { |
214 | u16 *tmp = (u16*)*pvBuffer; |
214 | u16 *tmp = (u16*)*pvBuffer; |
215 | 215 | ||
216 | *pvBuffer += sizeof(u16); |
216 | *pvBuffer += sizeof(u16); |
217 | 217 | ||
218 | return tmp; |
218 | return tmp; |
219 | } |
219 | } |
220 | 220 | ||
221 | static inline u32 *increment32(void **pvBuffer) |
221 | static inline u32 *increment32(void **pvBuffer) |
222 | { |
222 | { |
223 | u32 *tmp = (u32*)*pvBuffer; |
223 | u32 *tmp = (u32*)*pvBuffer; |
224 | 224 | ||
225 | *pvBuffer += sizeof(u32); |
225 | *pvBuffer += sizeof(u32); |
226 | 226 | ||
227 | return tmp; |
227 | return tmp; |
228 | } |
228 | } |
229 | 229 | ||
230 | static void readByte(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
230 | static void readByte(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
231 | { |
231 | { |
232 | u8 tmp; |
232 | u8 tmp; |
233 | 233 | ||
234 | tmp = readb((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
234 | tmp = readb((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
235 | __put_user(tmp, increment8(pvBuffer)); |
235 | __put_user(tmp, increment8(pvBuffer)); |
236 | } |
236 | } |
237 | 237 | ||
238 | static void writeByte(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
238 | static void writeByte(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
239 | { |
239 | { |
240 | u8 tmp; |
240 | u8 tmp; |
241 | 241 | ||
242 | __get_user(tmp, increment8(pvBuffer)); |
242 | __get_user(tmp, increment8(pvBuffer)); |
243 | writeb(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage )); |
243 | writeb(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage )); |
244 | } |
244 | } |
245 | 245 | ||
246 | static void readWord(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
246 | static void readWord(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
247 | { |
247 | { |
248 | u16 tmp; |
248 | u16 tmp; |
249 | 249 | ||
250 | tmp = readw((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
250 | tmp = readw((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
251 | __put_user(tmp, increment16(pvBuffer)); |
251 | __put_user(tmp, increment16(pvBuffer)); |
252 | } |
252 | } |
253 | 253 | ||
254 | static void writeWord(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
254 | static void writeWord(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
255 | { |
255 | { |
256 | u16 tmp; |
256 | u16 tmp; |
257 | 257 | ||
258 | __get_user(tmp, increment16(pvBuffer)); |
258 | __get_user(tmp, increment16(pvBuffer)); |
259 | writew(tmp, (volatile void *) ( pd->pVME + dwLocalAddressInPage )); |
259 | writew(tmp, (volatile void *) ( pd->pVME + dwLocalAddressInPage )); |
260 | } |
260 | } |
261 | 261 | ||
262 | static void readLong(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
262 | static void readLong(DEVICE_OBJ *pd, void **pvBuffer, u32 dwLocalAddressInPage) |
263 | { |
263 | { |
264 | u32 tmp; |
264 | u32 tmp; |
265 | 265 | ||
266 | tmp = readl((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
266 | tmp = readl((const volatile void *) (pd->pVME + dwLocalAddressInPage)); |
267 | __put_user(tmp, increment32(pvBuffer)); |
267 | __put_user(tmp, increment32(pvBuffer)); |
268 | } |
268 | } |
269 | 269 | ||
270 | static void writeLong(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
270 | static void writeLong(DEVICE_OBJ *pd, u32 dwLocalAddressInPage, void **pvBuffer) |
271 | { |
271 | { |
272 | u32 tmp; |
272 | u32 tmp; |
273 | 273 | ||
274 | __get_user(tmp, increment32(pvBuffer)); |
274 | __get_user(tmp, increment32(pvBuffer)); |
275 | writel(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage)); |
275 | writel(tmp, (volatile void *) (pd->pVME + dwLocalAddressInPage)); |
276 | } |
276 | } |
277 | 277 | ||
278 | /* test alignment functions -----------------------------------------------------------------------*/ |
278 | /* test alignment functions -----------------------------------------------------------------------*/ |
279 | static int MisalignmentForByteAccess(loff_t offset) |
279 | static int MisalignmentForByteAccess(loff_t offset) |
280 | { |
280 | { |
281 | return 0; |
281 | return 0; |
282 | } |
282 | } |
283 | 283 | ||
284 | static int MisalignmentForWordAccess(loff_t offset) |
284 | static int MisalignmentForWordAccess(loff_t offset) |
285 | { |
285 | { |
286 | return(offset & 1); |
286 | return(offset & 1); |
287 | } |
287 | } |
288 | 288 | ||
289 | static int MisalignmentForLongAccess(loff_t offset) |
289 | static int MisalignmentForLongAccess(loff_t offset) |
290 | { |
290 | { |
291 | return(offset & 3); |
291 | return(offset & 3); |
292 | } |
292 | } |
293 | 293 | ||
294 | // helper functions -------------------------------------------------------------------------------- |
294 | // helper functions -------------------------------------------------------------------------------- |
295 | int check_command(const PCIVME_INIT_ELEMENT *psInitElement) |
295 | int check_command(const PCIVME_INIT_ELEMENT *psInitElement) |
296 | { |
296 | { |
297 | u16 range; |
297 | u16 range; |
298 | u16 access_size; |
298 | u16 access_size; |
299 | 299 | ||
300 | // PRINTK(KERN_DEBUG "%s : check_command()\n", DEVICE_NAME); |
300 | // PRINTK(KERN_DEBUG "%s : check_command()\n", DEVICE_NAME); |
301 | 301 | ||
302 | switch (psInitElement->bDestination) |
302 | switch (psInitElement->bDestination) |
303 | { |
303 | { |
304 | case LCR: |
304 | case LCR: |
305 | range = 0x54; |
305 | range = 0x54; |
306 | break; |
306 | break; |
307 | case IFR: |
307 | case IFR: |
308 | range = 0x0c; |
308 | range = 0x0c; |
309 | break; |
309 | break; |
310 | case VIC: |
310 | case VIC: |
311 | range = 0xe4; |
311 | range = 0xe4; |
312 | if ((psInitElement->wOffset & 3) != 3) |
312 | if ((psInitElement->wOffset & 3) != 3) |
313 | return -EINVAL; |
313 | return -EINVAL; |
314 | break; |
314 | break; |
315 | default: |
315 | default: |
316 | return -EINVAL; |
316 | return -EINVAL; |
317 | break; |
317 | break; |
318 | } |
318 | } |
319 | 319 | ||
320 | // check alignment and allowed address range |
320 | // check alignment and allowed address range |
321 | switch (psInitElement->bAccessType) |
321 | switch (psInitElement->bAccessType) |
322 | { |
322 | { |
323 | case LONG_ACCESS: |
323 | case LONG_ACCESS: |
324 | if (psInitElement->wOffset & 3) |
324 | if (psInitElement->wOffset & 3) |
325 | return -EINVAL; |
325 | return -EINVAL; |
326 | access_size = sizeof(u32); |
326 | access_size = sizeof(u32); |
327 | break; |
327 | break; |
328 | case WORD_ACCESS: |
328 | case WORD_ACCESS: |
329 | if (psInitElement->wOffset & 1) |
329 | if (psInitElement->wOffset & 1) |
330 | return -EINVAL; |
330 | return -EINVAL; |
331 | access_size = sizeof(u16); |
331 | access_size = sizeof(u16); |
332 | break; |
332 | break; |
333 | case BYTE_ACCESS: |
333 | case BYTE_ACCESS: |
334 | access_size = sizeof(u8); |
334 | access_size = sizeof(u8); |
335 | break; |
335 | break; |
336 | default : |
336 | default : |
337 | return -EINVAL; |
337 | return -EINVAL; |
338 | break; |
338 | break; |
339 | } |
339 | } |
340 | 340 | ||
341 | if ((psInitElement->wOffset + access_size) > range) |
341 | if ((psInitElement->wOffset + access_size) > range) |
342 | return -EINVAL; // ignore it |
342 | return -EINVAL; // ignore it |
343 | 343 | ||
344 | return 0; |
344 | return 0; |
345 | } |
345 | } |
346 | 346 | ||
347 | static int CmdMachine(DEVICE_OBJ *pd, const PCIVME_INIT_ELEMENT *psInitElement) |
347 | static int CmdMachine(DEVICE_OBJ *pd, const PCIVME_INIT_ELEMENT *psInitElement) |
348 | { |
348 | { |
349 | u32 adr; |
349 | u32 adr; |
350 | int err; |
350 | int err; |
351 | 351 | ||
352 | PRINTK |
352 | //PRINTK(KERN_DEBUG "%s : CmdMachine()\n", DEVICE_NAME); |
353 | 353 | ||
354 | // loop through the init (or deinit) list |
354 | // loop through the init (or deinit) list |
355 | while (psInitElement->bDestination != STOP) |
355 | while (psInitElement->bDestination != STOP) |
356 | { |
356 | { |
357 | err = check_command(psInitElement); |
357 | err = check_command(psInitElement); |
358 | if (!err) |
358 | if (!err) |
359 | { |
359 | { |
360 | switch (psInitElement->bDestination) |
360 | switch (psInitElement->bDestination) |
361 | { |
361 | { |
362 | case LCR: |
362 | case LCR: |
363 | adr = pd->pLCR; |
363 | adr = pd->pLCR; |
364 | break; |
364 | break; |
365 | case VIC: |
365 | case VIC: |
366 | adr = pd->pCtl + VICBASE; |
366 | adr = pd->pCtl + VICBASE; |
367 | break; |
367 | break; |
368 | case IFR: |
368 | case IFR: |
369 | adr = pd->pCtl + CSR; |
369 | adr = pd->pCtl + CSR; |
370 | break; |
370 | break; |
371 | default: |
371 | default: |
372 | return -EINVAL; |
372 | return -EINVAL; |
373 | } |
373 | } |
374 | 374 | ||
375 | switch (psInitElement->bAccessType) |
375 | switch (psInitElement->bAccessType) |
376 | { |
376 | { |
377 | case LONG_ACCESS: |
377 | case LONG_ACCESS: |
378 | writel(psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
378 | writel(psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
379 | break; |
379 | break; |
380 | case WORD_ACCESS: |
380 | case WORD_ACCESS: |
381 | writew((u16)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
381 | writew((u16)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
382 | break; |
382 | break; |
383 | case BYTE_ACCESS: |
383 | case BYTE_ACCESS: |
384 | writeb((u8)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
384 | writeb((u8)psInitElement->dwValue, (volatile void *) (adr + psInitElement->wOffset)); |
385 | break; |
385 | break; |
386 | default: |
386 | default: |
387 | return -EINVAL; |
387 | return -EINVAL; |
388 | } |
388 | } |
389 | } |
389 | } |
390 | else |
390 | else |
391 | return err; |
391 | return err; |
392 | 392 | ||
393 | psInitElement++; |
393 | psInitElement++; |
394 | } |
394 | } |
395 | 395 | ||
396 | return 0; |
396 | return 0; |
397 | } |
397 | } |
398 | 398 | ||
399 | // all ioctls -------------------------------------------------------------------------------------- |
399 | // all ioctls -------------------------------------------------------------------------------------- |
400 | static int init_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *init) |
400 | static int init_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *init) |
401 | { |
401 | { |
402 | int err; |
402 | int err; |
403 | PCIVME_INIT_ELEMENT *element = init->sVie; |
403 | PCIVME_INIT_ELEMENT *element = init->sVie; |
404 | 404 | ||
405 | PRINTK( |
405 | PRINTK(KERN_INFO "%s : init_hardware()\n", DEVICE_NAME); |
406 | 406 | ||
407 | err = CmdMachine(pd, element); |
407 | err = CmdMachine(pd, element); |
408 | if (err) |
408 | if (err) |
409 | { |
409 | { |
410 | PRINTK(KERN_DEBUG "%s : init failed with err = %d!\n", DEVICE_NAME, err); |
410 | PRINTK(KERN_DEBUG "%s : init failed with err = %d!\n", DEVICE_NAME, err); |
411 | return err; |
411 | return err; |
412 | } |
412 | } |
413 | 413 | ||
414 | // sync storage with hardware |
414 | // sync storage with hardware |
415 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
415 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
416 | pd->dwCurrentPageAddress = readl((const volatile void *) pd->pAdrReg) & HI_ADDRESS_MASK; |
416 | pd->dwCurrentPageAddress = readl((const volatile void *) pd->pAdrReg) & HI_ADDRESS_MASK; |
417 | 417 | ||
418 | return 0; |
418 | return 0; |
419 | } |
419 | } |
420 | 420 | ||
421 | static int deinit_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *deinit) |
421 | static int deinit_hardware(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_INIT_COMMAND *deinit) |
422 | { |
422 | { |
423 | int err; |
423 | int err; |
424 | PCIVME_INIT_ELEMENT *element = deinit->sVie; |
424 | PCIVME_INIT_ELEMENT *element = deinit->sVie; |
425 | 425 | ||
426 | PRINTK(KERN_DEBUG "%s : deinit_hardware()\n", DEVICE_NAME); |
426 | PRINTK(KERN_DEBUG "%s : deinit_hardware()\n", DEVICE_NAME); |
427 | 427 | ||
428 | err = CmdMachine(pd, deinit_element_pre); |
428 | err = CmdMachine(pd, deinit_element_pre); |
429 | if (err) |
429 | if (err) |
430 | goto fail; |
430 | goto fail; |
431 | 431 | ||
432 | err = CmdMachine(pd, element); |
432 | err = CmdMachine(pd, element); |
433 | if (err) |
433 | if (err) |
434 | goto fail; |
434 | goto fail; |
435 | 435 | ||
436 | err = CmdMachine(pd, deinit_element_post); |
436 | err = CmdMachine(pd, deinit_element_post); |
437 | if (err) |
437 | if (err) |
438 | goto fail; |
438 | goto fail; |
439 | 439 | ||
440 | return 0; |
440 | return 0; |
441 | 441 | ||
442 | fail: |
442 | fail: |
443 | return err; |
443 | return err; |
444 | } |
444 | } |
445 | 445 | ||
446 | static int access_command(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_ACCESS_COMMAND *cmd) |
446 | static int access_command(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_ACCESS_COMMAND *cmd) |
447 | { |
447 | { |
448 | PRINTK(KERN_DEBUG "%s : access_command()\n", DEVICE_NAME); |
448 | PRINTK(KERN_DEBUG "%s : access_command()\n", DEVICE_NAME); |
449 | 449 | ||
450 | pp->bModifier = cmd->bModifier; |
450 | pp->bModifier = cmd->bModifier; |
451 | pp->bAccessType = cmd->bAccessType; |
451 | pp->bAccessType = cmd->bAccessType; |
452 | pp->bIncrement = cmd->bIncrement; |
452 | pp->bIncrement = cmd->bIncrement; |
453 | 453 | ||
454 | switch (pp->bAccessType) |
454 | switch (pp->bAccessType) |
455 | { |
455 | { |
456 | case BYTE_ACCESS: |
456 | case BYTE_ACCESS: |
457 | pp->read = readByte; |
457 | pp->read = readByte; |
458 | pp->write = writeByte; |
458 | pp->write = writeByte; |
459 | pp->AlignmentCheck = MisalignmentForByteAccess; |
459 | pp->AlignmentCheck = MisalignmentForByteAccess; |
460 | break; |
460 | break; |
461 | case WORD_ACCESS: |
461 | case WORD_ACCESS: |
462 | pp->read = readWord; |
462 | pp->read = readWord; |
463 | pp->write = writeWord; |
463 | pp->write = writeWord; |
464 | pp->AlignmentCheck = MisalignmentForWordAccess; |
464 | pp->AlignmentCheck = MisalignmentForWordAccess; |
465 | break; |
465 | break; |
466 | case LONG_ACCESS: |
466 | case LONG_ACCESS: |
467 | pp->read = readLong; |
467 | pp->read = readLong; |
468 | pp->write = writeLong; |
468 | pp->write = writeLong; |
469 | pp->AlignmentCheck = MisalignmentForLongAccess; |
469 | pp->AlignmentCheck = MisalignmentForLongAccess; |
470 | break; |
470 | break; |
471 | default: |
471 | default: |
472 | return -EINVAL; |
472 | return -EINVAL; |
473 | } |
473 | } |
474 | 474 | ||
475 | return 0; |
475 | return 0; |
476 | } |
476 | } |
477 | 477 | ||
478 | static int get_static_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_STATIC_STATUS *static_status) |
478 | static int get_static_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_STATIC_STATUS *static_status) |
479 | { |
479 | { |
480 | PRINTK(KERN_DEBUG "%s : get_static_status()\n", DEVICE_NAME); |
480 | PRINTK(KERN_DEBUG "%s : get_static_status()\n", DEVICE_NAME); |
481 | 481 | ||
482 | static_status->bConnected = pd->bConnected; |
482 | static_status->bConnected = pd->bConnected; |
483 | static_status->cModuleNumber = pd->cModuleNumber; |
483 | static_status->cModuleNumber = pd->cModuleNumber; |
484 | static_status->cFPGAVersion = pd->cFPGAVersion; |
484 | static_status->cFPGAVersion = pd->cFPGAVersion; |
485 | static_status->cSystemController = pd->cSystemController; |
485 | static_status->cSystemController = pd->cSystemController; |
486 | static_status->cWordMode = pd->cWordMode; |
486 | static_status->cWordMode = pd->cWordMode; |
487 | 487 | ||
488 | return 0; |
488 | return 0; |
489 | } |
489 | } |
490 | 490 | ||
491 | static int get_dynamic_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_DYNAMIC_STATUS *dynamic_status) |
491 | static int get_dynamic_status(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_DYNAMIC_STATUS *dynamic_status) |
492 | { |
492 | { |
493 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
493 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
494 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
494 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
495 | 495 | ||
496 | PRINTK(KERN_DEBUG "%s : get_dynamic_status()\n", DEVICE_NAME); |
496 | PRINTK(KERN_DEBUG "%s : get_dynamic_status()\n", DEVICE_NAME); |
497 | 497 | ||
498 | dynamic_status->bConnected = (cntrl & 0x0800) ? 1 : 0; |
498 | dynamic_status->bConnected = (cntrl & 0x0800) ? 1 : 0; |
499 | dynamic_status->bPCIADAIrq = (intCSR & 0x0020) ? 1 : 0; |
499 | dynamic_status->bPCIADAIrq = (intCSR & 0x0020) ? 1 : 0; |
500 | dynamic_status->bVMEMMIrq = (intCSR & 0x0004) ? 1 : 0; |
500 | dynamic_status->bVMEMMIrq = (intCSR & 0x0004) ? 1 : 0; |
501 | 501 | ||
502 | return 0; |
502 | return 0; |
503 | } |
503 | } |
504 | 504 | ||
505 | static int read_vector_polling(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector) |
505 | static int read_vector_polling(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector) |
506 | { |
506 | { |
507 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
507 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
508 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
508 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
509 | 509 | ||
510 | PRINTK(KERN_DEBUG "%s : read_vector()\n", DEVICE_NAME); |
510 | PRINTK(KERN_DEBUG "%s : read_vector()\n", DEVICE_NAME); |
511 | 511 | ||
512 | vector->dwStatusID = 0; |
512 | vector->dwStatusID = 0; |
513 | vector->bLevel = 0; |
513 | vector->bLevel = 0; |
514 | vector->bPCIADAIrq = 0; |
514 | vector->bPCIADAIrq = 0; |
515 | 515 | ||
516 | if (intCSR & 0x20) // check for PCIADA interrupt |
516 | if (intCSR & 0x20) // check for PCIADA interrupt |
517 | { |
517 | { |
518 | vector->bPCIADAIrq = 1; |
518 | vector->bPCIADAIrq = 1; |
519 | vector->dwStatusID = 1; // force for PCIADA irqs |
519 | vector->dwStatusID = 1; // force for PCIADA irqs |
520 | 520 | ||
521 | writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl); // clear pending PCIADA irq |
521 | writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl); // clear pending PCIADA irq |
522 | writew(cntrl, (volatile void *) pd->pPCIADACntrl); |
522 | writew(cntrl, (volatile void *) pd->pPCIADACntrl); |
523 | } |
523 | } |
524 | else |
524 | else |
525 | { |
525 | { |
526 | if ((cntrl & 0x0980) == 0x0980) // check if VMEMM is connected and ready |
526 | if ((cntrl & 0x0980) == 0x0980) // check if VMEMM is connected and ready |
527 | { |
527 | { |
528 | vector->bLevel = (u8)readw((const volatile void *) ( pd->pCtl + VICRES )); |
528 | vector->bLevel = (u8)readw((const volatile void *) ( pd->pCtl + VICRES )); |
529 | if (vector->bLevel & 1) |
529 | if (vector->bLevel & 1) |
530 | { |
530 | { |
531 | if (vector->bLevel != 1) |
531 | if (vector->bLevel != 1) |
532 | vector->dwStatusID = (u32)readb((const volatile void *) (pd->pCtl + VECBASE + vector->bLevel)); |
532 | vector->dwStatusID = (u32)readb((const volatile void *) (pd->pCtl + VECBASE + vector->bLevel)); |
533 | 533 | ||
534 | vector->bLevel >>= 1; |
534 | vector->bLevel >>= 1; |
535 | } |
535 | } |
536 | } |
536 | } |
537 | } |
537 | } |
538 | return 0; |
538 | return 0; |
539 | } |
539 | } |
540 | 540 | ||
541 | static int read_vector_blocking(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector, struct file *pFile) |
541 | static int read_vector_blocking(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VECTOR_LEVEL *vector, struct file *pFile) |
542 | { |
542 | { |
543 | int error; |
543 | int error; |
544 | 544 | ||
545 | vector->dwStatusID = 0; |
545 | vector->dwStatusID = 0; |
546 | vector->bLevel = 0; |
546 | vector->bLevel = 0; |
547 | vector->bPCIADAIrq = 0; |
547 | vector->bPCIADAIrq = 0; |
548 | 548 | ||
549 | // support nonblocking read if requested |
549 | // support nonblocking read if requested |
550 | if ((pFile->f_flags & O_NONBLOCK) && (!pd->wIrqStatus)) |
550 | if ((pFile->f_flags & O_NONBLOCK) && (!pd->wIrqStatus)) |
551 | return -EAGAIN; |
551 | return -EAGAIN; |
552 | 552 | ||
553 | // sleep until data are available |
553 | // sleep until data are available |
554 | if ((error = wait_event_interruptible(pd->event_queue, (pd->wIrqStatus)))) |
554 | if ((error = wait_event_interruptible(pd->event_queue, (pd->wIrqStatus)))) |
555 | return error; |
555 | return error; |
556 | 556 | ||
557 | error = read_vector_polling(pp, pd, vector); |
557 | error = read_vector_polling(pp, pd, vector); |
558 | 558 | ||
559 | pd->wIrqStatus = 0; // clear the status since it is read |
559 | pd->wIrqStatus = 0; // clear the status since it is read |
560 | 560 | ||
561 | return error; |
561 | return error; |
562 | } |
562 | } |
563 | 563 | ||
564 | 564 | ||
565 | static int control_interrupts(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_IRQ_CONTROL *irq_control) |
565 | static int control_interrupts(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_IRQ_CONTROL *irq_control) |
566 | { |
566 | { |
567 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
567 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
568 | u8 ret = (intCSR & 0x40) ? 1 : 0; |
568 | u8 ret = (intCSR & 0x40) ? 1 : 0; |
569 | 569 | ||
570 | PRINTK(KERN_DEBUG "%s : control_interrupts()\n", DEVICE_NAME); |
570 | PRINTK(KERN_DEBUG "%s : control_interrupts()\n", DEVICE_NAME); |
571 | 571 | ||
572 | if (irq_control->bEnable) |
572 | if (irq_control->bEnable) |
573 | writew(intCSR | 0x40, (volatile void *) pd->pPCIADAIntCSR); |
573 | writew(intCSR | 0x40, (volatile void *) pd->pPCIADAIntCSR); |
574 | else |
574 | else |
575 | writew(intCSR & ~0x40, (volatile void *) pd->pPCIADAIntCSR); |
575 | writew(intCSR & ~0x40, (volatile void *) pd->pPCIADAIntCSR); |
576 | 576 | ||
577 | // return the switch before set |
577 | // return the switch before set |
578 | irq_control->bEnable = ret; |
578 | irq_control->bEnable = ret; |
579 | 579 | ||
580 | return 0; |
580 | return 0; |
581 | } |
581 | } |
582 | 582 | ||
583 | static int VME_TAS(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_TAS_STRUCT *tas_cmd) |
583 | static int VME_TAS(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_TAS_STRUCT *tas_cmd) |
584 | { |
584 | { |
585 | u32 access_adr = pd->pVME + (tas_cmd->dwAddress & LO_ADDRESS_MASK); // make low part of address |
585 | u32 access_adr = pd->pVME + (tas_cmd->dwAddress & LO_ADDRESS_MASK); // make low part of address |
586 | u8 data; |
586 | u8 data; |
587 | 587 | ||
588 | // save old contents |
588 | // save old contents |
589 | u32 old_address = readl((const volatile void *) pd->pAdrReg); |
589 | u32 old_address = readl((const volatile void *) pd->pAdrReg); |
590 | u16 old_CSR = readw((const volatile void *) pd->pCSR); |
590 | u16 old_CSR = readw((const volatile void *) pd->pCSR); |
591 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
591 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
592 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
592 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
593 | 593 | ||
594 | PRINTK(KERN_DEBUG "%s : VME_TAS()\n", DEVICE_NAME); |
594 | PRINTK(KERN_DEBUG "%s : VME_TAS()\n", DEVICE_NAME); |
595 | 595 | ||
596 | // set new contents |
596 | // set new contents |
597 | writew(DISABLE_PCIADA_IRQS, (volatile void *) pd->pPCIADAIntCSR); |
597 | writew(DISABLE_PCIADA_IRQS, (volatile void *) pd->pPCIADAIntCSR); |
598 | writeb((u8)tas_cmd->bModifier & 0x3f, (volatile void *) pd->pAdrMod); |
598 | writeb((u8)tas_cmd->bModifier & 0x3f, (volatile void *) pd->pAdrMod); |
599 | writel(tas_cmd->dwAddress, (volatile void *) pd->pAdrReg); |
599 | writel(tas_cmd->dwAddress, (volatile void *) pd->pAdrReg); |
600 | writew(old_CSR | FLAG_RMC, (volatile void *) pd->pCSR); |
600 | writew(old_CSR | FLAG_RMC, (volatile void *) pd->pCSR); |
601 | 601 | ||
602 | // do the read - modify - write |
602 | // do the read - modify - write |
603 | data = readb((const volatile void *) access_adr); |
603 | data = readb((const volatile void *) access_adr); |
604 | writeb(tas_cmd->bContent, (volatile void *) access_adr); |
604 | writeb(tas_cmd->bContent, (volatile void *) access_adr); |
605 | 605 | ||
606 | // restore old contents |
606 | // restore old contents |
607 | writeb(pd->bCurrentModifier, (volatile void *) pd->pAdrMod); |
607 | writeb(pd->bCurrentModifier, (volatile void *) pd->pAdrMod); |
608 | writew(old_CSR, (volatile void *) pd->pCSR); |
608 | writew(old_CSR, (volatile void *) pd->pCSR); |
609 | writel(old_address, (volatile void *) pd->pAdrReg); |
609 | writel(old_address, (volatile void *) pd->pAdrReg); |
610 | writew(intCSR, (volatile void *) pd->pPCIADAIntCSR); |
610 | writew(intCSR, (volatile void *) pd->pPCIADAIntCSR); |
611 | 611 | ||
612 | // get back read data |
612 | // get back read data |
613 | tas_cmd->bContent = data; |
613 | tas_cmd->bContent = data; |
614 | 614 | ||
615 | return 0; |
615 | return 0; |
616 | } |
616 | } |
617 | 617 | ||
618 | static int VMEMM_RESET(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_RESET_COMMAND *reset_cmd) |
618 | static int VMEMM_RESET(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_RESET_COMMAND *reset_cmd) |
619 | { |
619 | { |
620 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
620 | u16 cntrl = readw((const volatile void *) pd->pPCIADACntrl); |
621 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
621 | u16 intCSR = readw((const volatile void *) pd->pPCIADAIntCSR); |
622 | int status = 0; |
622 | int status = 0; |
623 | 623 | ||
624 | PRINTK( |
624 | PRINTK(KERN_INFO "%s : VMEMM_RESET()\n", DEVICE_NAME); |
625 | 625 | ||
626 | // am I connected and switched on?? |
626 | // am I connected and switched on?? |
627 | if ((cntrl & 0x0980) == 0x0980) |
627 | if ((cntrl & 0x0980) == 0x0980) |
628 | { |
628 | { |
629 | // do command |
629 | // do command |
630 | switch (reset_cmd->bCommand) |
630 | switch (reset_cmd->bCommand) |
631 | { |
631 | { |
632 | case POLL_RESET_CMD: |
632 | case POLL_RESET_CMD: |
633 | break; |
633 | break; |
634 | case VME_RESET_CMD: |
634 | case VME_RESET_CMD: |
635 | writeb(0, (volatile void *) pd->pAdrMod); |
635 | writeb(0, (volatile void *) pd->pAdrMod); |
636 | writeb(0xf0, (volatile void *) (pd->pCtl + VICBASE + SRR)); // make VME reset |
636 | writeb(0xf0, (volatile void *) (pd->pCtl + VICBASE + SRR)); // make VME reset |
637 | break; |
637 | break; |
638 | case LOCAL_RESET_CMD: |
638 | case LOCAL_RESET_CMD: |
639 | writeb(0, (volatile void *) pd->pAdrMod); |
639 | writeb(0, (volatile void *) pd->pAdrMod); |
640 | writew(LOCAL_RESET, (volatile void *) (pd->pCtl + VICRES)); |
640 | writew(LOCAL_RESET, (volatile void *) (pd->pCtl + VICRES)); |
641 | break; |
641 | break; |
642 | case GLOBAL_RESET_CMD: |
642 | case GLOBAL_RESET_CMD: |
643 | writeb(0, (volatile void *) pd->pAdrMod); |
643 | writeb(0, (volatile void *) pd->pAdrMod); |
644 | writew(GLOBAL_RESET, (volatile void *) (pd->pCtl + VICRES)); |
644 | writew(GLOBAL_RESET, (volatile void *) (pd->pCtl + VICRES)); |
645 | break; |
645 | break; |
646 | 646 | ||
647 | default: status = -EINVAL; |
647 | default: status = -EINVAL; |
648 | } |
648 | } |
649 | 649 | ||
650 | // inhibit PCIADA generated irqs |
650 | // inhibit PCIADA generated irqs |
651 | writew(DISABLE_PCIADA_IRQS, (volatile void *) pd->pPCIADAIntCSR); |
651 | writew(DISABLE_PCIADA_IRQS, (volatile void *) pd->pPCIADAIntCSR); |
652 | 652 | ||
653 | // always poll reset status - access will sometimes generate PCIADA #2 interrupt |
653 | // always poll reset status - access will sometimes generate PCIADA #2 interrupt |
654 | reset_cmd->bResult = readb((const volatile void *) pd->pAdrMod); |
654 | reset_cmd->bResult = readb((const volatile void *) pd->pAdrMod); |
655 | 655 | ||
656 | // reset any pending PCIADA interrupt #2 |
656 | // reset any pending PCIADA interrupt #2 |
657 | writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl); |
657 | writew(cntrl & ~0x0100, (volatile void *) pd->pPCIADACntrl); |
658 | writew(cntrl , (volatile void *) pd->pPCIADACntrl); |
658 | writew(cntrl , (volatile void *) pd->pPCIADACntrl); |
659 | 659 | ||
660 | // restore IRQStatus |
660 | // restore IRQStatus |
661 | writew(intCSR , (volatile void *) pd->pPCIADAIntCSR); |
661 | writew(intCSR , (volatile void *) pd->pPCIADAIntCSR); |
662 | } |
662 | } |
663 | else |
663 | else |
664 | status = -EBUSY; |
664 | status = -EBUSY; |
665 | 665 | ||
666 | // sync storage with hardware |
666 | // sync storage with hardware |
667 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
667 | pd->bCurrentModifier = readb((const volatile void *) pd->pAdrMod) & 0x3f; |
668 | 668 | ||
669 | return status; |
669 | return status; |
670 | } |
670 | } |
671 | 671 | ||
672 | static int access_VIC68A(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VIC68A_ACTION *action) |
672 | static int access_VIC68A(PATH_OBJ *pp, DEVICE_OBJ *pd, PCIVME_VIC68A_ACTION *action) |
673 | { |
673 | { |
674 | int nStatus = 0; |
674 | int nStatus = 0; |
675 | 675 | ||
676 | PRINTK(KERN_DEBUG "%s : access_VIC68A()\n", DEVICE_NAME); |
676 | PRINTK(KERN_DEBUG "%s : access_VIC68A()\n", DEVICE_NAME); |
677 | 677 | ||
678 | if ((action->wRegisterAddress <= SRR) && ((action->wRegisterAddress & 0x03) == 3)) |
678 | if ((action->wRegisterAddress <= SRR) && ((action->wRegisterAddress & 0x03) == 3)) |
679 | { |
679 | { |
680 | u32 dwAddress; |
680 | u32 dwAddress; |
681 | u8 bByte = 0; |
681 | u8 bByte = 0; |
682 | 682 | ||
683 | dwAddress = (pd->pCtl + VICBASE + action->wRegisterAddress); |
683 | dwAddress = (pd->pCtl + VICBASE + action->wRegisterAddress); |
684 | 684 | ||
685 | switch (action->bAccessMode) |
685 | switch (action->bAccessMode) |
686 | { |
686 | { |
687 | case VIC68A_WRITE_ONLY: |
687 | case VIC68A_WRITE_ONLY: |
688 | writeb(action->bContent, (volatile void *) dwAddress); |
688 | writeb(action->bContent, (volatile void *) dwAddress); |
689 | break; |
689 | break; |
690 | case VIC68A_WRITE: |
690 | case VIC68A_WRITE: |
691 | writeb(action->bContent, (volatile void *) dwAddress); |
691 | writeb(action->bContent, (volatile void *) dwAddress); |
692 | action->bContent = readb((const volatile void *) dwAddress); |
692 | action->bContent = readb((const volatile void *) dwAddress); |
693 | break; |
693 | break; |
694 | case VIC68A_OR: |
694 | case VIC68A_OR: |
695 | bByte = readb((const volatile void *) dwAddress); |
695 | bByte = readb((const volatile void *) dwAddress); |
696 | bByte |= action->bContent; |
696 | bByte |= action->bContent; |
697 | writeb(bByte, (volatile void *) dwAddress); |
697 | writeb(bByte, (volatile void *) dwAddress); |
698 | action->bContent = readb((const volatile void *) dwAddress); |
698 | action->bContent = readb((const volatile void *) dwAddress); |
699 | break; |
699 | break; |
700 | case VIC68A_AND: |
700 | case VIC68A_AND: |
701 | bByte = readb((const volatile void *) dwAddress); |
701 | bByte = readb((const volatile void *) dwAddress); |
702 | bByte &= action->bContent; |
702 | bByte &= action->bContent; |
703 | writeb(bByte, (volatile void *) dwAddress); |
703 | writeb(bByte, (volatile void *) dwAddress); |
704 | action->bContent = readb((const volatile void *) dwAddress); |
704 | action->bContent = readb((const volatile void *) dwAddress); |
705 | break; |
705 | break; |
706 | case VIC68A_READ: |
706 | case VIC68A_READ: |
707 | action->bContent = readb((const volatile void *) dwAddress); |
707 | action->bContent = readb((const volatile void *) dwAddress); |
708 | break; |
708 | break; |
709 | default: |
709 | default: |
710 | nStatus = -EINVAL; |
710 | nStatus = -EINVAL; |
711 | } |
711 | } |
712 | } |
712 | } |
713 | else |
713 | else |
714 | nStatus = -EINVAL; |
714 | nStatus = -EINVAL; |
715 | 715 | ||
716 | return nStatus; |
716 | return nStatus; |
717 | } |
717 | } |
718 | 718 | ||
719 | // the dispatcher ---------------------------------------------------------------------------------- |
719 | // the dispatcher ---------------------------------------------------------------------------------- |
720 | int pcivme_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg) |
720 | int pcivme_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg) |
721 | { |
721 | { |
722 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
722 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
723 | DEVICE_OBJ *pd = pp->pDo; |
723 | DEVICE_OBJ *pd = pp->pDo; |
724 | int err = 1; |
724 | int err = 1; |
725 | 725 | ||
726 | PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd)); |
726 | PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd)); |
727 | 727 | ||
728 | if (_IOC_TYPE(cmd) != PCIVME_MAGIC) |
728 | if (_IOC_TYPE(cmd) != PCIVME_MAGIC) |
729 | return -EINVAL; |
729 | return -EINVAL; |
730 | 730 | ||
731 | // check for accessible user buffer |
731 | // check for accessible user buffer |
732 | if (_IOC_DIR(cmd) & _IOC_READ) |
732 | if (_IOC_DIR(cmd) & _IOC_READ) |
733 | err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); |
733 | err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); |
734 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
734 | if (_IOC_DIR(cmd) & _IOC_WRITE) |
735 | err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); |
735 | err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); |
736 | if (err) |
736 | if (err) |
737 | return -EFAULT; |
737 | return -EFAULT; |
738 | 738 | ||
739 | switch (_IOC_NR(cmd)) |
739 | switch (_IOC_NR(cmd)) |
740 | { |
740 | { |
741 | case _IOC_NR(PCIVME_READ_VECTOR_BLOCK): |
741 | case _IOC_NR(PCIVME_READ_VECTOR_BLOCK): |
742 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL)) |
742 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL)) |
743 | return -EINVAL; |
743 | return -EINVAL; |
744 | return read_vector_blocking(pp, pd, (PCIVME_VECTOR_LEVEL *)arg, pFile); |
744 | return read_vector_blocking(pp, pd, (PCIVME_VECTOR_LEVEL *)arg, pFile); |
745 | 745 | ||
746 | case _IOC_NR(PCIVME_READ_VECTOR_POLL): |
746 | case _IOC_NR(PCIVME_READ_VECTOR_POLL): |
747 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL)) |
747 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VECTOR_LEVEL)) |
748 | return -EINVAL; |
748 | return -EINVAL; |
749 | return read_vector_polling(pp, pd, (PCIVME_VECTOR_LEVEL *)arg); |
749 | return read_vector_polling(pp, pd, (PCIVME_VECTOR_LEVEL *)arg); |
750 | 750 | ||
751 | case _IOC_NR(PCIVME_CONTROL_INTERRUPTS): |
751 | case _IOC_NR(PCIVME_CONTROL_INTERRUPTS): |
752 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_IRQ_CONTROL)) |
752 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_IRQ_CONTROL)) |
753 | return -EINVAL; |
753 | return -EINVAL; |
754 | return control_interrupts(pp, pd, (PCIVME_IRQ_CONTROL *)arg); |
754 | return control_interrupts(pp, pd, (PCIVME_IRQ_CONTROL *)arg); |
755 | 755 | ||
756 | case _IOC_NR(PCIVME_TAS): |
756 | case _IOC_NR(PCIVME_TAS): |
757 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_TAS_STRUCT)) |
757 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_TAS_STRUCT)) |
758 | return -EINVAL; |
758 | return -EINVAL; |
759 | return VME_TAS(pp, pd, (PCIVME_TAS_STRUCT *)arg); |
759 | return VME_TAS(pp, pd, (PCIVME_TAS_STRUCT *)arg); |
760 | 760 | ||
761 | case _IOC_NR(PCIVME_ACCESS_VIC68A): |
761 | case _IOC_NR(PCIVME_ACCESS_VIC68A): |
762 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VIC68A_ACTION)) |
762 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_VIC68A_ACTION)) |
763 | return -EINVAL; |
763 | return -EINVAL; |
764 | return access_VIC68A(pp, pd, (PCIVME_VIC68A_ACTION *)arg); |
764 | return access_VIC68A(pp, pd, (PCIVME_VIC68A_ACTION *)arg); |
765 | 765 | ||
766 | case _IOC_NR(PCIVME_GET_DYNAMIC_STATUS): |
766 | case _IOC_NR(PCIVME_GET_DYNAMIC_STATUS): |
767 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_DYNAMIC_STATUS)) |
767 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_DYNAMIC_STATUS)) |
768 | return -EINVAL; |
768 | return -EINVAL; |
769 | return get_dynamic_status(pp, pd, (PCIVME_DYNAMIC_STATUS *)arg); |
769 | return get_dynamic_status(pp, pd, (PCIVME_DYNAMIC_STATUS *)arg); |
770 | 770 | ||
771 | case _IOC_NR(PCIVME_RESET): |
771 | case _IOC_NR(PCIVME_RESET): |
772 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_RESET_COMMAND)) |
772 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_RESET_COMMAND)) |
773 | return -EINVAL; |
773 | return -EINVAL; |
774 | return VMEMM_RESET(pp, pd, (PCIVME_RESET_COMMAND *)arg); |
774 | return VMEMM_RESET(pp, pd, (PCIVME_RESET_COMMAND *)arg); |
775 | 775 | ||
776 | case _IOC_NR(PCIVME_SET_ACCESS_PARA): |
776 | case _IOC_NR(PCIVME_SET_ACCESS_PARA): |
777 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_ACCESS_COMMAND)) |
777 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_ACCESS_COMMAND)) |
778 | return -EINVAL; |
778 | return -EINVAL; |
779 | return access_command(pp, pd, (PCIVME_ACCESS_COMMAND *)arg); |
779 | return access_command(pp, pd, (PCIVME_ACCESS_COMMAND *)arg); |
780 | 780 | ||
781 | case _IOC_NR(PCIVME_GET_STATIC_STATUS): |
781 | case _IOC_NR(PCIVME_GET_STATIC_STATUS): |
782 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_STATIC_STATUS)) |
782 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_STATIC_STATUS)) |
783 | return -EINVAL; |
783 | return -EINVAL; |
784 | return get_static_status(pp, pd, (PCIVME_STATIC_STATUS *)arg); |
784 | return get_static_status(pp, pd, (PCIVME_STATIC_STATUS *)arg); |
785 | 785 | ||
786 | case _IOC_NR(PCIVME_INIT_HARDWARE): |
786 | case _IOC_NR(PCIVME_INIT_HARDWARE): |
787 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND)) |
787 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND)) |
788 | return -EINVAL; |
788 | return -EINVAL; |
789 | return init_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg); |
789 | return init_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg); |
790 | 790 | ||
791 | case _IOC_NR(PCIVME_DEINIT_HARDWARE): |
791 | case _IOC_NR(PCIVME_DEINIT_HARDWARE): |
792 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND)) |
792 | if (_IOC_SIZE(cmd) < sizeof(PCIVME_INIT_COMMAND)) |
793 | return -EINVAL; |
793 | return -EINVAL; |
794 | return deinit_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg); |
794 | return deinit_hardware(pp, pd, (PCIVME_INIT_COMMAND *)arg); |
795 | 795 | ||
796 | default: |
796 | default: |
797 | PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x) is illegal\n", DEVICE_NAME, cmd); |
797 | PRINTK(KERN_DEBUG "%s : pcivme_ioctl(0x%08x) is illegal\n", DEVICE_NAME, cmd); |
798 | return -EINVAL; |
798 | return -EINVAL; |
799 | } |
799 | } |
800 | 800 | ||
801 | return 0; |
801 | return 0; |
802 | } |
802 | } |
- | 803 | ||
- | 804 | /* |
|
- | 805 | static long pcivme_compat_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){ |
|
- | 806 | PRINTK(KERN_DEBUG "%s : pcivme_compat_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd)); |
|
- | 807 | return pcivme_ioctl(NULL, pFile, cmd,arg); |
|
- | 808 | } |
|
- | 809 | */ |
|
803 | 810 | ||
804 | static long pcivme_unlocked_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){ |
811 | static long pcivme_unlocked_ioctl(struct file *pFile, unsigned int cmd, unsigned long arg){ |
805 | long retval=0; |
812 | long retval=0; |
- | 813 | ||
- | 814 | ||
806 | #if HAVE_UNLOCKED_IOCTL |
815 | #if HAVE_UNLOCKED_IOCTL |
807 | struct mutex fs_mutex; |
816 | struct mutex fs_mutex; |
808 | mutex_init(&fs_mutex); |
817 | mutex_init(&fs_mutex); |
809 | mutex_lock(&fs_mutex); |
818 | mutex_lock(&fs_mutex); |
810 | #else |
819 | #else |
811 | lock_kernel(); |
820 | lock_kernel(); |
812 | #endif |
821 | #endif |
813 | 822 | ||
- | 823 | PRINTK(KERN_DEBUG "%s : pcivme_unlocked_ioctl(0x%08x), size = %d\n", DEVICE_NAME, cmd, _IOC_SIZE(cmd)); |
|
814 | retval = pcivme_ioctl(NULL, pFile, cmd,arg); |
824 | retval = pcivme_ioctl(NULL, pFile, cmd,arg); |
815 | 825 | ||
816 | #if HAVE_UNLOCKED_IOCTL |
826 | #if HAVE_UNLOCKED_IOCTL |
817 | mutex_unlock(&fs_mutex); |
827 | mutex_unlock(&fs_mutex); |
818 | #else |
828 | #else |
819 | unlock_kernel(); |
829 | unlock_kernel(); |
820 | #endif |
830 | #endif |
- | 831 | ||
821 | return retval; |
832 | return retval; |
822 | } |
833 | } |
823 | 834 | ||
824 | int pcivme_open(struct inode *pInode, struct file *pFile) |
835 | int pcivme_open(struct inode *pInode, struct file *pFile) |
825 | { |
836 | { |
826 | DEVICE_OBJ *pd = 0; |
837 | DEVICE_OBJ *pd = 0; |
827 | DEVICE_OBJ *desc = 0; |
838 | DEVICE_OBJ *desc = 0; |
828 |
|
839 | int nMinor = MINOR(pInode->i_rdev); |
829 | struct list_head *ptr; |
840 | struct list_head *ptr; |
830 | 841 | ||
831 | PRINTK(KERN_DEBUG "%s : pcivme_open(), |
842 | PRINTK(KERN_DEBUG "%s : pcivme_open(), %d, scanning %d devices\n", DEVICE_NAME, nMinor, drv.count); |
832 | 843 | ||
833 | /* search for device */ |
844 | /* search for device */ |
834 | for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next) |
845 | for (ptr = drv.devList.next; ptr != &drv.devList; ptr = ptr->next) |
835 | { |
846 | { |
836 | pd = list_entry(ptr, DEVICE_OBJ, list); |
847 | pd = list_entry(ptr, DEVICE_OBJ, list); |
837 | pd->bConnected = get_module_info(pd); |
848 | pd->bConnected = get_module_info(pd); |
838 | if (pd->bConnected) |
849 | if (pd->bConnected) |
839 | { |
850 | { |
840 | if (test_connection(pd)) |
851 | if (test_connection(pd)) |
841 | { |
852 | { |
842 | printk(KERN_ERR "%s : connection test for module %d failed!\n", DEVICE_NAME, pd->cModuleNumber); |
853 | printk(KERN_ERR "%s : pcivme_open() connection test for module %d failed!\n", DEVICE_NAME, pd->cModuleNumber); |
843 | pd->bConnected = 0; |
854 | pd->bConnected = 0; |
844 | } |
855 | } |
845 | else |
856 | else |
846 | if (pd->cModuleNumber == nMinor) |
857 | if (pd->cModuleNumber == nMinor) |
847 | { |
858 | { |
848 | desc = pd; |
859 | desc = pd; |
849 | break; |
860 | break; |
850 | } |
861 | } |
851 | } |
862 | } |
852 | else |
863 | else |
853 | PRINTK(KERN_DEBUG "%s : module %d not connected!\n", DEVICE_NAME, nMinor); |
864 | PRINTK(KERN_DEBUG "%s pcivme_open(): module %d not connected!\n", DEVICE_NAME, nMinor); |
854 | } |
865 | } |
855 | 866 | ||
856 | if (desc) |
867 | if (desc) |
857 | { |
868 | { |
858 | int err; |
869 | int err; |
859 | PATH_OBJ *pp; |
870 | PATH_OBJ *pp; |
860 | 871 | ||
861 | pp = (PATH_OBJ *)kmalloc(sizeof(PATH_OBJ), GFP_ATOMIC); |
872 | pp = (PATH_OBJ *)kmalloc(sizeof(PATH_OBJ), GFP_ATOMIC); |
862 | if (!pp) |
873 | if (!pp) |
863 | return -ENOMEM; |
874 | return -ENOMEM; |
864 | 875 | ||
865 | // file PATH_OBJ structure with initialisation data |
876 | // file PATH_OBJ structure with initialisation data |
866 | pp->pDo = pd; |
877 | pp->pDo = pd; |
867 | pp->bAccessType = pp->bIncrement = BYTE_ACCESS; |
878 | pp->bAccessType = pp->bIncrement = BYTE_ACCESS; |
868 | pp->bModifier = Short_NoPriv; |
879 | pp->bModifier = Short_NoPriv; |
869 | pp->read = readByte; |
880 | pp->read = readByte; |
870 | pp->write = writeByte; |
881 | pp->write = writeByte; |
871 | pp->AlignmentCheck = MisalignmentForByteAccess; |
882 | pp->AlignmentCheck = MisalignmentForByteAccess; |
872 | pFile->private_data = (void *)pp; |
883 | pFile->private_data = (void *)pp; |
873 | 884 | ||
874 | PRINTK(KERN_DEBUG "%s : found VMEMM module with number %d.\n", DEVICE_NAME, nMinor); |
885 | PRINTK(KERN_DEBUG "%s : pcivme_open() found VMEMM module with number %d.\n", DEVICE_NAME, nMinor); |
875 | 886 | ||
876 | if (!pd->nOpenCounter) |
887 | if (!pd->nOpenCounter) |
877 | { |
888 | { |
878 | err = CmdMachine(pd, init_element); |
889 | err = CmdMachine(pd, init_element); |
879 | if (err) |
890 | if (err) |
880 | { |
891 | { |
881 | printk(KERN_ERR "%s : default init failed with err = %d!\n", DEVICE_NAME, err); |
892 | printk(KERN_ERR "%s : pcivme_open() default init failed with err = %d!\n", DEVICE_NAME, err); |
882 | kfree_s(pp, sizeof(*pp)); // FREE(pFile->private_data); |
893 | kfree_s(pp, sizeof(*pp)); // FREE(pFile->private_data); |
883 | return err; |
894 | return err; |
884 | } |
895 | } |
885 | } |
896 | } |
886 | 897 | ||
887 | pd->nOpenCounter++; |
898 | pd->nOpenCounter++; |
888 | } |
899 | } |
889 | else |
900 | else |
890 | { |
901 | { |
891 | printk(KERN_ERR "%s : No VMEMM module found.\n", DEVICE_NAME); |
902 | printk(KERN_ERR "%s pcivme_open(): No VMEMM module found.\n", DEVICE_NAME); |
892 | return -ENODEV; |
903 | return -ENODEV; |
893 | } |
904 | } |
894 | 905 | ||
895 | __MOD_INC_USE_COUNT__; |
906 | __MOD_INC_USE_COUNT__; |
896 | return 0; |
907 | return 0; |
897 | } |
908 | } |
898 | 909 | ||
899 | int pcivme_release(struct inode *pInode, struct file *pFile) |
910 | int pcivme_release(struct inode *pInode, struct file *pFile) |
900 | { |
911 | { |
901 | PATH_OBJ *pp; |
912 | PATH_OBJ *pp; |
902 | 913 | ||
903 | PRINTK(KERN_DEBUG "%s : |
914 | PRINTK(KERN_DEBUG "%s : pcivme_release()\n", DEVICE_NAME); |
904 | 915 | ||
905 | if (pFile->private_data) |
916 | if (pFile->private_data) |
906 | { |
917 | { |
907 | pp = (PATH_OBJ *)pFile->private_data; |
918 | pp = (PATH_OBJ *)pFile->private_data; |
908 | if (pp && pp->pDo ) |
919 | if (pp && pp->pDo ) |
909 | { |
920 | { |
910 | DEVICE_OBJ *pd = pp->pDo; |
921 | DEVICE_OBJ *pd = pp->pDo; |
911 | 922 | ||
912 | pd->nOpenCounter--; |
923 | pd->nOpenCounter--; |
913 | 924 | ||
914 | // the last one closes the door |
925 | // the last one closes the door |
915 | if (pd->nOpenCounter <= 0) |
926 | if (pd->nOpenCounter <= 0) |
916 | { |
927 | { |
917 | CmdMachine(pd, deinit_element_pre); |
928 | CmdMachine(pd, deinit_element_pre); |
918 | CmdMachine(pd, deinit_element_post); |
929 | CmdMachine(pd, deinit_element_post); |
919 | 930 | ||
920 | // Vorsicht ist die Mutter der Porzelankiste! |
931 | // Vorsicht ist die Mutter der Porzelankiste! |
921 | pd->nOpenCounter = 0; |
932 | pd->nOpenCounter = 0; |
922 | } |
933 | } |
923 | 934 | ||
924 | pp->pDo = 0; |
935 | pp->pDo = 0; |
925 | } |
936 | } |
926 | 937 | ||
927 | kfree_s(pp, sizeof(*pp)); // FREE(pFile->private_data); |
938 | kfree_s(pp, sizeof(*pp)); // FREE(pFile->private_data); |
928 | } |
939 | } |
929 | 940 | ||
930 | __MOD_DEC_USE_COUNT__; |
941 | __MOD_DEC_USE_COUNT__; |
931 | return 0; |
942 | return 0; |
932 | } |
943 | } |
933 | 944 | ||
934 | static ssize_t pcivme_read(struct file *pFile, char *pcBuffer, size_t count, loff_t *offp) |
945 | static ssize_t pcivme_read(struct file *pFile, char *pcBuffer, size_t count, loff_t *offp) |
935 | { |
946 | { |
936 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
947 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
937 | DEVICE_OBJ *pd = pp->pDo; |
948 | DEVICE_OBJ *pd = pp->pDo; |
938 | u32 dwLocalCount = count; |
949 | u32 dwLocalCount = count; |
939 | register u32 dwLocalPageAddress; |
950 | register u32 dwLocalPageAddress; |
940 | u32 dwLocalAddressInPage; |
951 | u32 dwLocalAddressInPage; |
941 | 952 | ||
942 | PRINTK(KERN_DEBUG "%s : pcivme_read(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount); |
953 | PRINTK(KERN_DEBUG "%s : pcivme_read(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount); |
943 | 954 | ||
944 | // inhibit misaligned accesses |
955 | // inhibit misaligned accesses |
945 | if (pp->AlignmentCheck(*offp)) |
956 | if (pp->AlignmentCheck(*offp)) |
946 | return -EFAULT; |
957 | return -EFAULT; |
947 | 958 | ||
948 | // check for free access to user buffer |
959 | // check for free access to user buffer |
949 | if (!access_ok(VERIFY_WRITE, pcBuffer, count)) |
960 | if (!access_ok(VERIFY_WRITE, pcBuffer, count)) |
950 | return -EFAULT; |
961 | return -EFAULT; |
951 | 962 | ||
952 | // do I still have the same modifier? |
963 | // do I still have the same modifier? |
953 | if (pp->bModifier != pd->bCurrentModifier) |
964 | if (pp->bModifier != pd->bCurrentModifier) |
954 | setModifier(pd, pp->bModifier); |
965 | setModifier(pd, pp->bModifier); |
955 | 966 | ||
956 | while (count >= pp->bAccessType) |
967 | while (count >= pp->bAccessType) |
957 | { |
968 | { |
958 | dwLocalPageAddress = *offp & HI_ADDRESS_MASK; |
969 | dwLocalPageAddress = *offp & HI_ADDRESS_MASK; |
959 | dwLocalAddressInPage = *offp & LO_ADDRESS_MASK; |
970 | dwLocalAddressInPage = *offp & LO_ADDRESS_MASK; |
960 | 971 | ||
961 | // do I still work in the same page? |
972 | // do I still work in the same page? |
962 | if (dwLocalPageAddress != pd->dwCurrentPageAddress) |
973 | if (dwLocalPageAddress != pd->dwCurrentPageAddress) |
963 | setPageAddress(pd, dwLocalPageAddress); |
974 | setPageAddress(pd, dwLocalPageAddress); |
964 | 975 | ||
965 | // standard access method |
976 | // standard access method |
966 | pp->read(pd, (void **)&pcBuffer, dwLocalAddressInPage); |
977 | pp->read(pd, (void **)&pcBuffer, dwLocalAddressInPage); |
967 | 978 | ||
968 | // decrement count and update pointer to next access address |
979 | // decrement count and update pointer to next access address |
969 | count -= pp->bAccessType; |
980 | count -= pp->bAccessType; |
970 | *offp += pp->bIncrement; |
981 | *offp += pp->bIncrement; |
971 | } |
982 | } |
972 | 983 | ||
973 | return dwLocalCount - count; |
984 | return dwLocalCount - count; |
974 | } |
985 | } |
975 | 986 | ||
976 | static ssize_t pcivme_write(struct file *pFile, const char *pcBuffer, size_t count, loff_t *offp) |
987 | static ssize_t pcivme_write(struct file *pFile, const char *pcBuffer, size_t count, loff_t *offp) |
977 | { |
988 | { |
978 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
989 | PATH_OBJ *pp = (PATH_OBJ *)pFile->private_data; |
979 | DEVICE_OBJ *pd = pp->pDo; |
990 | DEVICE_OBJ *pd = pp->pDo; |
980 | u32 dwLocalCount = count; |
991 | u32 dwLocalCount = count; |
981 | register u32 dwLocalPageAddress; |
992 | register u32 dwLocalPageAddress; |
982 | u32 dwLocalAddressInPage; |
993 | u32 dwLocalAddressInPage; |
983 | 994 | ||
984 | PRINTK(KERN_DEBUG "%s : pcivme_write(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount); |
995 | PRINTK(KERN_DEBUG "%s : pcivme_write(0x%08x, %d)\n", DEVICE_NAME, (u32)*offp, dwLocalCount); |
985 | 996 | ||
986 | // inhibit misaligned accesses |
997 | // inhibit misaligned accesses |
987 | if (pp->AlignmentCheck(*offp)) |
998 | if (pp->AlignmentCheck(*offp)) |
988 | return -EFAULT; |
999 | return -EFAULT; |
989 | 1000 | ||
990 | // check for free access to user buffer |
1001 | // check for free access to user buffer |
991 | if (!access_ok(VERIFY_READ, pcBuffer, count)) |
1002 | if (!access_ok(VERIFY_READ, pcBuffer, count)) |
992 | return -EFAULT; |
1003 | return -EFAULT; |
993 | 1004 | ||
994 | // do I still have the same modifier? |
1005 | // do I still have the same modifier? |
995 | if (pp->bModifier != pd->bCurrentModifier) |
1006 | if (pp->bModifier != pd->bCurrentModifier) |
996 | setModifier(pd, pp->bModifier); |
1007 | setModifier(pd, pp->bModifier); |
997 | 1008 | ||
998 | while (count >= pp->bAccessType) |
1009 | while (count >= pp->bAccessType) |
999 | { |
1010 | { |
1000 | dwLocalPageAddress = *offp & HI_ADDRESS_MASK; |
1011 | dwLocalPageAddress = *offp & HI_ADDRESS_MASK; |
1001 | dwLocalAddressInPage = *offp & LO_ADDRESS_MASK; |
1012 | dwLocalAddressInPage = *offp & LO_ADDRESS_MASK; |
1002 | 1013 | ||
1003 | // do I still work in the same page? |
1014 | // do I still work in the same page? |
1004 | if (dwLocalPageAddress != pd->dwCurrentPageAddress) |
1015 | if (dwLocalPageAddress != pd->dwCurrentPageAddress) |
1005 | setPageAddress(pd, dwLocalPageAddress); |
1016 | setPageAddress(pd, dwLocalPageAddress); |
1006 | 1017 | ||
1007 | // standard access method |
1018 | // standard access method |
1008 | pp->write(pd, dwLocalAddressInPage, (void **)&pcBuffer); |
1019 | pp->write(pd, dwLocalAddressInPage, (void **)&pcBuffer); |
1009 | 1020 | ||
1010 | // decrement count and update pointer to next access address |
1021 | // decrement count and update pointer to next access address |
1011 | count -= pp->bAccessType; |
1022 | count -= pp->bAccessType; |
1012 | *offp += pp->bIncrement; |
1023 | *offp += pp->bIncrement; |
1013 | } |
1024 | } |
1014 | 1025 | ||
1015 | return dwLocalCount - count; |
1026 | return dwLocalCount - count; |
1016 | } |
1027 | } |
1017 | 1028 | ||
1018 | 1029 | ||
1019 |
|
1030 | // http://learninglinuxkernel.in/writing-char-driver-for-linux-kernel-2-6/ |
- | 1031 | // http://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/ |
|
1020 |
|
1032 | loff_t pcivme_lseek(struct file* filep, loff_t offset, int whence) |
1021 | { |
1033 | { |
- | 1034 | ||
1022 |
|
1035 | PRINTK(KERN_DEBUG "%s : pcivme_lseek(0x%08x, %d)\n", DEVICE_NAME, (u32) offset, whence); |
1023 |
|
1036 | switch (whence) { |
1024 |
|
1037 | case 0: /* SEEK_SET */ |
1025 |
|
1038 | filep->f_pos = offset; |
- | 1039 | break; |
|
1026 |
|
1040 | case 1: /* SEEK_CUR */ |
1027 |
|
1041 | filep->f_pos += offset; |
- | 1042 | break; |
|
1028 |
|
1043 | case 2: /* SEEK_END */ |
1029 |
|
1044 | return -EINVAL; |
1030 |
|
1045 | default: |
- | 1046 | return -EINVAL; |
|
- | 1047 | }; |
|
- | 1048 | ||
1031 |
|
1049 | return filep->f_pos; |
1032 | } |
1050 | } |
- | 1051 | ||
- | 1052 | ||
1033 | #else |
1053 | |
1034 | struct file_operations pcivme_fops = |
1054 | struct file_operations pcivme_fops = |
1035 | { |
1055 | { |
- | 1056 | .llseek = pcivme_lseek, /* lseek */ |
|
1036 | .read = pcivme_read, /* read */ |
1057 | .read = pcivme_read, /* read */ |
1037 | .write = pcivme_write, /* write */ |
1058 | .write = pcivme_write, /* write */ |
- | 1059 | // .compat_ioctl = pcivme_compat_ioctl, /* ioctl */ |
|
1038 | .unlocked_ioctl = pcivme_unlocked_ioctl, /* ioctl */ |
1060 | .unlocked_ioctl = pcivme_unlocked_ioctl, /* ioctl */ |
1039 | .open = pcivme_open, /* open */ |
1061 | .open = pcivme_open, /* open */ |
1040 | .release = pcivme_release, /* release */ |
1062 | .release = pcivme_release, /* release */ |
1041 | }; |
1063 | }; |
1042 | #endif |
1064 | |
1043 | 1065 | ||
1044 | 1066 | ||
1045 | 1067 | ||
1046 | 1068 | ||
1047 | 1069 | ||
1048 | 1070 |