root/lm-sensors/trunk/kernel/chips/ddcmon.c @ 2784

Revision 2784, 18.0 KB (checked in by khali, 9 years ago)

Restore controlling_mod argument to i2c_register_entry(). This
is needed to properly lock chip drivers in memory while anyone uses their
/proc entries. This also brings back compatibility with the 2.4 Linux
kernel.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    ddcmon.c - Part of lm_sensors, Linux kernel modules for hardware
3               monitoring
4    Copyright (c) 1998, 1999, 2000  Frodo Looijaard <frodol@dds.nl>,
5    Philip Edelbrock <phil@netroedge.com>,
6    and Mark Studebaker <mdsxyz123@yahoo.com>
7    Copyright (c) 2003  Jean Delvare <khali@linux-fr.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include <linux/module.h>
25#include <linux/slab.h>
26#include <linux/i2c.h>
27#include <linux/i2c-proc.h>
28#include <linux/init.h>
29#include "version.h"
30
31MODULE_LICENSE("GPL");
32
33/* Addresses to scan */
34static unsigned short normal_i2c[] = { 0x50, SENSORS_I2C_END };
35static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
36static unsigned int normal_isa[] = { SENSORS_ISA_END };
37static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
38
39/* Insmod parameters */
40SENSORS_INSMOD_1(ddcmon);
41
42static int checksum = 0;
43MODULE_PARM(checksum, "i");
44MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct");
45
46/* Many constants specified below */
47
48/* DDCMON registers */
49/* vendor section */
50#define DDCMON_REG_MAN_ID 0x08
51#define DDCMON_REG_PROD_ID 0x0A
52#define DDCMON_REG_SERIAL 0x0C
53#define DDCMON_REG_WEEK 0x10
54#define DDCMON_REG_YEAR 0x11
55/* EDID version */
56#define DDCMON_REG_EDID_VER 0x12
57#define DDCMON_REG_EDID_REV 0x13
58/* display information */
59#define DDCMON_REG_HORSIZE 0x15
60#define DDCMON_REG_VERSIZE 0x16
61#define DDCMON_REG_GAMMA 0x17
62#define DDCMON_REG_DPMS_FLAGS 0x18
63/* supported timings */
64#define DDCMON_REG_ESTABLISHED_TIMINGS 0x23
65#define DDCMON_REG_STANDARD_TIMINGS 0x26
66#define DDCMON_REG_TIMBASE 0x36
67#define DDCMON_REG_TIMINCR 18
68#define DDCMON_REG_TIMNUM   4
69
70#define DDCMON_REG_CHECKSUM 0x7f
71
72/* Size of DDCMON in bytes */
73#define DDCMON_SIZE 128
74
75/* Each client has this additional data */
76struct ddcmon_data {
77        struct i2c_client client;
78        int sysctl_id;
79
80        struct semaphore update_lock;
81        char valid;             /* !=0 if following fields are valid */
82        unsigned long last_updated;     /* In jiffies */
83
84        u8 data[DDCMON_SIZE];   /* Register values */
85};
86
87
88static int ddcmon_attach_adapter(struct i2c_adapter *adapter);
89static int ddcmon_detect(struct i2c_adapter *adapter, int address,
90                         unsigned short flags, int kind);
91static int ddcmon_detach_client(struct i2c_client *client);
92
93static void ddcmon_idcall(struct i2c_client *client, int operation,
94                            int ctl_name, int *nrels_mag, long *results);
95static void ddcmon_size(struct i2c_client *client, int operation,
96                            int ctl_name, int *nrels_mag, long *results);
97static void ddcmon_sync(struct i2c_client *client, int operation,
98                            int ctl_name, int *nrels_mag, long *results);
99static void ddcmon_maxclock(struct i2c_client *client, int operation,
100                            int ctl_name, int *nrels_mag, long *results);
101static void ddcmon_timings(struct i2c_client *client, int operation,
102                            int ctl_name, int *nrels_mag, long *results);
103static void ddcmon_serial(struct i2c_client *client, int operation,
104                            int ctl_name, int *nrels_mag, long *results);
105static void ddcmon_time(struct i2c_client *client, int operation,
106                            int ctl_name, int *nrels_mag, long *results);
107static void ddcmon_edid(struct i2c_client *client, int operation,
108                            int ctl_name, int *nrels_mag, long *results);
109static void ddcmon_gamma(struct i2c_client *client, int operation,
110                            int ctl_name, int *nrels_mag, long *results);
111static void ddcmon_dpms(struct i2c_client *client, int operation,
112                            int ctl_name, int *nrels_mag, long *results);
113static void ddcmon_standard_timing(struct i2c_client *client, int operation,
114                            int ctl_name, int *nrels_mag, long *results);
115static void ddcmon_update_client(struct i2c_client *client);
116
117
118/* This is the driver that will be inserted */
119static struct i2c_driver ddcmon_driver = {
120        .name           = "DDCMON READER",
121        .id             = I2C_DRIVERID_DDCMON,
122        .flags          = I2C_DF_NOTIFY,
123        .attach_adapter = ddcmon_attach_adapter,
124        .detach_client  = ddcmon_detach_client,
125};
126
127/* -- SENSORS SYSCTL START -- */
128
129#define DDCMON_SYSCTL_ID 1010
130#define DDCMON_SYSCTL_SIZE 1011
131#define DDCMON_SYSCTL_SYNC 1012
132#define DDCMON_SYSCTL_TIMINGS 1013
133#define DDCMON_SYSCTL_SERIAL 1014
134#define DDCMON_SYSCTL_TIME 1015
135#define DDCMON_SYSCTL_EDID 1016
136#define DDCMON_SYSCTL_GAMMA 1017
137#define DDCMON_SYSCTL_DPMS 1018
138#define DDCMON_SYSCTL_TIMING1 1021
139#define DDCMON_SYSCTL_TIMING2 1022
140#define DDCMON_SYSCTL_TIMING3 1023
141#define DDCMON_SYSCTL_TIMING4 1024
142#define DDCMON_SYSCTL_TIMING5 1025
143#define DDCMON_SYSCTL_TIMING6 1026
144#define DDCMON_SYSCTL_TIMING7 1027
145#define DDCMON_SYSCTL_TIMING8 1028
146#define DDCMON_SYSCTL_MAXCLOCK 1029
147
148/* -- SENSORS SYSCTL END -- */
149
150/* These files are created for each detected DDCMON. This is just a template;
151   though at first sight, you might think we could use a statically
152   allocated list, we need some way to get back to the parent - which
153   is done through one of the 'extra' fields which are initialized
154   when a new copy is allocated. */
155static ctl_table ddcmon_dir_table_template[] = {
156        {DDCMON_SYSCTL_ID, "id", NULL, 0, 0444, NULL, &i2c_proc_real,
157         &i2c_sysctl_real, NULL, &ddcmon_idcall},
158        {DDCMON_SYSCTL_SIZE, "size", NULL, 0, 0444, NULL, &i2c_proc_real,
159         &i2c_sysctl_real, NULL, &ddcmon_size},
160        {DDCMON_SYSCTL_SYNC, "sync", NULL, 0, 0444, NULL,
161         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_sync},
162        {DDCMON_SYSCTL_TIMINGS, "timings", NULL, 0, 0444, NULL,
163         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_timings},
164        {DDCMON_SYSCTL_SERIAL, "serial", NULL, 0, 0444, NULL,
165         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_serial},
166        {DDCMON_SYSCTL_TIME, "time", NULL, 0, 0444, NULL,
167         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_time},
168        {DDCMON_SYSCTL_EDID, "edid", NULL, 0, 0444, NULL,
169         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_edid},
170        {DDCMON_SYSCTL_GAMMA, "gamma", NULL, 0, 0444, NULL,
171         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_gamma},
172        {DDCMON_SYSCTL_DPMS, "dpms", NULL, 0, 0444, NULL,
173         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_dpms},
174        {DDCMON_SYSCTL_TIMING1, "timing1", NULL, 0, 0444, NULL,
175         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
176        {DDCMON_SYSCTL_TIMING2, "timing2", NULL, 0, 0444, NULL,
177         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
178        {DDCMON_SYSCTL_TIMING3, "timing3", NULL, 0, 0444, NULL,
179         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
180        {DDCMON_SYSCTL_TIMING4, "timing4", NULL, 0, 0444, NULL,
181         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
182        {DDCMON_SYSCTL_TIMING5, "timing5", NULL, 0, 0444, NULL,
183         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
184        {DDCMON_SYSCTL_TIMING6, "timing6", NULL, 0, 0444, NULL,
185         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
186        {DDCMON_SYSCTL_TIMING7, "timing7", NULL, 0, 0444, NULL,
187         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
188        {DDCMON_SYSCTL_TIMING8, "timing8", NULL, 0, 0444, NULL,
189         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_standard_timing},
190        {DDCMON_SYSCTL_MAXCLOCK, "maxclock", NULL, 0, 0444, NULL,
191         &i2c_proc_real, &i2c_sysctl_real, NULL, &ddcmon_maxclock},
192        {0}
193};
194
195static int ddcmon_id = 0;
196
197static int ddcmon_attach_adapter(struct i2c_adapter *adapter)
198{
199        return i2c_detect(adapter, &addr_data, ddcmon_detect);
200}
201
202/* This function is called by i2c_detect */
203int ddcmon_detect(struct i2c_adapter *adapter, int address,
204                  unsigned short flags, int kind)
205{
206        int i, cs;
207        struct i2c_client *new_client;
208        struct ddcmon_data *data;
209        int err = 0;
210        const char *type_name, *client_name;
211
212        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
213                    goto ERROR0;
214
215        /* OK. For now, we presume we have a valid client. We now create the
216           client structure, even though we cannot fill it completely yet.
217           But it allows us to access ddcmon_{read,write}_value. */
218        if (!(data = kmalloc(sizeof(struct ddcmon_data), GFP_KERNEL))) {
219                err = -ENOMEM;
220                goto ERROR0;
221        }
222
223        new_client = &data->client;
224        memset(data->data, 0xff, DDCMON_SIZE);
225        new_client->addr = address;
226        new_client->data = data;
227        new_client->adapter = adapter;
228        new_client->driver = &ddcmon_driver;
229        new_client->flags = 0;
230
231        /* prevent 24RF08 corruption (just in case) */
232        i2c_smbus_write_quick(new_client, 0);
233
234        /* Now, we do the remaining detection. */
235        if (checksum) {
236                int cs = 0;
237                for (i = 0; i < 0x80; i++)
238                        cs += i2c_smbus_read_byte_data(new_client, i);
239                if ((cs & 0xff) != 0)
240                        goto ERROR1;
241        }
242
243        /* Verify the first 8 locations 0x00FFFFFFFFFFFF00 */
244        /* Allow force and force_ddcmon arguments */
245        if(kind < 0)
246        {
247                for(i = 0; i < 8; i++) {
248                        cs = i2c_smbus_read_byte_data(new_client, i);
249                        if(i == 0 || i == 7) {
250                                if(cs != 0)
251                                        goto ERROR1;
252                        } else if(cs != 0xff)
253                                goto ERROR1;
254                }
255        }
256
257        type_name = "ddcmon";
258        client_name = "DDC Monitor";
259
260        /* Fill in the remaining client fields and put it in the global list */
261        strcpy(new_client->name, client_name);
262
263        new_client->id = ddcmon_id++;
264        data->valid = 0;
265        init_MUTEX(&data->update_lock);
266
267        /* Tell the I2C layer a new client has arrived */
268        if ((err = i2c_attach_client(new_client)))
269                goto ERROR3;
270
271        /* Register a new directory entry with module sensors */
272        if ((i = i2c_register_entry(new_client, type_name,
273                                        ddcmon_dir_table_template,
274                                        THIS_MODULE)) < 0) {
275                err = i;
276                goto ERROR4;
277        }
278        data->sysctl_id = i;
279
280        return 0;
281
282      ERROR4:
283        i2c_detach_client(new_client);
284      ERROR3:
285      ERROR1:
286        kfree(data);
287      ERROR0:
288        return err;
289}
290
291static int ddcmon_detach_client(struct i2c_client *client)
292{
293        int err;
294
295        i2c_deregister_entry(((struct ddcmon_data *) (client->data))->
296                                 sysctl_id);
297        if ((err = i2c_detach_client(client))) {
298                printk
299                    ("ddcmon.o: Client deregistration failed, client not detached.\n");
300                return err;
301        }
302        kfree(client->data);
303        return 0;
304}
305
306static void ddcmon_update_client(struct i2c_client *client)
307{
308        struct ddcmon_data *data = client->data;
309        int i, j;
310
311        down(&data->update_lock);
312
313        if ((jiffies - data->last_updated > 300 * HZ) ||
314            (jiffies < data->last_updated) || !data->valid) {
315                if (i2c_check_functionality(client->adapter,
316                                            I2C_FUNC_SMBUS_READ_I2C_BLOCK))
317                {
318                        for (i=0; i<DDCMON_SIZE; i+=I2C_SMBUS_I2C_BLOCK_MAX)
319                                if (i2c_smbus_read_i2c_block_data(client,
320                                                           i, data->data + i)
321                                                    != I2C_SMBUS_I2C_BLOCK_MAX) {
322                                        printk(KERN_WARNING "ddcmon.o: block read fail at 0x%.2x!\n", i);
323                                        goto DONE;
324                                }
325                } else {
326                        if (i2c_smbus_write_byte(client, 0)) {
327                                printk(KERN_WARNING "ddcmon.o: read start fail at 0!\n");
328                                goto DONE;
329                        }
330                        for (i = 0; i < DDCMON_SIZE; i++) {
331                                j = i2c_smbus_read_byte(client);
332                                if (j < 0) {
333                                        printk(KERN_WARNING "eeprom.o: read fail at 0x%.2x!\n", i);
334                                        goto DONE;
335                                }
336                                data->data[i] = (u8) j;
337                        }
338                }
339                data->last_updated = jiffies;
340                data->valid = 1;
341        }
342DONE:
343        up(&data->update_lock);
344}
345
346
347void ddcmon_idcall(struct i2c_client *client, int operation,
348                   int ctl_name, int *nrels_mag, long *results)
349{
350        struct ddcmon_data *data = client->data;
351
352        if (operation == SENSORS_PROC_REAL_INFO)
353                *nrels_mag = 0;
354        else if (operation == SENSORS_PROC_REAL_READ) {
355                ddcmon_update_client(client);
356                results[0] = data->data[DDCMON_REG_MAN_ID + 1] |
357                             (data->data[DDCMON_REG_MAN_ID] << 8);
358                results[1] = data->data[DDCMON_REG_PROD_ID + 1] |
359                             (data->data[DDCMON_REG_PROD_ID] << 8);
360                *nrels_mag = 2;
361        }
362}
363
364void ddcmon_size(struct i2c_client *client, int operation,
365                 int ctl_name, int *nrels_mag, long *results)
366{
367        struct ddcmon_data *data = client->data;
368
369        if (operation == SENSORS_PROC_REAL_INFO)
370                *nrels_mag = 0;
371        else if (operation == SENSORS_PROC_REAL_READ) {
372                ddcmon_update_client(client);
373                results[0] = data->data[DDCMON_REG_VERSIZE];
374                results[1] = data->data[DDCMON_REG_HORSIZE];
375                *nrels_mag = 2;
376        }
377}
378
379void ddcmon_sync(struct i2c_client *client, int operation,
380                    int ctl_name, int *nrels_mag, long *results)
381{
382        int i, j;
383        struct ddcmon_data *data = client->data;
384
385        if (operation == SENSORS_PROC_REAL_INFO)
386                *nrels_mag = 0;
387        else if (operation == SENSORS_PROC_REAL_READ) {
388                ddcmon_update_client(client);
389                *nrels_mag = 4;
390                /* look for monitor limits entry */
391                for(i = DDCMON_REG_TIMBASE;
392                    i < DDCMON_REG_TIMBASE +
393                        (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR);
394                    i += DDCMON_REG_TIMINCR) {
395                        if (data->data[i] == 0x00
396                         && data->data[i + 1] == 0x00
397                         && data->data[i + 2] == 0x00
398                         && data->data[i + 3] == 0xfd) {
399                                for(j = 0; j < 4; j++)
400                                        results[j] = data->data[i + j + 5];
401                                return;
402                        }
403                }
404                for(j = 0; j < 4; j++)
405                        results[j] = 0;
406        }
407}
408
409void ddcmon_maxclock(struct i2c_client *client, int operation,
410                    int ctl_name, int *nrels_mag, long *results)
411{
412        int i;
413        struct ddcmon_data *data = client->data;
414
415        if (operation == SENSORS_PROC_REAL_INFO)
416                *nrels_mag = 0;
417        else if (operation == SENSORS_PROC_REAL_READ) {
418                ddcmon_update_client(client);
419                *nrels_mag = 1;
420                /* look for monitor limits entry */
421                for(i = DDCMON_REG_TIMBASE;
422                    i < DDCMON_REG_TIMBASE +
423                        (DDCMON_REG_TIMNUM * DDCMON_REG_TIMINCR);
424                    i += DDCMON_REG_TIMINCR) {
425                        if (data->data[i] == 0x00
426                         && data->data[i + 1] == 0x00
427                         && data->data[i + 2] == 0x00
428                         && data->data[i + 3] == 0xfd) {
429                                results[0] = (data->data[i + 9] == 0xff ?
430                                             0 : data->data[i + 9] * 10);
431                                return;
432                        }
433                }
434                results[0] = 0;
435        }
436}
437
438void ddcmon_timings(struct i2c_client *client, int operation,
439                    int ctl_name, int *nrels_mag, long *results)
440{
441        struct ddcmon_data *data = client->data;
442
443        if (operation == SENSORS_PROC_REAL_INFO)
444                *nrels_mag = 0;
445        else if (operation == SENSORS_PROC_REAL_READ) {
446                ddcmon_update_client(client);
447                results[0] = data->data[DDCMON_REG_ESTABLISHED_TIMINGS] |
448                             (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 1] << 8) |
449                             (data->data[DDCMON_REG_ESTABLISHED_TIMINGS + 2] << 16);
450                *nrels_mag = 1;
451        }
452}
453
454void ddcmon_serial(struct i2c_client *client, int operation,
455                    int ctl_name, int *nrels_mag, long *results)
456{
457        struct ddcmon_data *data = client->data;
458
459        if (operation == SENSORS_PROC_REAL_INFO)
460                *nrels_mag = 0;
461        else if (operation == SENSORS_PROC_REAL_READ) {
462                ddcmon_update_client(client);
463                results[0] = data->data[DDCMON_REG_SERIAL] |
464                             (data->data[DDCMON_REG_SERIAL + 1] << 8) |
465                             (data->data[DDCMON_REG_SERIAL + 2] << 16) |
466                             (data->data[DDCMON_REG_SERIAL + 3] << 24);
467                *nrels_mag = 1;
468        }
469}
470
471void ddcmon_time(struct i2c_client *client, int operation,
472                 int ctl_name, int *nrels_mag, long *results)
473{
474        struct ddcmon_data *data = client->data;
475
476        if (operation == SENSORS_PROC_REAL_INFO)
477                *nrels_mag = 0;
478        else if (operation == SENSORS_PROC_REAL_READ) {
479                ddcmon_update_client(client);
480                results[0] = data->data[DDCMON_REG_YEAR] + 1990;
481                results[1] = data->data[DDCMON_REG_WEEK];
482                *nrels_mag = 2;
483        }
484}
485
486void ddcmon_edid(struct i2c_client *client, int operation,
487                 int ctl_name, int *nrels_mag, long *results)
488{
489        struct ddcmon_data *data = client->data;
490
491        if (operation == SENSORS_PROC_REAL_INFO)
492                *nrels_mag = 0;
493        else if (operation == SENSORS_PROC_REAL_READ) {
494                ddcmon_update_client(client);
495                results[0] = data->data[DDCMON_REG_EDID_VER];
496                results[1] = data->data[DDCMON_REG_EDID_REV];
497                *nrels_mag = 2;
498        }
499}
500
501void ddcmon_gamma(struct i2c_client *client, int operation,
502                 int ctl_name, int *nrels_mag, long *results)
503{
504        struct ddcmon_data *data = client->data;
505
506        if (operation == SENSORS_PROC_REAL_INFO)
507                *nrels_mag = 2;
508        else if (operation == SENSORS_PROC_REAL_READ) {
509                ddcmon_update_client(client);
510                results[0] = 100 + data->data[DDCMON_REG_GAMMA];
511                *nrels_mag = 1;
512        }
513}
514
515void ddcmon_dpms(struct i2c_client *client, int operation,
516                 int ctl_name, int *nrels_mag, long *results)
517{
518        struct ddcmon_data *data = client->data;
519
520        if (operation == SENSORS_PROC_REAL_INFO)
521                *nrels_mag = 0;
522        else if (operation == SENSORS_PROC_REAL_READ) {
523                ddcmon_update_client(client);
524                results[0] = data->data[DDCMON_REG_DPMS_FLAGS];
525                *nrels_mag = 1;
526        }
527}
528
529void ddcmon_standard_timing(struct i2c_client *client, int operation,
530                 int ctl_name, int *nrels_mag, long *results)
531{
532        struct ddcmon_data *data = client->data;
533        int nr = ctl_name - DDCMON_SYSCTL_TIMING1;
534
535        if (operation == SENSORS_PROC_REAL_INFO)
536                *nrels_mag = 0;
537        else if (operation == SENSORS_PROC_REAL_READ) {
538                ddcmon_update_client(client);
539                /* If both bytes of the timing are 0x00 or 0x01, then the timing
540                   slot is unused. */
541                if ((data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2]
542                    | data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1]) & 0xfe) {
543                        results[0] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2] + 31) * 8;
544                        switch (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] >> 6) {
545                                /* We don't care about rounding issues there, it really
546                                   should be OK without it. */
547                                case 0x00:
548                                        results[1] = results[0]; /* unconfirmed */
549                                        break;
550                                case 0x01:
551                                        results[1] = results[0] * 3 / 4;
552                                        break;
553                                case 0x02:
554                                        results[1] = results[0] * 4 / 5;
555                                        break;
556                                case 0x03:
557                                        results[1] = results[0] * 9 / 16;
558                                        break;
559                        }
560                        results[2] = (data->data[DDCMON_REG_STANDARD_TIMINGS + nr * 2 + 1] & 0x3f) + 60;
561                } else {
562                        results[0] = 0;
563                        results[1] = 0;
564                        results[2] = 0;
565                }
566                *nrels_mag = 3;
567        }
568}
569
570static int __init sm_ddcmon_init(void)
571{
572        printk("ddcmon.o version %s (%s)\n", LM_VERSION, LM_DATE);
573        return i2c_add_driver(&ddcmon_driver);
574}
575
576static void __exit sm_ddcmon_exit(void)
577{
578        i2c_del_driver(&ddcmon_driver);
579}
580
581
582
583MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
584              "Philip Edelbrock <phil@netroedge.com>, "
585              "Mark Studebaker <mdsxyz123@yahoo.com> "
586                  "and Jean Delvare <khali@linux-fr.org>");
587MODULE_DESCRIPTION("DDCMON driver");
588
589module_init(sm_ddcmon_init);
590module_exit(sm_ddcmon_exit);
Note: See TracBrowser for help on using the browser.