diff options
Diffstat (limited to 'drivers/isdn/hardware/eicon/divasproc.c')
-rw-r--r-- | drivers/isdn/hardware/eicon/divasproc.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c new file mode 100644 index 000000000000..b6435589d459 --- /dev/null +++ b/drivers/isdn/hardware/eicon/divasproc.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* $Id: divasproc.c,v 1.19.4.3 2005/01/31 12:22:20 armin Exp $ | ||
2 | * | ||
3 | * Low level driver for Eicon DIVA Server ISDN cards. | ||
4 | * /proc functions | ||
5 | * | ||
6 | * Copyright 2000-2003 by Armin Schindler (mac@melware.de) | ||
7 | * Copyright 2000-2003 Cytronics & Melware (info@melware.de) | ||
8 | * | ||
9 | * This software may be used and distributed according to the terms | ||
10 | * of the GNU General Public License, incorporated herein by reference. | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/poll.h> | ||
17 | #include <linux/proc_fs.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <asm/uaccess.h> | ||
20 | |||
21 | #include "platform.h" | ||
22 | #include "debuglib.h" | ||
23 | #undef ID_MASK | ||
24 | #undef N_DATA | ||
25 | #include "pc.h" | ||
26 | #include "di_defs.h" | ||
27 | #include "divasync.h" | ||
28 | #include "di.h" | ||
29 | #include "io.h" | ||
30 | #include "xdi_msg.h" | ||
31 | #include "xdi_adapter.h" | ||
32 | #include "diva.h" | ||
33 | #include "diva_pci.h" | ||
34 | |||
35 | |||
36 | extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; | ||
37 | extern void divas_get_version(char *); | ||
38 | extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf); | ||
39 | |||
40 | /********************************************************* | ||
41 | ** Functions for /proc interface / File operations | ||
42 | *********************************************************/ | ||
43 | |||
44 | static char *divas_proc_name = "divas"; | ||
45 | static char *adapter_dir_name = "adapter"; | ||
46 | static char *info_proc_name = "info"; | ||
47 | static char *grp_opt_proc_name = "group_optimization"; | ||
48 | static char *d_l1_down_proc_name = "dynamic_l1_down"; | ||
49 | |||
50 | /* | ||
51 | ** "divas" entry | ||
52 | */ | ||
53 | |||
54 | extern struct proc_dir_entry *proc_net_eicon; | ||
55 | static struct proc_dir_entry *divas_proc_entry = NULL; | ||
56 | |||
57 | static ssize_t | ||
58 | divas_read(struct file *file, char __user *buf, size_t count, loff_t * off) | ||
59 | { | ||
60 | int len = 0; | ||
61 | int cadapter; | ||
62 | char tmpbuf[80]; | ||
63 | char tmpser[16]; | ||
64 | |||
65 | if (*off) | ||
66 | return 0; | ||
67 | |||
68 | divas_get_version(tmpbuf); | ||
69 | if (copy_to_user(buf + len, &tmpbuf, strlen(tmpbuf))) | ||
70 | return -EFAULT; | ||
71 | len += strlen(tmpbuf); | ||
72 | |||
73 | for (cadapter = 0; cadapter < MAX_ADAPTER; cadapter++) { | ||
74 | if (IoAdapters[cadapter]) { | ||
75 | diva_get_vserial_number(IoAdapters[cadapter], | ||
76 | tmpser); | ||
77 | sprintf(tmpbuf, | ||
78 | "%2d: %-30s Serial:%-10s IRQ:%2d\n", | ||
79 | cadapter + 1, | ||
80 | IoAdapters[cadapter]->Properties.Name, | ||
81 | tmpser, | ||
82 | IoAdapters[cadapter]->irq_info.irq_nr); | ||
83 | if ((strlen(tmpbuf) + len) > count) | ||
84 | break; | ||
85 | if (copy_to_user | ||
86 | (buf + len, &tmpbuf, | ||
87 | strlen(tmpbuf))) return -EFAULT; | ||
88 | len += strlen(tmpbuf); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | *off += len; | ||
93 | return (len); | ||
94 | } | ||
95 | |||
96 | static ssize_t | ||
97 | divas_write(struct file *file, const char __user *buf, size_t count, loff_t * off) | ||
98 | { | ||
99 | return (-ENODEV); | ||
100 | } | ||
101 | |||
102 | static unsigned int divas_poll(struct file *file, poll_table * wait) | ||
103 | { | ||
104 | return (POLLERR); | ||
105 | } | ||
106 | |||
107 | static int divas_open(struct inode *inode, struct file *file) | ||
108 | { | ||
109 | return nonseekable_open(inode, file); | ||
110 | } | ||
111 | |||
112 | static int divas_close(struct inode *inode, struct file *file) | ||
113 | { | ||
114 | return (0); | ||
115 | } | ||
116 | |||
117 | static struct file_operations divas_fops = { | ||
118 | .owner = THIS_MODULE, | ||
119 | .llseek = no_llseek, | ||
120 | .read = divas_read, | ||
121 | .write = divas_write, | ||
122 | .poll = divas_poll, | ||
123 | .open = divas_open, | ||
124 | .release = divas_close | ||
125 | }; | ||
126 | |||
127 | int create_divas_proc(void) | ||
128 | { | ||
129 | divas_proc_entry = create_proc_entry(divas_proc_name, | ||
130 | S_IFREG | S_IRUGO, | ||
131 | proc_net_eicon); | ||
132 | if (!divas_proc_entry) | ||
133 | return (0); | ||
134 | |||
135 | divas_proc_entry->proc_fops = &divas_fops; | ||
136 | divas_proc_entry->owner = THIS_MODULE; | ||
137 | |||
138 | return (1); | ||
139 | } | ||
140 | |||
141 | void remove_divas_proc(void) | ||
142 | { | ||
143 | if (divas_proc_entry) { | ||
144 | remove_proc_entry(divas_proc_name, proc_net_eicon); | ||
145 | divas_proc_entry = NULL; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | ** write group_optimization | ||
151 | */ | ||
152 | static int | ||
153 | write_grp_opt(struct file *file, const char __user *buffer, unsigned long count, | ||
154 | void *data) | ||
155 | { | ||
156 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
157 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
158 | |||
159 | if ((count == 1) || (count == 2)) { | ||
160 | char c; | ||
161 | if (get_user(c, buffer)) | ||
162 | return -EFAULT; | ||
163 | switch (c) { | ||
164 | case '0': | ||
165 | IoAdapter->capi_cfg.cfg_1 &= | ||
166 | ~DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON; | ||
167 | break; | ||
168 | case '1': | ||
169 | IoAdapter->capi_cfg.cfg_1 |= | ||
170 | DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON; | ||
171 | break; | ||
172 | default: | ||
173 | return (-EINVAL); | ||
174 | } | ||
175 | return (count); | ||
176 | } | ||
177 | return (-EINVAL); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | ** write dynamic_l1_down | ||
182 | */ | ||
183 | static int | ||
184 | write_d_l1_down(struct file *file, const char __user *buffer, unsigned long count, | ||
185 | void *data) | ||
186 | { | ||
187 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
188 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
189 | |||
190 | if ((count == 1) || (count == 2)) { | ||
191 | char c; | ||
192 | if (get_user(c, buffer)) | ||
193 | return -EFAULT; | ||
194 | switch (c) { | ||
195 | case '0': | ||
196 | IoAdapter->capi_cfg.cfg_1 &= | ||
197 | ~DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON; | ||
198 | break; | ||
199 | case '1': | ||
200 | IoAdapter->capi_cfg.cfg_1 |= | ||
201 | DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON; | ||
202 | break; | ||
203 | default: | ||
204 | return (-EINVAL); | ||
205 | } | ||
206 | return (count); | ||
207 | } | ||
208 | return (-EINVAL); | ||
209 | } | ||
210 | |||
211 | |||
212 | /* | ||
213 | ** read dynamic_l1_down | ||
214 | */ | ||
215 | static int | ||
216 | read_d_l1_down(char *page, char **start, off_t off, int count, int *eof, | ||
217 | void *data) | ||
218 | { | ||
219 | int len = 0; | ||
220 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
221 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
222 | |||
223 | len += sprintf(page + len, "%s\n", | ||
224 | (IoAdapter->capi_cfg. | ||
225 | cfg_1 & DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? "1" : | ||
226 | "0"); | ||
227 | |||
228 | if (off + count >= len) | ||
229 | *eof = 1; | ||
230 | if (len < off) | ||
231 | return 0; | ||
232 | *start = page + off; | ||
233 | return ((count < len - off) ? count : len - off); | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | ** read group_optimization | ||
238 | */ | ||
239 | static int | ||
240 | read_grp_opt(char *page, char **start, off_t off, int count, int *eof, | ||
241 | void *data) | ||
242 | { | ||
243 | int len = 0; | ||
244 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
245 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
246 | |||
247 | len += sprintf(page + len, "%s\n", | ||
248 | (IoAdapter->capi_cfg. | ||
249 | cfg_1 & DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) | ||
250 | ? "1" : "0"); | ||
251 | |||
252 | if (off + count >= len) | ||
253 | *eof = 1; | ||
254 | if (len < off) | ||
255 | return 0; | ||
256 | *start = page + off; | ||
257 | return ((count < len - off) ? count : len - off); | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | ** info write | ||
262 | */ | ||
263 | static int | ||
264 | info_write(struct file *file, const char __user *buffer, unsigned long count, | ||
265 | void *data) | ||
266 | { | ||
267 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
268 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
269 | char c[4]; | ||
270 | |||
271 | if (count <= 4) | ||
272 | return -EINVAL; | ||
273 | |||
274 | if (copy_from_user(c, buffer, 4)) | ||
275 | return -EFAULT; | ||
276 | |||
277 | /* this is for test purposes only */ | ||
278 | if (!memcmp(c, "trap", 4)) { | ||
279 | (*(IoAdapter->os_trap_nfy_Fnc)) (IoAdapter, IoAdapter->ANum); | ||
280 | return (count); | ||
281 | } | ||
282 | return (-EINVAL); | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | ** info read | ||
287 | */ | ||
288 | static int | ||
289 | info_read(char *page, char **start, off_t off, int count, int *eof, | ||
290 | void *data) | ||
291 | { | ||
292 | int i = 0; | ||
293 | int len = 0; | ||
294 | char *p; | ||
295 | char tmpser[16]; | ||
296 | diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) data; | ||
297 | PISDN_ADAPTER IoAdapter = IoAdapters[a->controller - 1]; | ||
298 | |||
299 | len += | ||
300 | sprintf(page + len, "Name : %s\n", | ||
301 | IoAdapter->Properties.Name); | ||
302 | len += sprintf(page + len, "DSP state : %08x\n", a->dsp_mask); | ||
303 | len += sprintf(page + len, "Channels : %02d\n", | ||
304 | IoAdapter->Properties.Channels); | ||
305 | len += sprintf(page + len, "E. max/used : %03d/%03d\n", | ||
306 | IoAdapter->e_max, IoAdapter->e_count); | ||
307 | diva_get_vserial_number(IoAdapter, tmpser); | ||
308 | len += sprintf(page + len, "Serial : %s\n", tmpser); | ||
309 | len += | ||
310 | sprintf(page + len, "IRQ : %d\n", | ||
311 | IoAdapter->irq_info.irq_nr); | ||
312 | len += sprintf(page + len, "CardIndex : %d\n", a->CardIndex); | ||
313 | len += sprintf(page + len, "CardOrdinal : %d\n", a->CardOrdinal); | ||
314 | len += sprintf(page + len, "Controller : %d\n", a->controller); | ||
315 | len += sprintf(page + len, "Bus-Type : %s\n", | ||
316 | (a->Bus == | ||
317 | DIVAS_XDI_ADAPTER_BUS_ISA) ? "ISA" : "PCI"); | ||
318 | len += sprintf(page + len, "Port-Name : %s\n", a->port_name); | ||
319 | if (a->Bus == DIVAS_XDI_ADAPTER_BUS_PCI) { | ||
320 | len += | ||
321 | sprintf(page + len, "PCI-bus : %d\n", | ||
322 | a->resources.pci.bus); | ||
323 | len += | ||
324 | sprintf(page + len, "PCI-func : %d\n", | ||
325 | a->resources.pci.func); | ||
326 | for (i = 0; i < 8; i++) { | ||
327 | if (a->resources.pci.bar[i]) { | ||
328 | len += | ||
329 | sprintf(page + len, | ||
330 | "Mem / I/O %d : 0x%x / mapped : 0x%lx", | ||
331 | i, a->resources.pci.bar[i], | ||
332 | (unsigned long) a->resources. | ||
333 | pci.addr[i]); | ||
334 | if (a->resources.pci.length[i]) { | ||
335 | len += | ||
336 | sprintf(page + len, | ||
337 | " / length : %d", | ||
338 | a->resources.pci. | ||
339 | length[i]); | ||
340 | } | ||
341 | len += sprintf(page + len, "\n"); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | if ((!a->xdi_adapter.port) && | ||
346 | ((!a->xdi_adapter.ram) || | ||
347 | (!a->xdi_adapter.reset) | ||
348 | || (!a->xdi_adapter.cfg))) { | ||
349 | if (!IoAdapter->irq_info.irq_nr) { | ||
350 | p = "slave"; | ||
351 | } else { | ||
352 | p = "out of service"; | ||
353 | } | ||
354 | } else if (a->xdi_adapter.trapped) { | ||
355 | p = "trapped"; | ||
356 | } else if (a->xdi_adapter.Initialized) { | ||
357 | p = "active"; | ||
358 | } else { | ||
359 | p = "ready"; | ||
360 | } | ||
361 | len += sprintf(page + len, "State : %s\n", p); | ||
362 | |||
363 | if (off + count >= len) | ||
364 | *eof = 1; | ||
365 | if (len < off) | ||
366 | return 0; | ||
367 | *start = page + off; | ||
368 | return ((count < len - off) ? count : len - off); | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | ** adapter proc init/de-init | ||
373 | */ | ||
374 | |||
375 | /* -------------------------------------------------------------------------- | ||
376 | Create adapter directory and files in proc file system | ||
377 | -------------------------------------------------------------------------- */ | ||
378 | int create_adapter_proc(diva_os_xdi_adapter_t * a) | ||
379 | { | ||
380 | struct proc_dir_entry *de, *pe; | ||
381 | char tmp[16]; | ||
382 | |||
383 | sprintf(tmp, "%s%d", adapter_dir_name, a->controller); | ||
384 | if (!(de = create_proc_entry(tmp, S_IFDIR, proc_net_eicon))) | ||
385 | return (0); | ||
386 | a->proc_adapter_dir = (void *) de; | ||
387 | |||
388 | if (!(pe = | ||
389 | create_proc_entry(info_proc_name, S_IFREG | S_IRUGO | S_IWUSR, de))) | ||
390 | return (0); | ||
391 | a->proc_info = (void *) pe; | ||
392 | pe->write_proc = info_write; | ||
393 | pe->read_proc = info_read; | ||
394 | pe->data = a; | ||
395 | |||
396 | if ((pe = create_proc_entry(grp_opt_proc_name, | ||
397 | S_IFREG | S_IRUGO | S_IWUSR, de))) { | ||
398 | a->proc_grp_opt = (void *) pe; | ||
399 | pe->write_proc = write_grp_opt; | ||
400 | pe->read_proc = read_grp_opt; | ||
401 | pe->data = a; | ||
402 | } | ||
403 | if ((pe = create_proc_entry(d_l1_down_proc_name, | ||
404 | S_IFREG | S_IRUGO | S_IWUSR, de))) { | ||
405 | a->proc_d_l1_down = (void *) pe; | ||
406 | pe->write_proc = write_d_l1_down; | ||
407 | pe->read_proc = read_d_l1_down; | ||
408 | pe->data = a; | ||
409 | } | ||
410 | |||
411 | DBG_TRC(("proc entry %s created", tmp)); | ||
412 | |||
413 | return (1); | ||
414 | } | ||
415 | |||
416 | /* -------------------------------------------------------------------------- | ||
417 | Remove adapter directory and files in proc file system | ||
418 | -------------------------------------------------------------------------- */ | ||
419 | void remove_adapter_proc(diva_os_xdi_adapter_t * a) | ||
420 | { | ||
421 | char tmp[16]; | ||
422 | |||
423 | if (a->proc_adapter_dir) { | ||
424 | if (a->proc_d_l1_down) { | ||
425 | remove_proc_entry(d_l1_down_proc_name, | ||
426 | (struct proc_dir_entry *) a->proc_adapter_dir); | ||
427 | } | ||
428 | if (a->proc_grp_opt) { | ||
429 | remove_proc_entry(grp_opt_proc_name, | ||
430 | (struct proc_dir_entry *) a->proc_adapter_dir); | ||
431 | } | ||
432 | if (a->proc_info) { | ||
433 | remove_proc_entry(info_proc_name, | ||
434 | (struct proc_dir_entry *) a->proc_adapter_dir); | ||
435 | } | ||
436 | sprintf(tmp, "%s%d", adapter_dir_name, a->controller); | ||
437 | remove_proc_entry(tmp, proc_net_eicon); | ||
438 | DBG_TRC(("proc entry %s%d removed", adapter_dir_name, | ||
439 | a->controller)); | ||
440 | } | ||
441 | } | ||