Merge branch 'master' of /home/tglx/work/mtd/git/linux-2.6.git/
[linux-2.6] / drivers / isdn / hardware / eicon / divasproc.c
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 = proc_mkdir(tmp, 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 }