root/lm-sensors/trunk/kernel/i2c-proc.c @ 247

Revision 247, 14.9 KB (checked in by frodo, 14 years ago)

Two insignificant patches to remove 2.0.x kernel compile warnings.

It compiles now cleanly against kernel 2.0.36; I checked, double-checked and
cross-checked.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2c-proc.c - Part of lm_sensors, Linux kernel modules for hardware
3                 monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include <linux/module.h>
22#include <linux/proc_fs.h>
23
24#include "i2c.h"
25#include "smbus.h"
26#include "i2c-isa.h"
27#include "version.h"
28#include "compat.h"
29#include "sensors.h"
30
31#ifdef MODULE
32extern int init_module(void);
33extern int cleanup_module(void);
34#endif /* def MODULE */
35
36static int i2cproc_init(void);
37static int i2cproc_cleanup(void);
38static int i2cproc_attach_adapter(struct i2c_adapter *adapter);
39static int i2cproc_detach_client(struct i2c_client *client);
40static int i2cproc_command(struct i2c_client *client, unsigned int cmd,
41                           void *arg);
42static void i2cproc_inc_use(struct i2c_client *client);
43static void i2cproc_dec_use(struct i2c_client *client);
44
45#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
46static void monitor_bus_i2c(struct inode *inode, int fill);
47#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
48
49#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
50
51static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
52                                loff_t *ppos);
53static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
54                           int *eof , void *private);
55
56#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
57
58static int i2cproc_bus_read(struct inode * inode, struct file * file,
59                            char * buf, int count);
60static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
61                        int unused);
62
63static struct proc_dir_entry proc_bus_dir =
64  {
65    /* low_ino */       0,     /* Set by proc_register_dynamic */
66    /* namelen */       3, 
67    /* name */          "bus",
68    /* mode */          S_IRUGO | S_IXUGO | S_IFDIR,
69    /* nlink */         2,     /* Corrected by proc_register[_dynamic] */
70    /* uid */           0,
71    /* gid */           0,
72    /* size */          0,
73#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36))
74    /* ops */           &proc_dir_inode_operations, 
75#endif
76  };
77
78static struct proc_dir_entry proc_bus_i2c_dir =
79  {
80    /* low_ino */       0,     /* Set by proc_register_dynamic */
81    /* namelen */       3, 
82    /* name */          "i2c",
83    /* mode */          S_IRUGO | S_IFREG,
84    /* nlink */         1,     
85    /* uid */           0,
86    /* gid */           0,
87    /* size */          0,
88    /* ops */           NULL,
89    /* get_info */      &read_bus_i2c
90  };
91
92/* List of registered entries in /proc/bus */
93static struct proc_dir_entry *i2cproc_proc_entries[I2C_ADAP_MAX];
94
95#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
96
97/* To implement the dynamic /proc/bus/i2c-? files, we need our own
98   implementation of the read hook */
99static struct file_operations i2cproc_operations = {
100        NULL,
101        i2cproc_bus_read,
102};
103
104static struct inode_operations i2cproc_inode_operations = {
105        &i2cproc_operations
106};
107
108
109/* Used by init/cleanup */
110static int i2cproc_initialized;
111
112/* This is a sorted list of all adapters that will have entries in /proc/bus */
113static struct i2c_adapter *i2cproc_adapters[I2C_ADAP_MAX];
114
115/* Inodes of /dev/bus/i2c-? files */
116static int i2cproc_inodes[I2C_ADAP_MAX];
117
118/* We will use a nasty trick: we register a driver, that will be notified
119   for each adapter. Then, we register a dummy client on the adapter, that
120   will get notified if the adapter is removed. This is the same trick as
121   used in i2c/i2c-dev.c */
122static struct i2c_driver i2cproc_driver = {
123  /* name */            "i2c-proc dummy driver",
124  /* id */              I2C_DRIVERID_I2CPROC,
125  /* flags */           DF_NOTIFY,
126  /* attach_adapter */  &i2cproc_attach_adapter,
127  /* detach_client */   &i2cproc_detach_client,
128  /* command */         &i2cproc_command,
129  /* inc_use */         &i2cproc_inc_use,
130  /* dec_use */         &i2cproc_dec_use
131};
132
133static struct i2c_client i2cproc_client_template = {
134  /* name */            "i2c-proc dummy client",
135  /* id */              1,
136  /* flags */           0,
137  /* addr */            -1,
138  /* adapter */         NULL,
139  /* driver */          &i2cproc_driver,
140  /* data */            NULL
141};
142
143
144int i2cproc_init(void)
145{
146  int res;
147
148#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
149  struct proc_dir_entry *proc_bus_i2c;
150#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
151
152  printk("i2c-proc.o version %s (%s)\n",LM_VERSION,LM_DATE);
153  i2cproc_initialized = 0;
154
155#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
156  if (! proc_bus) {
157    printk("i2c-proc.o: /proc/bus/ does not exist, module not inserted.\n");
158    i2cproc_cleanup();
159    return -ENOENT;
160  }
161  proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
162  if (!proc_bus_i2c) {
163    printk("i2c-proc.o: Could not create /proc/bus/i2c, "
164           "module not inserted.\n");
165    i2cproc_cleanup();
166    return -ENOENT;
167  }
168  proc_bus_i2c->read_proc = &read_bus_i2c;
169#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
170  proc_bus_i2c->fill_inode = &monitor_bus_i2c;
171#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
172  i2cproc_initialized += 2;
173#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
174  /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
175     introduced it, or we are fucked. And 2.0.35 and earlier does not
176     export proc_dir_inode_operations, so we grab it from proc_net,
177     which also uses it. Not nice. */
178/* #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,0,36) */
179  proc_bus_dir.ops = proc_net.ops;
180/* #endif */
181  if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
182    printk("i2c-proc.o: Could not create /proc/bus/, module not inserted.\n");
183    i2cproc_cleanup();
184    return res;
185  }
186  i2cproc_initialized ++;
187  if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
188    printk("i2c-proc.o: Could not create /proc/bus/i2c, "
189           "module not inserted.\n");
190    i2cproc_cleanup();
191    return res;
192  }
193  i2cproc_initialized ++;
194#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
195  if ((res = i2c_add_driver(&i2cproc_driver))) {
196    printk("i2c-proc.o: Driver registration failed, module not inserted.\n");
197    i2cproc_cleanup();
198    return res;
199  }
200  i2cproc_initialized ++;
201  return 0;
202}
203
204int i2cproc_cleanup(void)
205{
206  int res;
207
208  if (i2cproc_initialized >= 3) {
209    if ((res = i2c_del_driver(&i2cproc_driver))) {
210      printk("i2c-proc.o: Driver deregistration failed, "
211             "module not removed.\n");
212      return res;
213    }
214    i2cproc_initialized--;
215  }
216  if (i2cproc_initialized >= 1) {
217#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
218    remove_proc_entry("i2c",proc_bus);
219    i2cproc_initialized -= 2;
220#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
221    if (i2cproc_initialized >= 2) {
222      if ((res = proc_unregister(&proc_bus_dir,proc_bus_i2c_dir.low_ino))) {
223         printk("i2c-proc.o: could not delete /proc/bus/i2c, "
224                "module not removed.");
225         return res;
226      }   
227      i2cproc_initialized --;
228    }
229    if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
230       printk("i2c-proc.o: could not delete /proc/bus/, "
231              "module not removed.");
232       return res;
233    }   
234    i2cproc_initialized --;
235#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
236  }
237  return 0;
238}
239
240#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
241/* Monitor access to /proc/bus/i2c*; make unloading i2c-proc.o impossible
242   if some process still uses it or some file in it */
243void monitor_bus_i2c(struct inode *inode, int fill)
244{
245  if (fill)
246    MOD_INC_USE_COUNT;
247  else
248    MOD_DEC_USE_COUNT;
249}
250#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
251
252
253/* This function generates the output for /proc/bus/i2c */
254#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
255int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
256                 void *private)
257#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
258int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
259#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
260{
261  int i;
262  len = 0;
263  for (i = 0; i < I2C_ADAP_MAX; i++)
264    if (i2cproc_adapters[i])
265      len += sprintf(buf+len, "i2c-%d\t%s\t%-32s\t%-32s\n",
266                     i2c_adapter_id(i2cproc_adapters[i]),
267                     i2c_is_smbus_adapter(i2cproc_adapters[i])?"smbus":
268#ifdef DEBUG
269                       i2c_is_isa_adapter(i2cproc_adapters[i])?"isa":
270#endif /* def DEBUG */
271                       "i2c",
272                     i2cproc_adapters[i]->name,
273                     i2cproc_adapters[i]->algo->name);
274  return len;
275}
276
277/* This function generates the output for /proc/bus/i2c-? */
278#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
279ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
280                         loff_t *ppos)
281{
282  struct inode * inode = file->f_dentry->d_inode;
283#else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29))
284int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf,
285                     int count)
286{
287#endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
288  char *kbuf;
289  struct i2c_client *client;
290  int i,j,len=0;
291
292  if (count < 0)
293    return -EINVAL;
294  if (count > 4000)
295    count = 4000;
296  for (i = 0; i < I2C_ADAP_MAX; i++)
297    if (i2cproc_inodes[i] == inode->i_ino) {
298      if (! (kbuf = kmalloc(count,GFP_KERNEL)))
299        return -ENOMEM;
300      for (j = 0; j < I2C_CLIENT_MAX; j++)
301        if ((client = i2cproc_adapters[i]->clients[j]))
302          /* Filter out dummy clients */
303#ifndef DEBUG
304          if ((client->driver->id != I2C_DRIVERID_I2CPROC) &&
305              (client->driver->id != I2C_DRIVERID_I2CDEV))
306#endif /* ndef DEBUG */
307            len += sprintf(kbuf+len,"%x\t%-32s\t%-32s\n",
308#ifdef DEBUG
309                           i2c_is_isa_client(client)?
310                             ((struct isa_client *) client)->isa_addr&0xffffff:
311#endif /* def DEBUG */
312                             client->addr,
313                           client->name,client->driver->name);
314      if (file->f_pos+len > count)
315        len = count - file->f_pos;
316      len = len - file->f_pos;
317      if (len < 0) 
318        len = 0;
319      copy_to_user (buf,kbuf+file->f_pos,len);
320      file->f_pos += len;
321      kfree(kbuf);
322      return len;
323    }
324  return -ENOENT;
325}
326
327
328/* We need to add the adapter to i2cproc_adapters, if it is interesting
329   enough */
330int i2cproc_attach_adapter(struct i2c_adapter *adapter)
331{
332  struct i2c_client *client;
333  int i,res;
334  char name[8];
335
336  struct proc_dir_entry *proc_entry;
337
338#ifndef DEBUG
339  if (i2c_is_isa_adapter(adapter))
340    return 0;
341#endif /* ndef DEBUG */
342
343  for (i = 0; i < I2C_ADAP_MAX; i++)
344    if(!i2cproc_adapters[i])
345      break;
346  if (i == I2C_ADAP_MAX) {
347    printk("i2c-proc.o: Too many adapters!\n");
348    return -ENOMEM;
349  }
350
351#ifndef DEBUG
352  if (! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) {
353#else /* def DEBUG */
354  if (! (client = kmalloc(sizeof(struct isa_client),GFP_KERNEL))) {
355#endif
356    printk("i2c-proc.o: Out of memory!\n");
357    return -ENOMEM;
358  }
359  memcpy(client,&i2cproc_client_template,sizeof(struct i2c_client));
360#ifdef DEBUG
361  ((struct isa_client *) client) -> isa_addr = -1;
362#endif /* def DEBUG */
363  client->adapter = adapter;
364  if ((res = i2c_attach_client(client))) {
365    printk("i2c-proc.o: Attaching client failed.\n");
366    kfree(client);
367    return res;
368  }
369  i2cproc_adapters[i] = adapter;
370
371  sprintf(name,"i2c-%d",i2c_adapter_id(adapter));
372
373#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
374  proc_entry = create_proc_entry(name,0,proc_bus);
375  if (! proc_entry) {
376    printk("i2c-proc.o: Could not create /proc/bus/%s\n",name);
377    kfree(client);
378    return -ENOENT;
379  }
380  proc_entry->ops = &i2cproc_inode_operations;
381#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58))
382  proc_entry->fill_inode = &monitor_bus_i2c;
383#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */
384#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
385  if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+strlen(name)+1,
386                             GFP_KERNEL))) {
387    printk("i2c-proc.o: Out of memory!\n");
388    return -ENOMEM;
389  }
390
391  memset(proc_entry,0,sizeof(struct proc_dir_entry));
392  proc_entry->namelen = strlen(name);
393  proc_entry->name = (char *) (proc_entry + 1);
394  proc_entry->mode = S_IRUGO | S_IFREG;
395  proc_entry->nlink = 1;
396  proc_entry->ops = &i2cproc_inode_operations;
397
398  /* Nasty stuff to keep GCC satisfied */
399  { 
400    char *procname;
401    (const char *) procname  = proc_entry->name;
402    strcpy (procname,name);
403  }
404
405  if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
406    printk("i2c-proc.o: Could not create %s.\n",name);
407    kfree(proc_entry);
408    kfree(client);
409    return res;
410  }
411
412  i2cproc_proc_entries[i] = proc_entry;
413#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
414
415  i2cproc_inodes[i] = proc_entry->low_ino;
416  return 0;
417}
418 
419int i2cproc_detach_client(struct i2c_client *client)
420{
421  int i,res;
422#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
423  char name[8];
424#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
425
426#ifndef DEBUG
427  if (i2c_is_isa_client(client))
428    return 0;
429#endif /* ndef DEBUG */
430
431  for (i = 0; i < I2C_ADAP_MAX; i++) 
432    if (client->adapter == i2cproc_adapters[i]) {
433#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
434      sprintf(name,"i2c-%d",i2c_adapter_id(i2cproc_adapters[i]));
435      remove_proc_entry(name,proc_bus);
436#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
437      if ((res = proc_unregister(&proc_bus_dir,
438                                 i2cproc_proc_entries[i]->low_ino))) {
439        printk("i2c-proc.o: Deregistration of /proc entry failed, "
440               "client not detached.\n");
441        return res;
442      }
443      kfree(i2cproc_proc_entries[i]);
444      i2cproc_proc_entries[i] = NULL;
445#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
446      if ((res = i2c_detach_client(client))) {
447        printk("i2c-proc.o: Client deregistration failed, "
448               "client not detached.\n");
449        return res;
450      }
451      i2cproc_adapters[i] = NULL;
452      i2cproc_inodes[i] = 0;
453      kfree(client);
454      return 0;
455    }
456  return -ENOENT;
457}
458
459/* Nothing here yet */
460int i2cproc_command(struct i2c_client *client, unsigned int cmd,
461                    void *arg)
462{
463  return -1;
464}
465
466/* Nothing here yet */
467void i2cproc_inc_use(struct i2c_client *client)
468{
469#ifdef MODULE
470  MOD_INC_USE_COUNT;
471#endif
472}
473
474/* Nothing here yet */
475void i2cproc_dec_use(struct i2c_client *client)
476{
477#ifdef MODULE
478  MOD_DEC_USE_COUNT;
479#endif
480}
481
482#ifdef MODULE
483
484MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
485MODULE_DESCRIPTION("I2C /proc/bus entries driver");
486
487int init_module(void)
488{
489  return i2cproc_init();
490}
491
492int cleanup_module(void)
493{
494  return i2cproc_cleanup();
495}
496
497#endif /* def MODULE */
498
Note: See TracBrowser for help on using the browser.