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