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