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

Revision 19, 33.0 KB (checked in by frodo, 16 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/*
3    lm78.c - A Linux module for reading sensor data.
4    Copyright (c) 1998  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/malloc.h>
23#include <linux/proc_fs.h>
24#include <linux/ioport.h>
25#include <linux/sysctl.h>
26#include <asm/errno.h>
27#include <asm/io.h>
28#include <linux/types.h>
29#include "smbus.h"
30#include "version.h"
31#include "isa.h"
32#include "sensors.h"
33#include "i2c.h"
34#include "compat.h"
35
36/* Many LM78 constants needed below */
37
38/* Length of ISA address segment */
39#define LM78_EXTENT 8
40
41/* Where are the ISA address/data registers relative to the base address */
42#define LM78_ADDR_REG_OFFSET 5
43#define LM78_DATA_REG_OFFSET 6
44
45/* The LM78 registers */
46#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2)
47#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2)
48#define LM78_REG_IN(nr) (0x20 + (nr))
49
50#define LM78_REG_FAN_MIN(nr) (0x3a + (nr))
51#define LM78_REG_FAN(nr) (0x27 + (nr))
52
53#define LM78_REG_TEMP 0x27
54#define LM78_REG_TEMP_OVER 0x39
55#define LM78_REG_TEMP_HYST 0x3a
56
57#define LM78_REG_ALARM1 0x41
58#define LM78_REG_ALARM2 0x42
59
60#define LM78_REG_VID_FANDIV 0x47
61
62#define LM78_REG_CONFIG 0x40
63
64
65/* Conversions */
66static int lm78_in_conv[7] = {10000, 10000, 10000, 16892, 38000, 
67                              -34768, -15050 };
68#define IN_TO_REG(val,nr) ((((val) * 100000 / lm78_in_conv[nr]) + 8) / 16)
69#define IN_FROM_REG(val,nr) (((val) *  16 * lm78_in_conv[nr]) / 100000)
70
71#define FAN_TO_REG(val) (((val)==0)?255:((1350000+(val))/((val)*2)))
72#define FAN_FROM_REG(val) (((val)==0)?-1:\
73                           ((val)==255)?0:(1350000 + (val))/((val)*2))
74
75#define TEMP_TO_REG(val) ((val)<0?(val)&0xff:(val))
76#define TEMP_FROM_REG(val) ((val)>0x80?(val)-0x100:(val));
77
78#define VID_FROM_REG(val) ((val) == 0x0f?0:350-(val)*10)
79
80#define ALARMS_FROM_REG(val) (val)
81
82#define DIV_FROM_REG(val) (1 >> (val))
83#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?1:2)
84
85/* Initial limits */
86#define LM78_INIT_IN_0 280
87#define LM78_INIT_IN_1 280
88#define LM78_INIT_IN_2 330
89#define LM78_INIT_IN_3 500
90#define LM78_INIT_IN_4 1200
91#define LM78_INIT_IN_5 -1200
92#define LM78_INIT_IN_6 -500
93
94#define LM78_INIT_IN_PERCENTAGE 100
95
96#define LM78_INIT_IN_MIN_0 \
97        (LM78_INIT_IN_0 - LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100)
98#define LM78_INIT_IN_MAX_0 \
99        (LM78_INIT_IN_0 + LM78_INIT_IN_0 * LM78_INIT_IN_PERCENTAGE / 100)
100#define LM78_INIT_IN_MIN_1 \
101        (LM78_INIT_IN_1 - LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100)
102#define LM78_INIT_IN_MAX_1 \
103        (LM78_INIT_IN_1 + LM78_INIT_IN_1 * LM78_INIT_IN_PERCENTAGE / 100)
104#define LM78_INIT_IN_MIN_2 \
105        (LM78_INIT_IN_2 - LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100)
106#define LM78_INIT_IN_MAX_2 \
107        (LM78_INIT_IN_2 + LM78_INIT_IN_2 * LM78_INIT_IN_PERCENTAGE / 100)
108#define LM78_INIT_IN_MIN_3 \
109        (LM78_INIT_IN_3 - LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100)
110#define LM78_INIT_IN_MAX_3 \
111        (LM78_INIT_IN_3 + LM78_INIT_IN_3 * LM78_INIT_IN_PERCENTAGE / 100)
112#define LM78_INIT_IN_MIN_4 \
113        (LM78_INIT_IN_4 - LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100)
114#define LM78_INIT_IN_MAX_4 \
115        (LM78_INIT_IN_4 + LM78_INIT_IN_4 * LM78_INIT_IN_PERCENTAGE / 100)
116#define LM78_INIT_IN_MIN_5 \
117        (LM78_INIT_IN_5 - LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100)
118#define LM78_INIT_IN_MAX_5 \
119        (LM78_INIT_IN_5 + LM78_INIT_IN_5 * LM78_INIT_IN_PERCENTAGE / 100)
120#define LM78_INIT_IN_MIN_6 \
121        (LM78_INIT_IN_6 - LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100)
122#define LM78_INIT_IN_MAX_6 \
123        (LM78_INIT_IN_6 + LM78_INIT_IN_6 * LM78_INIT_IN_PERCENTAGE / 100)
124
125#define LM78_INIT_FAN_MIN_1 3000
126#define LM78_INIT_FAN_MIN_2 3000
127#define LM78_INIT_FAN_MIN_3 3000
128
129#define LM78_INIT_TEMP_OVER 60
130#define LM78_INIT_TEMP_HYST 50
131
132#ifdef MODULE
133extern int init_module(void);
134extern int cleanup_module(void);
135#endif /* MODULE */
136
137/* There are some complications in a module like this. First off, LM78 chips
138   may be both present on the SMBus and the ISA bus, and we have to handle
139   those cases separately at some places. Second, there might be several
140   LM78 chips available (well, actually, that is probably never done; but
141   it is a clean illustration of how to handle a case like that). Finally,
142   a specific chip may be attached to *both* ISA and SMBus, and we would
143   not like to detect it double. Fortunately, in the case of the LM78 at
144   least, a register tells us what SMBus address we are on, so that helps
145   a bit - except if there could be more than one SMBus. Groan. No solution
146   for this yet. */
147
148/* This module may seem overly long and complicated. In fact, it is not so
149   bad. Quite a lot of bookkeeping is done. A real driver can often cut
150   some corners. */
151
152/* For each registered LM78, we need to keep some data in memory. That
153   data is pointed to by lm78_list[NR]->data. The structure itself is
154   dynamically allocated, at the same time when a new lm78 client is
155   allocated. */
156struct lm78_data {
157         struct semaphore lock;
158         int sysctl_id;
159
160         struct semaphore update_lock;
161         char valid;                 /* !=0 if following fields are valid */
162         unsigned long last_updated; /* In jiffies */
163
164         u8 in[7];                   /* Register value */
165         u8 in_max[7];               /* Register value */
166         u8 in_min[7];               /* Register value */
167         u8 fan[3];                  /* Register value */
168         u8 fan_min[3];              /* Register value */
169         u8 temp;                    /* Register value */
170         u8 temp_over;               /* Register value */
171         u8 temp_hyst;               /* Register value */
172         u8 fan_div[2];              /* Register encoding, shifted right */
173         u8 vid;                     /* Register encoding, combined */
174         u16 alarms;                 /* Register encoding, combined */
175};
176
177
178static int lm78_init(void);
179static int lm78_cleanup(void);
180
181static int lm78_attach_adapter(struct i2c_adapter *adapter);
182static int lm78_detect_isa(struct isa_adapter *adapter);
183static int lm78_detect_smbus(struct i2c_adapter *adapter);
184static int lm78_detach_client(struct i2c_client *client);
185static int lm78_detach_isa(struct isa_client *client);
186static int lm78_detach_smbus(struct i2c_client *client);
187static int lm78_new_client(struct i2c_adapter *adapter,
188                           struct i2c_client *new_client);
189static void lm78_remove_client(struct i2c_client *client);
190static int lm78_command(struct i2c_client *client, unsigned int cmd, 
191                        void *arg);
192static void lm78_inc_use (struct i2c_client *client);
193static void lm78_dec_use (struct i2c_client *client);
194
195static int lm78_read_value(struct i2c_client *client, u8 register);
196static int lm78_write_value(struct i2c_client *client, u8 register, u8 value);
197static void lm78_update_client(struct i2c_client *client);
198static void lm78_init_client(struct i2c_client *client);
199
200static int lm78_sysctl (ctl_table *table, int *name, int nlen, void *oldval, 
201                        size_t *oldlenp, void *newval, size_t newlen,
202                        void **context);
203static int lm78_proc (ctl_table *ctl, int write, struct file * filp,
204                      void *buffer, size_t *lenp);
205
206
207static void write_in(struct i2c_client *client, int nr, int nrels, 
208                     long *results);
209static void read_in(struct i2c_client *client, int nr, long *results);
210static void write_fan(struct i2c_client *client, int nr, int nrels, 
211                      long *results);
212static void read_fan(struct i2c_client *client, int nr, long *results);
213static void write_temp(struct i2c_client *client, int nrels, long *results);
214static void read_temp(struct i2c_client *client, long *results);
215static void read_vid(struct i2c_client *client, long *results);
216static void read_alarms(struct i2c_client *client, long *results);
217static void write_fan_div(struct i2c_client *client, int nrels, long *results);
218static void read_fan_div(struct i2c_client *client, long *results);
219
220
221
222/* I choose here for semi-static LM78 allocation. Complete dynamic
223   allocation could also be used; the code needed for this would probably
224   take more memory than the datastructure takes now. */
225#define MAX_LM78_NR 4
226static struct i2c_client *lm78_list[MAX_LM78_NR];
227
228/* The driver. I choose to use type i2c_driver, as at is identical to both
229   smbus_driver and isa_driver, and clients could be of either kind */
230static struct i2c_driver lm78_driver = {
231  /* name */            "LM78 sensor chip driver",
232  /* id */              I2C_DRIVERID_LM78,
233  /* flags */           DF_NOTIFY,
234  /* attach_adapter */  &lm78_attach_adapter,
235  /* detach_client */   &lm78_detach_client,
236  /* command */         &lm78_command,
237  /* inc_use */         &lm78_inc_use,
238  /* dec_use */         &lm78_dec_use
239};
240
241/* Used by lm78_init/cleanup */
242static int lm78_initialized = 0;
243
244/* The /proc/sys entries */
245/* These files are created for each detected LM78. This is just a template;
246   though at first sight, you might think we could use a statically
247   allocated list, we need some way to get back to the parent - which
248   is done through one of the 'extra' fields which are initialized
249   when a new copy is allocated. */
250static ctl_table lm78_dir_table_template[] = {
251  { LM78_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
252  { LM78_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
253  { LM78_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
254  { LM78_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
255  { LM78_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
256  { LM78_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
257  { LM78_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
258  { LM78_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
259  { LM78_SYSCTL_FAN2, "fan1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
260  { LM78_SYSCTL_FAN3, "fan1", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
261  { LM78_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
262  { LM78_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
263  { LM78_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl },
264
265  { LM78_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &lm78_proc, &lm78_sysctl }
266};
267
268
269/* This function is called when:
270     * lm78_driver is inserted (when this module is loaded), for each
271       available adapter
272     * when a new adapter is inserted (and lm78_driver is still present) */
273int lm78_attach_adapter(struct i2c_adapter *adapter)
274{
275  if (i2c_is_isa_adapter(adapter))
276    return lm78_detect_isa((struct isa_adapter *) adapter);
277  else
278    return lm78_detect_smbus(adapter);
279}
280
281/* This function is called whenever a client should be removed:
282    * lm78_driver is removed (when this module is unloaded)
283    * when an adapter is removed which has a lm78 client (and lm78_driver
284      is still present). */
285int lm78_detach_client(struct i2c_client *client)
286{
287  if (i2c_is_isa_client(client))
288    return lm78_detach_isa((struct isa_client *) client);
289  else
290    return lm78_detach_smbus(client);
291}
292
293/* Detect whether there is a LM78 on the ISA bus, register and initialize
294   it. */
295int lm78_detect_isa(struct isa_adapter *adapter)
296{
297  int address,err;
298  struct isa_client *new_client;
299
300  /* OK, this is no detection. I know. It will do for now, though.  */
301
302  err = 0;
303  for (address = 0x290; (! err) && (address <= 0x290); address += 0x08) {
304    if (check_region(address, LM78_EXTENT))
305      continue;
306   
307    if (inb_p(address + LM78_ADDR_REG_OFFSET) == 0xff) {
308      outb_p(0x00,address + LM78_ADDR_REG_OFFSET);
309      if (inb_p(address + LM78_ADDR_REG_OFFSET) == 0xff)
310        continue;
311    }
312   
313    /* Real detection code goes here */
314   
315    request_region(address, LM78_EXTENT, "lm78");
316
317    /* Allocate space for a new client structure */
318    if (! (new_client = kmalloc(sizeof(struct isa_client) + 
319                                sizeof(struct lm78_data),
320                               GFP_KERNEL)))
321    {
322      err=-ENOMEM;
323      goto ERROR1;
324    } 
325
326    /* Fill the new client structure with data */
327    new_client->data = (struct lm78_data *) (new_client + 1);
328    new_client->addr = 0;
329    new_client->isa_addr = address;
330    if ((err = lm78_new_client((struct i2c_adapter *) adapter,
331                               (struct i2c_client *) new_client)))
332      goto ERROR2;
333
334    /* Tell i2c-core a new client has arrived */
335    if ((err = isa_attach_client(new_client)))
336      goto ERROR3;
337   
338    /* Register a new directory entry with module sensors */
339    if ((err = sensors_register_entry((struct i2c_client *) new_client,"lm78",
340                                      lm78_dir_table_template) < 0))
341      goto ERROR4;
342    ((struct lm78_data *) (new_client->data)) -> sysctl_id = err;
343
344    /* Initialize the LM78 chip */
345    lm78_init_client((struct i2c_client *) new_client);
346    continue;
347
348/* OK, this is not exactly good programming practice, usually. But it is
349   very code-efficient in this case. */
350
351ERROR4:
352    isa_detach_client(new_client);
353ERROR3:
354    lm78_remove_client((struct i2c_client *) new_client);
355ERROR2:
356    kfree(new_client);
357ERROR1:
358    release_region(address, LM78_EXTENT);
359  }
360  return err;
361
362}
363
364/* Deregister and remove a LM78 client */
365int lm78_detach_isa(struct isa_client *client)
366{
367  int err,i;
368  for (i = 0; i < MAX_LM78_NR; i++)
369    if ((client == (struct isa_client *) (lm78_list[i])))
370      break;
371  if (i == MAX_LM78_NR) {
372    printk("lm78.o: Client to detach not found.\n");
373    return -ENOENT;
374  }
375
376  sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
377
378  if ((err = isa_detach_client(client))) {
379    printk("lm78.o: Client deregistration failed, client not detached.\n");
380    return err;
381  }
382  lm78_remove_client((struct i2c_client *) client);
383  kfree(client);
384  release_region(client->isa_addr,LM78_EXTENT);
385  return 0;
386}
387
388int lm78_detect_smbus(struct i2c_adapter *adapter)
389{
390  int address,err;
391  struct i2c_client *new_client;
392
393  /* OK, this is no detection. I know. It will do for now, though.  */
394  err = 0;
395  for (address = 0x20; (! err) && (address <= 0x2f); address ++) {
396
397    /* Later on, we will keep a list of registered addresses for each
398       adapter, and check whether they are used here */
399
400    if (smbus_read_byte_data(adapter,address,1) == 0xff) 
401      continue;
402
403    /* Real detection code goes here */
404
405    /* Allocate space for a new client structure */
406    if (! (new_client = kmalloc(sizeof(struct i2c_client) + 
407                                sizeof(struct lm78_data),
408                               GFP_KERNEL))) {
409      err = -ENOMEM;
410      continue;
411    }
412
413    /* Fill the new client structure with data */
414    new_client->data = (struct lm78_data *) (new_client + 1);
415    new_client->addr = address;
416    if ((err = lm78_new_client(adapter,new_client)))
417      goto ERROR2;
418
419    /* Tell i2c-core a new client has arrived */
420    if ((err = i2c_attach_client(new_client))) 
421      goto ERROR3;
422
423    /* Register a new directory entry with module sensors */
424    if ((err = sensors_register_entry(new_client,"lm78",
425                                      lm78_dir_table_template) < 0))
426      goto ERROR4;
427    ((struct lm78_data *) (new_client->data))->sysctl_id = err;
428
429    /* Initialize the LM78 chip */
430    lm78_init_client(new_client);
431    continue;
432
433/* OK, this is not exactly good programming practice, usually. But it is
434   very code-efficient in this case. */
435ERROR4:
436    i2c_detach_client(new_client);
437ERROR3:
438    lm78_remove_client((struct i2c_client *) new_client);
439ERROR2:
440    kfree(new_client);
441  }
442  return err;
443}
444
445int lm78_detach_smbus(struct i2c_client *client)
446{
447  int err,i;
448  for (i = 0; i < MAX_LM78_NR; i++)
449    if (client == lm78_list[i])
450      break;
451  if ((i == MAX_LM78_NR)) {
452    printk("lm78.o: Client to detach not found.\n");
453    return -ENOENT;
454  }
455
456  sensors_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
457
458  if ((err = i2c_detach_client(client))) {
459    printk("lm78.o: Client deregistration failed, client not detached.\n");
460    return err;
461  }
462  lm78_remove_client(client);
463  kfree(client);
464  return 0;
465}
466
467
468/* Find a free slot, and initialize most of the fields */
469int lm78_new_client(struct i2c_adapter *adapter,
470                    struct i2c_client *new_client)
471{
472  int i;
473  struct lm78_data *data;
474
475  /* First, seek out an empty slot */
476  for(i = 0; i < MAX_LM78_NR; i++)
477    if (! lm78_list[i])
478      break;
479  if (i == MAX_LM78_NR) {
480    printk("lm78.o: No empty slots left, recompile and heighten "
481           "MAX_LM78_NR!\n");
482    return -ENOMEM;
483  }
484 
485  lm78_list[i] = new_client;
486  strcpy(new_client->name,"LM78 chip");
487  new_client->id = i;
488  new_client->adapter = adapter;
489  new_client->driver = &lm78_driver;
490  data = new_client->data;
491  data->valid = 0;
492  data->lock = MUTEX;
493  data->update_lock = MUTEX;
494  return 0;
495}
496
497/* Inverse of lm78_new_client */
498void lm78_remove_client(struct i2c_client *client)
499{
500  int i;
501  for (i = 0; i < MAX_LM78_NR; i++)
502    if (client == lm78_list[i]) 
503      lm78_list[i] = NULL;
504}
505
506/* No commands defined yet */
507int lm78_command(struct i2c_client *client, unsigned int cmd, void *arg)
508{
509  return 0;
510}
511
512/* Nothing here yet */
513void lm78_inc_use (struct i2c_client *client)
514{
515}
516
517/* Nothing here yet */
518void lm78_dec_use (struct i2c_client *client)
519{
520}
521 
522
523/* The SMBus locks itself, but ISA access must be locked explicitely!
524   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
525   would slow down the LM78 access and should not be necessary.
526   There are some ugly typecasts here, but the good new is - they should
527   nowhere else be necessary! */
528int lm78_read_value(struct i2c_client *client, u8 reg)
529{
530  int res;
531  if (i2c_is_isa_client(client)) {
532    down((struct semaphore *) (client->data));
533    outb_p(reg,(((struct isa_client *) client)->isa_addr) + 
534               LM78_ADDR_REG_OFFSET);
535    res = inb_p((((struct isa_client *) client)->isa_addr) + 
536                LM78_DATA_REG_OFFSET);
537    up((struct semaphore *) (client->data));
538    return res;
539  } else
540    return smbus_read_byte_data(client->adapter,client->addr, reg);
541}
542
543/* The SMBus locks itself, but ISA access muse be locked explicitely!
544   We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
545   would slow down the LM78 access and should not be necessary.
546   There are some ugly typecasts here, but the good new is - they should
547   nowhere else be necessary! */
548int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
549{
550  if (i2c_is_isa_client(client)) {
551    down((struct semaphore *) (client->data));
552    outb_p(reg,((struct isa_client *) client)->isa_addr + LM78_ADDR_REG_OFFSET);
553    outb_p(value,((struct isa_client *) client)->isa_addr + LM78_DATA_REG_OFFSET);
554    up((struct semaphore *) (client->data));
555    return 0;
556  } else
557    return smbus_write_byte_data(client->adapter, client->addr, reg,value);
558}
559
560/* Called when we have found a new LM78. It should set limits, etc. */
561void lm78_init_client(struct i2c_client *client)
562{
563  /* Reset all except Watchdog values and last conversion values
564     This sets fan-divs to 2, among others */
565  lm78_write_value(client,LM78_REG_CONFIG,0x80);
566
567  lm78_write_value(client,LM78_REG_IN_MIN(0),IN_TO_REG(LM78_INIT_IN_MIN_0,0));
568  lm78_write_value(client,LM78_REG_IN_MAX(0),IN_TO_REG(LM78_INIT_IN_MAX_0,0));
569  lm78_write_value(client,LM78_REG_IN_MIN(1),IN_TO_REG(LM78_INIT_IN_MIN_1,1));
570  lm78_write_value(client,LM78_REG_IN_MAX(1),IN_TO_REG(LM78_INIT_IN_MAX_1,1));
571  lm78_write_value(client,LM78_REG_IN_MIN(2),IN_TO_REG(LM78_INIT_IN_MIN_2,2));
572  lm78_write_value(client,LM78_REG_IN_MAX(2),IN_TO_REG(LM78_INIT_IN_MAX_2,2));
573  lm78_write_value(client,LM78_REG_IN_MIN(3),IN_TO_REG(LM78_INIT_IN_MIN_3,3));
574  lm78_write_value(client,LM78_REG_IN_MAX(3),IN_TO_REG(LM78_INIT_IN_MAX_3,3));
575  lm78_write_value(client,LM78_REG_IN_MIN(4),IN_TO_REG(LM78_INIT_IN_MIN_4,4));
576  lm78_write_value(client,LM78_REG_IN_MAX(4),IN_TO_REG(LM78_INIT_IN_MAX_4,4));
577  lm78_write_value(client,LM78_REG_IN_MIN(5),IN_TO_REG(LM78_INIT_IN_MIN_5,5));
578  lm78_write_value(client,LM78_REG_IN_MAX(5),IN_TO_REG(LM78_INIT_IN_MAX_5,5));
579  lm78_write_value(client,LM78_REG_IN_MIN(6),IN_TO_REG(LM78_INIT_IN_MIN_6,6));
580  lm78_write_value(client,LM78_REG_IN_MAX(6),IN_TO_REG(LM78_INIT_IN_MAX_6,6));
581  lm78_write_value(client,LM78_REG_FAN_MIN(1),FAN_TO_REG(LM78_INIT_FAN_MIN_1));
582  lm78_write_value(client,LM78_REG_FAN_MIN(2),FAN_TO_REG(LM78_INIT_FAN_MIN_2));
583  lm78_write_value(client,LM78_REG_FAN_MIN(3),FAN_TO_REG(LM78_INIT_FAN_MIN_3));
584  lm78_write_value(client,LM78_REG_TEMP_OVER,TEMP_TO_REG(LM78_INIT_TEMP_OVER));
585  lm78_write_value(client,LM78_REG_TEMP_HYST,TEMP_TO_REG(LM78_INIT_TEMP_HYST));
586
587  /* Start monitoring */
588  lm78_write_value(client,LM78_REG_CONFIG,
589                   (lm78_read_value(client,LM78_REG_CONFIG) & 0xf7) | 0x01);
590 
591}
592
593void lm78_update_client(struct i2c_client *client)
594{
595  struct lm78_data *data =  client->data;
596  int i;
597
598  down(&data->update_lock);
599
600  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
601      (jiffies < data->last_updated) || ! data->valid) {
602
603    for (i = 0; i <= 6; i++) {
604      data->in[i]     = lm78_read_value(client,LM78_REG_IN(i));
605      data->in_min[i] = lm78_read_value(client,LM78_REG_IN_MIN(i));
606      data->in_max[i] = lm78_read_value(client,LM78_REG_IN_MAX(i));
607    }
608    for (i = 1; i <= 3; i++) {
609      data->fan[i-1] = lm78_read_value(client,LM78_REG_FAN(i));
610      data->fan_min[i-1] = lm78_read_value(client,LM78_REG_FAN_MIN(i));
611    }
612    data->temp = lm78_read_value(client,LM78_REG_TEMP);
613    data->temp_over = lm78_read_value(client,LM78_REG_TEMP_OVER);
614    data->temp_hyst = lm78_read_value(client,LM78_REG_TEMP_HYST);
615    i = lm78_read_value(client,LM78_REG_VID_FANDIV);
616    data->vid = i & 0x0f;
617    data->fan_div[0] = (i >> 4) & 0x03;
618    data->fan_div[1] = i >> 6;
619    data->alarms = lm78_read_value(client,LM78_REG_ALARM1) +
620                   (lm78_read_value(client,LM78_REG_ALARM2) >> 8);
621    data->last_updated = jiffies;
622    data->valid = 1;
623  }
624
625  up(&data->update_lock);
626}
627
628/* This function is called when /proc/sys/dev/lm78-???/... is accessed */
629int lm78_proc (ctl_table *ctl, int write, struct file * filp,
630               void *buffer, size_t *lenp)
631{
632  int nrels,mag;
633  long results[7];
634  struct i2c_client *client = ctl -> extra1;
635
636  /* If buffer is size 0, or we try to read when not at the start, we
637     return nothing. Note that I think writing when not at the start
638     does not work either, but anyway, this is straight from the kernel
639     sources. */
640  if (!*lenp || (filp->f_pos && !write)) {
641    *lenp = 0;
642    return 0;
643  }
644
645  /* How many numbers are found within these files, and how to scale them? */
646  switch (ctl->ctl_name) {
647    case LM78_SYSCTL_IN0: case LM78_SYSCTL_IN1: case LM78_SYSCTL_IN2:
648    case LM78_SYSCTL_IN3: case LM78_SYSCTL_IN4: case LM78_SYSCTL_IN5:
649    case LM78_SYSCTL_IN6:
650      nrels=3;
651      mag=2;
652      break;
653    case LM78_SYSCTL_FAN_DIV: case LM78_SYSCTL_TEMP:
654      nrels=3;
655      mag=0;
656      break;
657    case LM78_SYSCTL_FAN1: case LM78_SYSCTL_FAN2: case LM78_SYSCTL_FAN3:
658      nrels=2;
659      mag=0;
660      break;
661    case LM78_SYSCTL_VID:
662      nrels=1;
663      mag=2;
664      break;
665    case LM78_SYSCTL_ALARMS:
666      nrels=1;
667      mag=0;
668      break;
669    default: /* Should never be called */
670      return -EINVAL;
671  }
672 
673  /* OK, try writing stuff. */
674  if (write) {
675    sensors_parse_reals(&nrels,buffer,*lenp,results,mag);
676    if (nrels == 0)
677      return 0;
678    switch (ctl->ctl_name) {
679      case LM78_SYSCTL_IN0: write_in(client,0,nrels,results); break;
680      case LM78_SYSCTL_IN1: write_in(client,1,nrels,results); break;
681      case LM78_SYSCTL_IN2: write_in(client,2,nrels,results); break;
682      case LM78_SYSCTL_IN3: write_in(client,3,nrels,results); break;
683      case LM78_SYSCTL_IN4: write_in(client,4,nrels,results); break;
684      case LM78_SYSCTL_IN5: write_in(client,5,nrels,results); break;
685      case LM78_SYSCTL_IN6: write_in(client,6,nrels,results); break;
686      case LM78_SYSCTL_FAN1: write_fan(client,1,nrels,results); break;
687      case LM78_SYSCTL_FAN2: write_fan(client,2,nrels,results); break;
688      case LM78_SYSCTL_FAN3: write_fan(client,3,nrels,results); break;
689      case LM78_SYSCTL_FAN_DIV: write_fan_div(client,nrels,results);break;
690      case LM78_SYSCTL_TEMP: write_temp(client,nrels,results);break;
691      case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS: break;
692      default: /* Should never be called */ *lenp=0; return -EINVAL; break;
693    }
694    filp->f_pos += *lenp;
695    return 0;
696  } else { /* read */
697    /* Update all values in LM_Sensor_Data */
698
699    lm78_update_client((struct i2c_client *) (ctl->extra1));
700
701    /* Read the values to print into results */
702    switch (ctl->ctl_name) {
703      case LM78_SYSCTL_IN0: read_in(client,0,results);break;
704      case LM78_SYSCTL_IN1: read_in(client,1,results);break;
705      case LM78_SYSCTL_IN2: read_in(client,2,results);break;
706      case LM78_SYSCTL_IN3: read_in(client,3,results);break;
707      case LM78_SYSCTL_IN4: read_in(client,4,results);break;
708      case LM78_SYSCTL_IN5: read_in(client,5,results);break;
709      case LM78_SYSCTL_IN6: read_in(client,6,results);break;
710      case LM78_SYSCTL_FAN1: read_fan(client,1,results);break;
711      case LM78_SYSCTL_FAN2: read_fan(client,2,results);break;
712      case LM78_SYSCTL_FAN3: read_fan(client,3,results);break;
713      case LM78_SYSCTL_TEMP: read_temp(client,results);break;
714      case LM78_SYSCTL_FAN_DIV: read_fan_div(client,results);break;
715      case LM78_SYSCTL_VID: read_vid(client,results);break;
716      case LM78_SYSCTL_ALARMS: read_alarms(client,results);break;
717      default: /* Should never be called */ return -EINVAL;
718    }
719    /* OK, print it now */
720    sensors_write_reals(nrels,buffer,lenp,results,mag);
721    filp->f_pos += *lenp;
722    return 0;
723  }
724}
725
726/* This function is called when a sysctl on a lm78 file is done */
727int lm78_sysctl (ctl_table *table, int *name, int nlen, void *oldval, 
728               size_t *oldlenp, void *newval, size_t newlen,
729               void **context)
730{
731  long results[7];
732  int nrels,oldlen;
733  struct i2c_client *client = table -> extra1;
734 
735  /* How many numbers are found within these files, and how to scale them? */
736  switch (table->ctl_name) {
737    case LM78_SYSCTL_IN0: case LM78_SYSCTL_IN1: case LM78_SYSCTL_IN2:
738    case LM78_SYSCTL_IN3: case LM78_SYSCTL_IN4: case LM78_SYSCTL_IN5:
739    case LM78_SYSCTL_IN6: case LM78_SYSCTL_TEMP: case LM78_SYSCTL_FAN_DIV:
740      nrels=3;
741      break;
742    case LM78_SYSCTL_FAN1: case LM78_SYSCTL_FAN2: case LM78_SYSCTL_FAN3:
743      nrels=2;
744      break;
745    case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS:
746      nrels=1;
747      break;
748    default: /* Should never be called */
749      return -EINVAL;
750  }
751
752  /* Check if we need to output the old values */
753  if (oldval && oldlenp && ! get_user_data(oldlen,oldlenp) && oldlen) {
754
755    /* Update all values in LM_Sensor_Data */
756    lm78_update_client((struct i2c_client *) (table->extra1));
757    switch (table->ctl_name) {
758      case LM78_SYSCTL_IN0: read_in(client,0,results);break;
759      case LM78_SYSCTL_IN1: read_in(client,1,results);break;
760      case LM78_SYSCTL_IN2: read_in(client,2,results);break;
761      case LM78_SYSCTL_IN3: read_in(client,3,results);break;
762      case LM78_SYSCTL_IN4: read_in(client,4,results);break;
763      case LM78_SYSCTL_IN5: read_in(client,5,results);break;
764      case LM78_SYSCTL_IN6: read_in(client,6,results);break;
765      case LM78_SYSCTL_FAN1: read_fan(client,1,results);break;
766      case LM78_SYSCTL_FAN2: read_fan(client,2,results);break;
767      case LM78_SYSCTL_FAN3: read_fan(client,3,results);break;
768      case LM78_SYSCTL_TEMP: read_temp(client,results);break;
769      case LM78_SYSCTL_FAN_DIV: read_fan_div(client,results);break;
770      case LM78_SYSCTL_VID: read_vid(client,results);break;
771      case LM78_SYSCTL_ALARMS: read_alarms(client,results);break;
772      default: /* Should never be called */ return -EINVAL;
773    }
774   
775    /* Note the rounding factor! */
776    if (nrels * sizeof(long) < oldlen)
777      oldlen = nrels * sizeof(long);
778    oldlen = (oldlen / sizeof(long)) * sizeof(long);
779    copy_to_user(oldval,results,oldlen);
780    put_user(oldlen,oldlenp);
781  }
782
783  /* Check to see whether we need to read the new values */
784  if (newval && newlen) {
785    if (nrels * sizeof(long) < newlen)
786      newlen = nrels * sizeof(long);
787    nrels = newlen / sizeof(long);
788    newlen = (newlen / sizeof(long)) * sizeof(long);
789    copy_from_user(results,newval,newlen);
790   
791    switch (table->ctl_name) {
792      case LM78_SYSCTL_IN0: write_in(client,0,nrels,results); break;
793      case LM78_SYSCTL_IN1: write_in(client,1,nrels,results); break;
794      case LM78_SYSCTL_IN2: write_in(client,2,nrels,results); break;
795      case LM78_SYSCTL_IN3: write_in(client,3,nrels,results); break;
796      case LM78_SYSCTL_IN4: write_in(client,4,nrels,results); break;
797      case LM78_SYSCTL_IN5: write_in(client,5,nrels,results); break;
798      case LM78_SYSCTL_IN6: write_in(client,6,nrels,results); break;
799      case LM78_SYSCTL_FAN1: write_fan(client,1,nrels,results); break;
800      case LM78_SYSCTL_FAN2: write_fan(client,2,nrels,results); break;
801      case LM78_SYSCTL_FAN3: write_fan(client,3,nrels,results); break;
802      case LM78_SYSCTL_TEMP: write_temp(client,nrels,results); break;
803      case LM78_SYSCTL_FAN_DIV: write_fan_div(client,nrels,results);break;
804      case LM78_SYSCTL_VID: case LM78_SYSCTL_ALARMS: break;
805      default: /* Should never be called */ return -EINVAL; break;
806    }
807  }
808  return 1; /* We have done all the work */
809}
810
811void write_in(struct i2c_client *client, int nr, int nrels, long *results)
812{
813  struct lm78_data *data = client->data;
814  if (nrels >= 1) {
815    data->in_min[nr] = IN_TO_REG(results[0],nr);
816    lm78_write_value(client,LM78_REG_IN_MIN(nr),data->in_min[nr]);
817  }
818  if (nrels >= 2) {
819    data->in_max[nr] = IN_TO_REG(results[1],nr);
820    lm78_write_value(client,LM78_REG_IN_MAX(nr),data->in_max[nr]);
821  }
822}
823
824void read_in(struct i2c_client *client, int nr, long *results)
825{
826  struct lm78_data *data = client->data;
827  results[0] = IN_FROM_REG(data->in_min[nr],nr);
828  results[1] = IN_FROM_REG(data->in_min[nr],nr);
829  results[2] = IN_FROM_REG(data->in_min[nr],nr);
830}
831
832void write_fan(struct i2c_client *client, int nr, int nrels, long *results)
833{
834  struct lm78_data *data = client->data;
835  if (nrels >= 1) {
836    data->fan_min[nr-1] = FAN_TO_REG(results[0]);
837    lm78_write_value(client,LM78_REG_FAN_MIN(nr),data->fan_min[nr-1]);
838  }
839}
840
841void read_fan(struct i2c_client *client, int nr, long *results)
842{
843  struct lm78_data *data = client->data;
844  results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
845  results[1] = FAN_FROM_REG(data->fan[nr-1]);
846}
847
848void write_temp(struct i2c_client *client, int nrels, long *results)
849{
850  struct lm78_data *data = client->data;
851  if (nrels >= 1) {
852    data->temp_over = TEMP_TO_REG(results[0]);
853    lm78_write_value(client,LM78_REG_TEMP_OVER,data->temp_over);
854  }
855  if (nrels >= 2) {
856    data->temp_hyst = TEMP_TO_REG(results[0]);
857    lm78_write_value(client,LM78_REG_TEMP_HYST,data->temp_hyst);
858  }
859}
860
861void read_temp(struct i2c_client *client, long *results)
862{
863  struct lm78_data *data = client->data;
864  results[0] = TEMP_FROM_REG(data->temp_over);
865  results[1] = TEMP_FROM_REG(data->temp_hyst);
866  results[2] = TEMP_FROM_REG(data->temp);
867}
868
869void read_vid(struct i2c_client *client, long *results)
870{
871  struct lm78_data *data = client->data;
872  results[0] = VID_FROM_REG(data->vid);
873}
874
875void read_alarms(struct i2c_client *client, long *results)
876{
877  struct lm78_data *data = client->data;
878  results[0] = ALARMS_FROM_REG(data->alarms);
879}
880
881void read_fan_div(struct i2c_client *client, long *results)
882{
883  struct lm78_data *data = client->data;
884  results[0] = DIV_FROM_REG(data->fan_div[0]);
885  results[1] = DIV_FROM_REG(data->fan_div[1]);
886}
887 
888void write_fan_div(struct i2c_client *client, int nrels, long *results)
889{
890  struct lm78_data *data = client->data;
891  if (nrels >= 2)
892    data->fan_div[1] = DIV_TO_REG(results[1]);
893  if (nrels >= 1) {
894    data->fan_div[0] = DIV_TO_REG(results[0]);
895    lm78_write_value(client,LM78_REG_VID_FANDIV,
896                     (data->fan_div[0] >> 4) | (data->fan_div[1] >> 6));
897  }
898}
899
900int lm78_init(void)
901{
902  int res;
903
904  printk("lm78.o version %s (%s)\n",LM_VERSION,LM_DATE);
905  lm78_initialized = 0;
906
907  if ((res =i2c_add_driver(&lm78_driver))) {
908    printk("lm78.o: Driver registration failed, module not inserted.\n");
909    lm78_cleanup();
910    return res;
911  }
912  lm78_initialized ++;
913  return 0;
914}
915
916int lm78_cleanup(void)
917{
918  int res;
919
920  if (lm78_initialized >= 1) {
921    if ((res = i2c_del_driver(&lm78_driver))) {
922      printk("lm78.o: Driver deregistration failed, module not removed.\n");
923      return res;
924    }
925  } else
926    lm78_initialized --;
927
928  return 0;
929}
930
931
932#ifdef MODULE
933
934MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
935MODULE_DESCRIPTION("LM78 driver");
936
937int init_module(void)
938{
939  return lm78_init();
940}
941
942int cleanup_module(void)
943{
944  return lm78_cleanup();
945}
946
947#endif /* MODULE */
948
Note: See TracBrowser for help on using the browser.