root/lm-sensors/trunk/kernel/chips/matorb.c @ 513

Revision 513, 10.2 KB (checked in by frodo, 15 years ago)

First step to make it possible to integrate lm_sensors modules into

the kernel.

* <kernel/init.h> is now included for all modules
* Initialization-time only functions and variables are marked with init
* EXPORT_SYMBOL or EXPORT_NO_SYMBOLS declarations added

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    matorb.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
5    and Philip Edelbrock <phil@netroedge.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22
23#define DEBUG 1
24
25#include <linux/module.h>
26#include <linux/malloc.h>
27#include <linux/i2c.h>
28#include "sensors.h"
29#include "i2c-isa.h"
30#include "version.h"
31#include "compat.h"
32
33#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,53)
34#include <linux/init.h>
35#else
36#define __init
37#endif
38
39
40/* Addresses to scan */
41static unsigned short normal_i2c[] = {0x2E,SENSORS_I2C_END};
42static unsigned short normal_i2c_range[] = {SENSORS_I2C_END};
43static unsigned int normal_isa[] = {SENSORS_ISA_END};
44static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
45
46/* Insmod parameters */
47SENSORS_INSMOD_1(matorb);
48
49/* Many MATORB constants specified below */
50
51
52/* Each client has this additional data */
53struct matorb_data {
54         int sysctl_id;
55
56         struct semaphore update_lock;
57         char valid;                 /* !=0 if following fields are valid */
58         unsigned long last_updated; /* In jiffies */
59
60};
61
62#ifdef MODULE
63extern int init_module(void);
64extern int cleanup_module(void);
65#endif /* MODULE */
66
67static int __init matorb_init(void);
68static int __init matorb_cleanup(void);
69static int matorb_attach_adapter(struct i2c_adapter *adapter);
70static int matorb_detect(struct i2c_adapter *adapter, int address, int kind);
71static void matorb_init_client(struct i2c_client *client);
72static int matorb_detach_client(struct i2c_client *client);
73static int matorb_command(struct i2c_client *client, unsigned int cmd,
74                        void *arg);
75static void matorb_inc_use (struct i2c_client *client);
76static void matorb_dec_use (struct i2c_client *client);
77static int matorb_write_value(struct i2c_client *client, u8 reg, u16 value);
78static void matorb_disp(struct i2c_client *client, int operation, int ctl_name,
79                      int *nrels_mag, long *results);
80static void matorb_update_client(struct i2c_client *client);
81
82
83/* This is the driver that will be inserted */
84static struct i2c_driver matorb_driver = {
85  /* name */            "Matrix Orbital LCD driver",
86  /* id */              I2C_DRIVERID_MATORB,
87  /* flags */           I2C_DF_NOTIFY,
88  /* attach_adapter */  &matorb_attach_adapter,
89  /* detach_client */   &matorb_detach_client,
90  /* command */         &matorb_command,
91  /* inc_use */         &matorb_inc_use,
92  /* dec_use */         &matorb_dec_use
93};
94
95/* These files are created for each detected MATORB. This is just a template;
96   though at first sight, you might think we could use a statically
97   allocated list, we need some way to get back to the parent - which
98   is done through one of the 'extra' fields which are initialized
99   when a new copy is allocated. */
100static ctl_table matorb_dir_table_template[] = {
101  { MATORB_SYSCTL_DISP, "disp", NULL, 0, 0644, NULL, &sensors_proc_real,
102    &sensors_sysctl_real, NULL, &matorb_disp },
103  { 0 }
104};
105
106/* Used by init/cleanup */
107static int __init matorb_initialized = 0;
108
109/* I choose here for semi-static MATORB allocation. Complete dynamic
110   allocation could also be used; the code needed for this would probably
111   take more memory than the datastructure takes now. */
112#define MAX_MATORB_NR 16
113static struct i2c_client *matorb_list[MAX_MATORB_NR];
114
115
116int matorb_attach_adapter(struct i2c_adapter *adapter)
117{
118  return sensors_detect(adapter,&addr_data,matorb_detect);
119}
120
121/* This function is called by sensors_detect */
122int matorb_detect(struct i2c_adapter *adapter, int address, int kind)
123{
124  int i,cur;
125  struct i2c_client *new_client;
126  struct matorb_data *data;
127  int err=0;
128  const char *type_name="matorb";
129  const char *client_name="matorb";
130
131  /* Make sure we aren't probing the ISA bus!! This is just a safety check
132     at this moment; sensors_detect really won't call us. */
133#ifdef DEBUG
134  if (i2c_is_isa_adapter(adapter)) {
135    printk("matorb.o: matorb_detect called for an ISA bus adapter?!?\n");
136    return 0;
137  }
138#endif
139
140  /* Here, we have to do the address registration check for the I2C bus.
141     But that is not yet implemented. */
142
143  /* OK. For now, we presume we have a valid client. We now create the
144     client structure, even though we cannot fill it completely yet.
145     But it allows us to access matorb_{read,write}_value. */
146  if (! (new_client = kmalloc(sizeof(struct i2c_client) +
147                              sizeof(struct matorb_data),
148                              GFP_KERNEL))) {
149    err = -ENOMEM;
150    goto ERROR0;
151  }
152
153  data = (struct matorb_data *) (((struct i2c_client *) new_client) + 1);
154  new_client->addr = address;
155  new_client->data = data;
156  new_client->adapter = adapter;
157  new_client->driver = &matorb_driver;
158
159  /* Now, we do the remaining detection. It is lousy. */
160  cur = i2c_smbus_write_byte_data(adapter,address,0x0FE, 0x58); /* clear screen */
161 
162  printk("matorb.o: debug detect 0x%X\n",cur);
163 
164  /* Fill in the remaining client fields and put it into the global list */
165  strcpy(new_client->name,client_name);
166
167  /* Find a place in our global list */
168  for (i = 0; i < MAX_MATORB_NR; i++)
169    if (! matorb_list[i])
170       break;
171  if (i == MAX_MATORB_NR) {
172    err = -ENOMEM;
173    printk("matorb.o: No empty slots left, recompile and heighten "
174           "MAX_MATORB_NR!\n");
175    goto ERROR2;
176  }
177  matorb_list[i] = new_client;
178  new_client->id = i;
179  data->valid = 0;
180  init_MUTEX(&data->update_lock);
181   
182  /* Tell the I2C layer a new client has arrived */
183  if ((err = i2c_attach_client(new_client)))
184    goto ERROR3;
185
186  /* Register a new directory entry with module sensors */
187  if ((i = sensors_register_entry(new_client,type_name,
188                                  matorb_dir_table_template)) < 0) {
189    err = i;
190    goto ERROR4;
191  }
192  data->sysctl_id = i;
193
194  matorb_init_client((struct i2c_client *) new_client);
195  return 0;
196
197/* OK, this is not exactly good programming practice, usually. But it is
198   very code-efficient in this case. */
199
200ERROR4:
201  i2c_detach_client(new_client);
202ERROR3:
203  for (i = 0; i < MAX_MATORB_NR; i++)
204    if (new_client == matorb_list[i])
205      matorb_list[i] = NULL;
206ERROR2:
207  kfree(new_client);
208ERROR0:
209  return err;
210}
211
212int matorb_detach_client(struct i2c_client *client)
213{
214  int err,i;
215
216  sensors_deregister_entry(((struct matorb_data *)(client->data))->sysctl_id);
217
218  if ((err = i2c_detach_client(client))) {
219    printk("matorb.o: Client deregistration failed, client not detached.\n");
220    return err;
221  }
222
223  for (i = 0; i < MAX_MATORB_NR; i++)
224    if (client == matorb_list[i])
225      break;
226  if ((i == MAX_MATORB_NR)) {
227    printk("matorb.o: Client to detach not found.\n");
228    return -ENOENT;
229  }
230  matorb_list[i] = NULL;
231
232  kfree(client);
233
234  return 0;
235}
236
237
238/* No commands defined yet */
239int matorb_command(struct i2c_client *client, unsigned int cmd, void *arg)
240{
241  return 0;
242}
243
244/* Nothing here yet */
245void matorb_inc_use (struct i2c_client *client)
246{
247#ifdef MODULE
248  MOD_INC_USE_COUNT;
249#endif
250}
251
252/* Nothing here yet */
253void matorb_dec_use (struct i2c_client *client)
254{
255#ifdef MODULE
256  MOD_DEC_USE_COUNT;
257#endif
258}
259
260#if 0
261/* All registers are word-sized, except for the configuration register.
262   MATORB uses a high-byte first convention, which is exactly opposite to
263   the usual practice. */
264int matorb_read_value(struct i2c_client *client, u8 reg)
265{
266    return -1;  /* Doesn't support reads */
267}
268#endif
269
270/* All registers are word-sized, except for the configuration register.
271   MATORB uses a high-byte first convention, which is exactly opposite to
272   the usual practice. */
273int matorb_write_value(struct i2c_client *client, u8 reg, u16 value)
274{
275  if (reg==0) {
276    return i2c_smbus_write_byte(client->adapter,client->addr,value);
277  } else {
278    return i2c_smbus_write_byte_data(client->adapter,client->addr,reg,value);
279  }
280}
281
282void matorb_init_client(struct i2c_client *client)
283{
284    /* Initialize the MATORB chip */
285}
286
287void matorb_update_client(struct i2c_client *client)
288{
289  struct matorb_data *data = client->data;
290
291  down(&data->update_lock);
292
293  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
294      (jiffies < data->last_updated) || ! data->valid) {
295
296#ifdef DEBUG
297    printk("Starting matorb update\n");
298#endif
299
300/* nothing yet */
301    data->last_updated = jiffies;
302    data->valid = 1;
303  }
304
305  up(&data->update_lock);
306}
307
308
309void matorb_disp(struct i2c_client *client, int operation, int ctl_name,
310               int *nrels_mag, long *results)
311{
312int i;
313
314  if (operation == SENSORS_PROC_REAL_INFO)
315    *nrels_mag = 0;
316  else if (operation == SENSORS_PROC_REAL_READ) {
317    matorb_update_client(client);
318    results[0] = 0;
319    *nrels_mag = 3;
320  } else if (operation == SENSORS_PROC_REAL_WRITE) {
321    for (i=1; i<=*nrels_mag;i++) {
322      matorb_write_value(client,0,results[i-1]);
323    }
324  }
325}
326
327int __init matorb_init(void)
328{
329  int res;
330
331  printk("matorb.o version %s (%s)\n",LM_VERSION,LM_DATE);
332  matorb_initialized = 0;
333  if ((res = i2c_add_driver(&matorb_driver))) {
334    printk("matorb.o: Driver registration failed, module not inserted.\n");
335    matorb_cleanup();
336    return res;
337  }
338  matorb_initialized ++;
339  return 0;
340}
341
342int __init matorb_cleanup(void)
343{
344  int res;
345
346  if (matorb_initialized >= 1) {
347    if ((res = i2c_del_driver(&matorb_driver))) {
348      printk("matorb.o: Driver deregistration failed, module not removed.\n");
349      return res;
350    }
351    matorb_initialized --;
352  }
353
354  return 0;
355}
356
357EXPORT_NO_SYMBOLS;
358
359#ifdef MODULE
360
361MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
362MODULE_DESCRIPTION("MATORB driver");
363
364int init_module(void)
365{
366  return matorb_init();
367}
368
369int cleanup_module(void)
370{
371  return matorb_cleanup();
372}
373
374#endif /* MODULE */
375
Note: See TracBrowser for help on using the browser.