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

Revision 17, 11.6 KB (checked in by frodo, 15 years ago)

Dynamic generation of /proc/bus/i2c-? files (no info yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2c-proc.c - A Linux module for reading sensor data.
3    Copyright (c) 1998  Frodo Looijaard <frodol@dds.nl>
4
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
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
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
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20#include <linux/module.h>
21#include <linux/proc_fs.h>
22
23#include "i2c.h"
24#include "smbus.h"
25#include "isa.h"
26#include "version.h"
27#include "compat.h"
28#include "sensors.h"
29
30#ifdef MODULE
31extern int init_module(void);
32extern int cleanup_module(void);
33#endif /* def MODULE */
34
35static int i2cproc_init(void);
36static int i2cproc_cleanup(void);
37static int i2cproc_attach_adapter(struct i2c_adapter *adapter);
38static int i2cproc_detach_client(struct i2c_client *client);
39static int i2cproc_command(struct i2c_client *client, unsigned int cmd,
40                           void *arg);
41static void i2cproc_inc_use(struct i2c_client *client);
42static void i2cproc_dec_use(struct i2c_client *client);
43
44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
45
46static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
47                        int *eof , void *private);
48
49#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
50
51static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
52                        int unused);
53
54static struct proc_dir_entry proc_bus_dir =
55  {
56    /* low_ino */       0,     /* Set by proc_register_dynamic */
57    /* namelen */       3, 
58    /* name */          "bus",
59    /* mode */          S_IRUGO | S_IXUGO | S_IFDIR,
60    /* nlink */         1,     /* Corrected by proc_register[_dynamic] */
61    /* uid */           0,
62    /* gid */           0,
63    /* size */          0,
64    /* ops */           &proc_dir_inode_operations,
65  };
66
67static struct proc_dir_entry proc_bus_i2c_dir =
68  {
69    /* low_ino */       0,     /* Set by proc_register_dynamic */
70    /* namelen */       3, 
71    /* name */          "i2c",
72    /* mode */          S_IRUGO | S_IFREG,
73    /* nlink */         1,     
74    /* uid */           0,
75    /* gid */           0,
76    /* size */          0,
77    /* ops */           NULL,
78    /* get_info */      &read_bus_i2c
79  };
80
81/* List of registered entries in /proc/bus */
82static struct proc_dir_entry *i2cproc_proc_entries[I2C_ADAP_MAX];
83
84#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
85
86/* Used by init/cleanup */
87static int i2cproc_initialized;
88
89/* This is a sorted list of all adapters that will have entries in /proc/bus */
90static struct i2c_adapter *i2cproc_adapters[I2C_ADAP_MAX];
91
92/* We will use a nasty trick: we register a driver, that will be notified
93   for each adapter. Then, we register a dummy client on the adapter, that
94   will get notified if the adapter is removed. This is the same trick as
95   used in i2c/i2c-dev.c */
96static struct i2c_driver i2cproc_driver = {
97  /* name */            "i2c-proc dummy driver",
98  /* id */              I2C_DRIVERID_I2CPROC,
99  /* flags */           DF_NOTIFY,
100  /* attach_adapter */  &i2cproc_attach_adapter,
101  /* detach_client */   &i2cproc_detach_client,
102  /* command */         &i2cproc_command,
103  /* inc_use */         &i2cproc_inc_use,
104  /* dec_use */         &i2cproc_dec_use
105};
106
107static struct i2c_client i2cproc_client_template = {
108  /* name */            "i2c-proc dummy client",
109  /* id */              1,
110  /* flags */           0,
111  /* addr */            -1,
112  /* adapter */         NULL,
113  /* driver */          &i2cproc_driver,
114  /* data */            NULL
115};
116
117
118int i2cproc_init(void)
119{
120  int res;
121
122#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
123  struct proc_dir_entry *proc_bus_i2c;
124#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
125
126  printk("i2c-proc.o version %s (%s)\n",LM_VERSION,LM_DATE);
127  i2cproc_initialized = 0;
128
129#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
130  if (! proc_bus) {
131    printk("i2c-proc.o: /proc/bus/ does not exist, module not inserted.\n");
132    i2cproc_cleanup();
133    return -ENOENT;
134  }
135  proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
136  if (proc_bus_i2c)
137    proc_bus_i2c->read_proc = &read_bus_i2c;
138  else {
139    printk("i2c-proc.o: Could not create /proc/bus/i2c, "
140           "module not inserted.\n");
141    i2cproc_cleanup();
142    return -ENOENT;
143  }
144  i2cproc_initialized += 2;
145#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
146  /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module
147     introduced it, or we are fucked. */
148  if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) {
149    printk("i2c-proc.o: Could not create /proc/bus/, module not inserted.\n");
150    i2cproc_cleanup();
151    return res;
152  }
153  i2cproc_initialized ++;
154  if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) {
155    printk("i2c-proc.o: Could not create /proc/bus/i2c, "
156           "module not inserted.\n");
157    i2cproc_cleanup();
158    return res;
159  }
160  i2cproc_initialized ++;
161#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
162  if ((res = i2c_add_driver(&i2cproc_driver))) {
163    printk("i2c-proc.o: Driver registration failed, module not inserted.\n");
164    i2cproc_cleanup();
165    return res;
166  }
167  i2cproc_initialized ++;
168  return 0;
169}
170
171int i2cproc_cleanup(void)
172{
173  int res;
174
175  if (i2cproc_initialized >= 3) {
176    if ((res = i2c_del_driver(&i2cproc_driver))) {
177      printk("i2c-proc.o: Driver deregistration failed, "
178             "module not removed.\n");
179      return res;
180    }
181    i2cproc_initialized--;
182  }
183  if (i2cproc_initialized >= 1) {
184#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
185    if ((res = remove_proc_entry("i2c",proc_bus))) {
186      printk("i2c-proc.o: could not delete /proc/bus/i2c, module not removed.");
187      return res;
188    }
189    i2cproc_initialized -= 2;
190#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
191    if (i2cproc_initialized >= 2) {
192      if ((res = proc_unregister(&proc_bus_dir,proc_bus_i2c_dir.low_ino))) {
193         printk("i2c-proc.o: could not delete /proc/bus/i2c, "
194                "module not removed.");
195         return res;
196      }   
197      i2cproc_initialized --;
198    }
199    if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) {
200       printk("i2c-proc.o: could not delete /proc/bus/, "
201              "module not removed.");
202       return res;
203    }   
204    i2cproc_initialized --;
205#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
206  }
207  return 0;
208}
209
210#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
211int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
212                 void *private)
213#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
214int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused)
215#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
216{
217  int i;
218  len = 0;
219  for (i = 0; i < I2C_ADAP_MAX; i++)
220    if (i2cproc_adapters[i])
221      len += sprintf(buf, "/dev/i2c-%d\t%s\t%-32s\t%-32s\n",i,
222                     i2c_is_smbus_adapter(i2cproc_adapters[i])?"smbus":
223#ifdef DEBUG
224                       i2c_is_isa_adapter(i2cproc_adapters[i])?"isa":
225#endif /* def DEBUG */
226                       "i2c",
227                     i2cproc_adapters[i]->name,
228                     i2cproc_adapters[i]->algo->name);
229  return len;
230}
231
232#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
233int read_bus_i2c_file(char *buf, char **start, off_t offset, int len, 
234                      int *eof, void *private)
235#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
236int read_bus_i2c_file(char *buf, char **start, off_t offset, int len, 
237                      int unused)
238#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
239{
240  len = 0;
241  return len;
242}
243
244
245/* We need to add the adapter to i2cproc_adapters, if it is interesting
246   enough */
247int i2cproc_attach_adapter(struct i2c_adapter *adapter)
248{
249  struct i2c_client *client;
250  int i,res;
251  char name[8];
252
253  struct proc_dir_entry *proc_entry;
254
255#ifndef DEBUG
256  if (i2c_is_isa_adapter(adapter))
257    return 0;
258#endif /* ndef DEBUG */
259
260  for (i = 0; i < I2C_ADAP_MAX; i++)
261    if(!i2cproc_adapters[i])
262      break;
263  if (i == I2C_ADAP_MAX) {
264    printk("i2c-proc.o: Too many adapters!\n");
265    return -ENOMEM;
266  }
267
268  if (! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) {
269    printk("i2c-proc.o: Out of memory!\n");
270    return -ENOMEM;
271  }
272  memcpy(client,&i2cproc_client_template,sizeof(struct i2c_client));
273  client->adapter = adapter;
274  if ((res = i2c_attach_client(client))) {
275    printk("i2c-proc.o: Attaching client failed.\n");
276    kfree(client);
277    return res;
278  }
279  i2cproc_adapters[i] = adapter;
280
281  sprintf(name,"i2c-%d",i);
282
283#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
284  proc_entry = create_proc_entry(name,0,proc_bus);
285  if (! proc_entry)
286  else {
287    printk("i2c-proc.o: Could not create /proc/bus/%s\n",name);
288    kfree(client);
289    return -ENOENT;
290  }
291  proc_entry->read_proc = &read_bus_i2c_file;
292#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
293  if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+strlen(name)+1,
294                             GFP_KERNEL))) {
295    printk("i2c-proc.o: Out of memory!\n");
296    return -ENOMEM;
297  }
298
299  memset(proc_entry,0,sizeof(struct proc_dir_entry));
300  proc_entry->namelen = strlen(name);
301  proc_entry->name = (char *) (proc_entry + 1);
302  proc_entry->mode = S_IRUGO | S_IFREG;
303  proc_entry->nlink = 1;
304  proc_entry->get_info = &read_bus_i2c_file;
305  strcpy((char *) proc_entry->name,name);
306
307  if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) {
308    printk("i2c-proc.o: Could not create %s.\n",name);
309    kfree(proc_entry);
310    kfree(client);
311    return res;
312  }
313 
314  i2cproc_proc_entries[i] = proc_entry;
315#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
316  return 0;
317}
318 
319int i2cproc_detach_client(struct i2c_client *client)
320{
321  int i,res;
322#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
323  char name[8];
324#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
325
326  printk("OK!\n");
327#ifndef DEBUG
328  if (i2c_is_isa_client(client))
329    return 0;
330#endif /* ndef DEBUG */
331
332  for (i = 0; i < I2C_ADAP_MAX; i++) 
333    if (client->adapter == i2cproc_adapters[i]) {
334#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29))
335      sprintf(name,"i2c-%d",i);
336      if ((res = remove_proc_entry(name,proc_bus))) {
337        printk("i2c-proc.o: Deregistration of /proc entry failed, "
338               "client not detached.\n");
339        return res;
340      }
341#else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */
342      if ((res = proc_unregister(&proc_bus_dir,
343                                 i2cproc_proc_entries[i]->low_ino))) {
344        printk("i2c-proc.o: Deregistration of /proc entry failed, "
345               "client not detached.\n");
346        return res;
347      }
348      kfree(i2cproc_proc_entries[i]);
349      i2cproc_proc_entries[i] = NULL;
350#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */
351      if ((res = i2c_detach_client(client))) {
352        printk("i2c-proc.o: Client deregistration failed, "
353               "client not detached.\n");
354        return res;
355      }
356      i2cproc_adapters[i] = NULL;
357      kfree(client);
358      return 0;
359    }
360  return -ENOENT;
361}
362
363/* Nothing here yet */
364int i2cproc_command(struct i2c_client *client, unsigned int cmd,
365                    void *arg)
366{
367  return -1;
368}
369
370/* Nothing here yet */
371void i2cproc_inc_use(struct i2c_client *client)
372{
373}
374
375/* Nothing here yet */
376void i2cproc_dec_use(struct i2c_client *client)
377{
378}
379
380
381#ifdef MODULE
382
383MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
384MODULE_DESCRIPTION("I2C /proc/bus entries driver");
385
386int init_module(void)
387{
388  return i2cproc_init();
389}
390
391int cleanup_module(void)
392{
393  return i2cproc_cleanup();
394}
395
396#endif /* def MODULE */
397
Note: See TracBrowser for help on using the browser.