root/lm-sensors/trunk/src/sensors.c @ 19

Revision 19, 9.2 KB (checked in by frodo, 14 years ago)

Many things, most notable the lm78 module

* Some Makefile changes. doc/makefiles documents most of them.
* The lm78 module now compiles, but it will still crash.
* New module sensors, with general code usable by chip driver modules
* i2c-core: added function i2c_adapter_id(), which returns a (low)

unique i2c-bus ID.

* lm78.h stuff moved into lm78.c or sensors.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    sensors.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/malloc.h>
22#include <linux/ctype.h>
23#include <linux/sysctl.h>
24
25#include "version.h"
26#include "compat.h"
27#include "i2c.h"
28#include "isa.h"
29#include "sensors.h"
30
31#ifdef MODULE
32extern int init_module(void);
33extern int cleanup_module(void);
34#endif /* MODULE */
35
36int sensors_register_entry(struct i2c_client *client ,const char *prefix, 
37                           ctl_table *ctl_template);
38static int sensors_create_name(char **name, const char *prefix,
39                               struct i2c_adapter * adapter, int addr);
40static int sensors_init(void);
41static int sensors_cleanup(void);
42
43#define SENSORS_ENTRY_MAX 20
44static struct ctl_table_header *sensors_entries[SENSORS_ENTRY_MAX];
45
46static ctl_table sysctl_table[] = {
47  { CTL_DEV, "dev", NULL, 0, 0555 },
48  { 0 },
49  { DEV_SENSORS, "sensors", NULL, 0, 0555 },
50  { 0 },
51  { 0, NULL, NULL, 0, 0555 },
52  { 0 }
53};
54
55/* This returns a nice name for a new directory; for example lm78-isa-0310
56   (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for
57   a LM75 chip on the third i2c bus at address 0x4e). 
58   name is allocated first. */
59int sensors_create_name(char **name, const char *prefix, 
60                        struct i2c_adapter * adapter, int addr)
61{
62  char name_buffer[50]; 
63  int id;
64  if (i2c_is_isa_adapter(adapter)) 
65    sprintf(name_buffer,"%s-isa-%d",prefix,addr);
66  else {
67    if ((id = i2c_adapter_id(adapter)) < 0);
68      return -ENOENT;
69    sprintf(name_buffer,"%s-i2c-%d-%d",prefix,id,addr);
70  }
71  *name = kmalloc(strlen(name_buffer)+1,GFP_KERNEL);
72  strcpy(*name,name_buffer);
73  return 0;
74}
75
76/* This rather complex function must be called when you want to add an entry
77   to /proc/sys/dev/sensors/chips (not yet implemented). It also creates
78   a new directory within /proc/sys/dev/sensors/.
79   ctl_template should be a template of the newly created directory. It is
80   copied in memory. The extra1 field of each file is set to point to client.
81   If any driver wants subdirectories within the newly created directory,
82   this function must be updated! */
83int sensors_register_entry(struct i2c_client *client ,const char *prefix, 
84                           ctl_table *ctl_template)
85{
86  int i,res,len,id;
87  ctl_table *new_table;
88  char *name;
89  struct ctl_table_header *new_header;
90
91  if ((res = sensors_create_name(&name,prefix,client->adapter,
92                                 i2c_is_isa_client(client)?
93                                 ((struct isa_client *) client)->isa_addr:
94                                 client->addr)))
95    return res;
96
97  for (id = 0; id < SENSORS_ENTRY_MAX; i++)
98    if (! sensors_entries[id]) {
99      break;
100    }
101  if (id == SENSORS_ENTRY_MAX) {
102    kfree(name);
103    return -ENOMEM;
104  }
105  id += 256;
106
107  len = 0;
108  while (ctl_template[len].procname)
109    len++;
110  len += 7;
111  if (! (new_table = kmalloc(sizeof(ctl_table) * len,GFP_KERNEL))) {
112    kfree(name);
113    return -ENOMEM;
114  }
115   
116  memcpy(new_table,sysctl_table,6 * sizeof(ctl_table));
117  new_table[0].child = &new_table[2];
118  new_table[2].child = &new_table[4];
119  new_table[4].child = &new_table[6];
120  new_table[4].procname = name;
121  new_table[4].ctl_name = id;
122  memcpy(new_table+6,ctl_template,(len-6) * sizeof(ctl_table));
123  for (i = 6; i < len; i++)
124    new_table[i].extra1 = client;
125
126  if (! (new_header = register_sysctl_table(new_table,0))) {
127    kfree(new_table);
128    kfree(name);
129    return -ENOMEM;
130  }
131
132  sensors_entries[i] = new_header;
133
134  return id;
135}
136
137void sensors_deregister_entry(int id)
138{
139  ctl_table *table;
140  id -= 256;
141  if (sensors_entries[id]) {
142    table = sensors_entries[id]->ctl_table;
143    unregister_sysctl_table(sensors_entries[id]);
144    kfree((void *) (table->procname));
145    kfree(table);
146    sensors_entries[id] = 0;
147  }
148}
149
150/* nrels contains initially the maximum number of elements which can be
151   put in results, and finally the number of elements actually put there.
152   A magnitude of 1 will multiply everything with 10; etc.
153   buffer, bufsize is the character buffer we read from and its length.
154   results will finally contain the parsed integers.
155
156   Buffer should contain several reals, separated by whitespace. A real
157   has the following syntax:
158     [ Minus ] Digit* [ Dot Digit* ]
159   (everything between [] is optional; * means zero or more).
160   When the next character is unparsable, everything is skipped until the
161   next whitespace.
162
163   WARNING! This is tricky code. I have tested it, but there may still be
164            hidden bugs in it, even leading to crashes and things!
165*/
166void sensors_parse_reals(int *nrels, void *buffer, int bufsize, 
167                         long *results, int magnitude)
168{
169  int maxels,min,mag;
170  long res;
171  char nextchar=0;
172
173  maxels = *nrels;
174  *nrels = 0;
175
176  while (bufsize && (*nrels < maxels)) {
177
178    /* Skip spaces at the start */
179    while (bufsize && ! get_user_data(nextchar,(char *) buffer) && 
180           isspace((int) nextchar)) {
181      bufsize --;
182      ((char *) buffer)++;
183    }
184
185    /* Well, we may be done now */
186    if (! bufsize)
187      return;
188
189    /* New defaults for our result */
190    min = 0;
191    res = 0;
192    mag = magnitude;
193
194    /* Check for a minus */
195    if (! get_user_data(nextchar,(char *) buffer) && (nextchar == '-')) {
196      min=1;
197      bufsize--;
198      ((char *) buffer)++;
199    }
200
201    /* Digits before a decimal dot */
202    while (bufsize && !get_user_data(nextchar,(char *) buffer) && 
203           isdigit((int) nextchar)) {
204      res = res * 10 + nextchar - '0';
205      bufsize--;
206      ((char *) buffer)++;
207    }
208
209    /* If mag < 0, we must actually divide here! */
210    while (mag < 0) {
211      res = res / 10;
212      mag++;
213    }
214
215    if (bufsize && (nextchar == '.')) {
216      /* Skip the dot */
217      bufsize--;
218      ((char *) buffer)++;
219 
220      /* Read digits while they are significant */
221      while(bufsize && (mag > 0) && 
222            !get_user_data(nextchar,(char *) buffer) &&
223            isdigit((int) nextchar)) {
224        res = res * 10 + nextchar - '0';
225        mag--;
226        bufsize--;
227        ((char *) buffer)++;
228      }
229    }
230    /* If we are out of data, but mag > 0, we need to scale here */
231    while (mag > 0) {
232      res = res * 10;
233      mag --;
234    }
235
236    /* Skip everything until we hit whitespace */
237    while(bufsize && !get_user_data(nextchar,(char *) buffer) &&
238          isspace ((int) nextchar)) {
239      bufsize --;
240      ((char *) buffer) ++;
241    }
242
243    /* Put res in results */
244    results[*nrels] = (min?-1:1)*res;
245    (*nrels)++;
246  }   
247 
248  /* Well, there may be more in the buffer, but we need no more data.
249     Ignore anything that is left. */
250  return;
251}
252   
253void sensors_write_reals(int nrels,void *buffer,int *bufsize,long *results,
254                         int magnitude)
255{
256  #define BUFLEN 20
257  char BUF[BUFLEN+1]; /* An individual representation should fit in here! */
258  char printfstr[10];
259  int nr=0;
260  int buflen,mag,times;
261  int curbufsize=0;
262
263  while ((nr < nrels) && (curbufsize < *bufsize)) {
264    mag=magnitude;
265
266    if (nr != 0) {
267      put_user(' ', (char *) buffer);
268      curbufsize ++;
269      ((char *) buffer) ++;
270    }
271
272    /* Fill BUF with the representation of the next string */
273    if (mag <= 0) {
274
275      buflen=sprintf(BUF,"%ld",results[nr]);
276      if (buflen < 0) { /* Oops, a sprintf error! */
277        *bufsize=0;
278        return;
279      }
280      while ((mag < 0) && (buflen < BUFLEN)) {
281        BUF[buflen++]='0';
282        mag++;
283      }
284      BUF[buflen]=0;
285    } else {
286      times=1;
287      for (times=1; mag-- > 0; times *= 10);
288      if (results[nr] < 0) {
289        BUF[0] = '-';
290        buflen = 1;
291      } else
292        buflen=0;
293      strcpy(printfstr,"%ld.%0Xld");
294      printfstr[6]=magnitude+'0';
295      buflen+=sprintf(BUF+buflen,printfstr,abs(results[nr])/times,
296                      abs(results[nr])%times);
297      if (buflen < 0) { /* Oops, a sprintf error! */
298        *bufsize=0;
299        return;
300      }
301    }
302
303    /* Now copy it to the user-space buffer */
304    if (buflen + curbufsize > *bufsize)
305      buflen=*bufsize-curbufsize;
306    copy_to_user(buffer,BUF,buflen);
307    curbufsize += buflen;
308    (char *) buffer += buflen;
309
310    nr ++;
311  }
312  if (curbufsize < *bufsize) {
313    put_user('\n', (char *) buffer);
314    curbufsize ++;
315  }
316  *bufsize=curbufsize;
317}
318
319int sensors_init(void) 
320{
321  printk("sensors.o version %s (%s)\n",LM_VERSION,LM_DATE);
322  return 0;
323}
324
325int sensors_cleanup(void)
326{
327  return 0;
328}
329
330#ifdef MODULE
331
332MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
333MODULE_DESCRIPTION("LM78 driver");
334
335int init_module(void)
336{
337  return sensors_init();
338}
339
340int cleanup_module(void)
341{
342  return sensors_cleanup();
343}
344
345#endif /* MODULE */
346
Note: See TracBrowser for help on using the browser.