root/i2c/trunk/kernel/i2c-dev.c @ 3437

Revision 3437, 12.6 KB (checked in by frodo, 13 years ago)

Russell King's 'calling NULL functions' patch (slightly modified)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2c-dev.c - i2c-bus driver, char device interface 
3
4    Copyright (C) 1995-97 Simon G. Vogl
5    Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
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/* Note that this is a complete rewrite of Simon Vogl's i2c-dev module.
23   But I have used so much of his original code and ideas that it seems
24   only fair to recognize him as co-author -- Frodo */
25
26/* $Id$ */
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/fs.h>
31#include <linux/malloc.h>
32#include <linux/version.h>
33
34/* If you want debugging uncomment: */
35/* #define DEBUG */
36
37#include <linux/init.h>
38#include <asm/uaccess.h>
39
40#include "i2c.h"
41#include "i2c-dev.h"
42
43#ifdef MODULE
44extern int init_module(void);
45extern int cleanup_module(void);
46#endif /* def MODULE */
47
48/* struct file_operations changed too often in the 2.1 series for nice code */
49
50static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
51
52static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
53                            loff_t *offset);
54static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
55                             loff_t *offset);
56
57static int i2cdev_ioctl (struct inode *inode, struct file *file, 
58                         unsigned int cmd, unsigned long arg);
59static int i2cdev_open (struct inode *inode, struct file *file);
60
61static int i2cdev_release (struct inode *inode, struct file *file);
62
63static int i2cdev_attach_adapter(struct i2c_adapter *adap);
64static int i2cdev_detach_client(struct i2c_client *client);
65static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
66                           void *arg);
67
68#ifdef MODULE
69static
70#else
71extern
72#endif
73       int __init i2c_dev_init(void);
74static int i2cdev_cleanup(void);
75
76static struct file_operations i2cdev_fops = {
77        i2cdev_lseek,
78        i2cdev_read,
79        i2cdev_write,
80        NULL,                   /* i2cdev_readdir       */
81        NULL,                   /* i2cdev_select        */
82        i2cdev_ioctl,
83        NULL,                   /* i2cdev_mmap          */
84        i2cdev_open,
85        NULL,                   /* i2cdev_flush         */
86        i2cdev_release,
87};
88
89#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
90static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
91
92static struct i2c_driver i2cdev_driver = {
93        /* name */              "i2c-dev dummy driver",
94        /* id */                I2C_DRIVERID_I2CDEV,
95        /* flags */             I2C_DF_DUMMY,
96        /* attach_adapter */    i2cdev_attach_adapter,
97        /* detach_client */     i2cdev_detach_client,
98        /* command */           i2cdev_command,
99        /* inc_use */           NULL,
100        /* dec_use */           NULL,
101};
102
103static struct i2c_client i2cdev_client_template = {
104        /* name */              "I2C /dev entry",
105        /* id */                1,
106        /* flags */             0,
107        /* addr */              -1,
108        /* adapter */           NULL,
109        /* driver */            &i2cdev_driver,
110        /* data */              NULL
111};
112
113static int i2cdev_initialized;
114
115/* Note that the lseek function is called llseek in 2.1 kernels. But things
116   are complicated enough as is. */
117loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
118{
119#ifdef DEBUG
120        struct inode *inode = file->f_dentry->d_inode;
121        printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
122               MINOR(inode->i_rdev),(long) offset,origin);
123#endif /* DEBUG */
124        return -ESPIPE;
125}
126
127static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
128                            loff_t *offset)
129{
130        char *tmp;
131        int ret;
132
133#ifdef DEBUG
134        struct inode *inode = file->f_dentry->d_inode;
135#endif /* DEBUG */
136
137        struct i2c_client *client = (struct i2c_client *)file->private_data;
138
139        /* copy user space data to kernel space. */
140        tmp = kmalloc(count,GFP_KERNEL);
141        if (tmp==NULL)
142                return -ENOMEM;
143
144#ifdef DEBUG
145        printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
146               count);
147#endif
148
149        ret = i2c_master_recv(client,tmp,count);
150        if (! ret)
151                copy_to_user(buf,tmp,count);
152        kfree(tmp);
153        return ret;
154}
155
156static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
157                             loff_t *offset)
158{
159        int ret;
160        char *tmp;
161        struct i2c_client *client = (struct i2c_client *)file->private_data;
162
163#ifdef DEBUG
164        struct inode *inode = file->f_dentry->d_inode;
165#endif /* DEBUG */
166
167        /* copy user space data to kernel space. */
168        tmp = kmalloc(count,GFP_KERNEL);
169        if (tmp==NULL)
170                return -ENOMEM;
171        copy_from_user(tmp,buf,count);
172
173#ifdef DEBUG
174        printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
175               count);
176#endif
177        ret = i2c_master_send(client,tmp,count);
178        kfree(tmp);
179        return ret;
180}
181
182int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 
183                  unsigned long arg)
184{
185        struct i2c_client *client = (struct i2c_client *)file->private_data;
186        struct i2c_smbus_ioctl_data data_arg;
187        union i2c_smbus_data temp;
188        int ver,datasize,res;
189        unsigned long funcs;
190
191#ifdef DEBUG
192        printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
193               MINOR(inode->i_rdev),cmd, arg);
194#endif /* DEBUG */
195
196        switch ( cmd ) {
197        case I2C_SLAVE:
198        case I2C_SLAVE_FORCE:
199                if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
200                        return -EINVAL;
201                if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
202                        return -EBUSY;
203                client->addr = arg;
204                return 0;
205        case I2C_TENBIT:
206                if (arg)
207                        client->flags |= I2C_M_TEN;
208                else
209                        client->flags &= ~I2C_M_TEN;
210                return 0;
211        case I2C_FUNCS:
212                if (! arg) {
213#ifdef DEBUG
214                        printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
215#endif
216                        return -EINVAL;
217                }
218                if (verify_area(VERIFY_WRITE,(unsigned long *) arg,
219                                 sizeof(unsigned long))) {
220#ifdef DEBUG
221                        printk("i2c-dev.o: invalid argument pointer (%ld) "
222                               "in IOCTL I2C_SMBUS.\n", arg);
223#endif
224                        return -EINVAL;
225                }
226     
227                funcs = i2c_get_functionality(client->adapter);
228                copy_to_user((unsigned long *)arg,&funcs,sizeof(unsigned long));
229                return 0;
230        case I2C_SMBUS:
231                if (! arg) {
232#ifdef DEBUG
233                        printk("i2c-dev.o: NULL argument pointer in ioctl I2C_SMBUS.\n");
234#endif
235                        return -EINVAL;
236                }
237                if (verify_area(VERIFY_READ,(struct i2c_smbus_ioctl_data *) arg,
238                                sizeof(struct i2c_smbus_ioctl_data))) {
239#ifdef DEBUG
240                        printk("i2c-dev.o: invalid argument pointer (%ld) "
241                               "in IOCTL I2C_SMBUS.\n", arg);
242#endif
243                        return -EINVAL;
244                }
245                copy_from_user(&data_arg,(struct i2c_smbus_ioctl_data *) arg,
246                               sizeof(struct i2c_smbus_ioctl_data));
247                if ((data_arg.size != I2C_SMBUS_BYTE) && 
248                    (data_arg.size != I2C_SMBUS_QUICK) &&
249                    (data_arg.size != I2C_SMBUS_BYTE_DATA) && 
250                    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
251                    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
252                    (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
253#ifdef DEBUG
254                        printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
255                               data_arg.size);
256#endif
257                        return -EINVAL;
258                }
259                /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
260                   so the check is valid if size==I2C_SMBUS_QUICK too. */
261                if ((data_arg.read_write != I2C_SMBUS_READ) && 
262                    (data_arg.read_write != I2C_SMBUS_WRITE)) {
263#ifdef DEBUG
264                        printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
265                               data_arg.read_write);
266#endif
267                        return -EINVAL;
268                }
269
270                /* Note that command values are always valid! */
271
272                if ((data_arg.size == I2C_SMBUS_QUICK) ||
273                    ((data_arg.size == I2C_SMBUS_BYTE) && 
274                    (data_arg.read_write == I2C_SMBUS_WRITE)))
275                        /* These are special: we do not use data */
276                        return i2c_smbus_xfer(client->adapter, client->addr,
277                                              client->flags,
278                                              data_arg.read_write,
279                                              data_arg.command,
280                                              data_arg.size, NULL);
281
282                if (data_arg.data == NULL) {
283#ifdef DEBUG
284                        printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
285#endif
286                        return -EINVAL;
287                }
288
289                /* This seems unlogical but it is not: if the user wants to read a
290                   value, we must write that value to user memory! */
291                ver = ((data_arg.read_write == I2C_SMBUS_WRITE) && 
292                       (data_arg.size != I2C_SMBUS_PROC_CALL))?
293                      VERIFY_READ:VERIFY_WRITE;
294
295                if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
296                    (data_arg.size == I2C_SMBUS_BYTE))
297                        datasize = sizeof(data_arg.data->byte);
298                else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
299                         (data_arg.size == I2C_SMBUS_PROC_CALL))
300                        datasize = sizeof(data_arg.data->word);
301                else /* size == I2C_SMBUS_BLOCK_DATA */
302                        datasize = sizeof(data_arg.data->block);
303
304                if (verify_area(ver,data_arg.data,datasize)) {
305#ifdef DEBUG
306                        printk("i2c-dev.o: invalid pointer data (%p) in ioctl I2C_SMBUS.\n",
307                               data_arg.data);
308#endif
309                        return -EINVAL;
310                }
311
312                if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
313                    (data_arg.read_write == I2C_SMBUS_WRITE))
314                        copy_from_user(&temp,data_arg.data,datasize);
315                res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
316                      data_arg.read_write,
317                      data_arg.command,data_arg.size,&temp);
318                if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
319                   (data_arg.read_write == I2C_SMBUS_READ)))
320                        copy_to_user(data_arg.data,&temp,datasize);
321                return res;
322
323        default:
324                return i2c_control(client,cmd,arg);
325        }
326        return 0;
327}
328
329int i2cdev_open (struct inode *inode, struct file *file)
330{
331        unsigned int minor = MINOR(inode->i_rdev);
332        struct i2c_client *client;
333
334        if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
335#ifdef DEBUG
336                printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",
337                       minor);
338#endif
339                return -ENODEV;
340        }
341
342        /* Note that we here allocate a client for later use, but we will *not*
343           register this client! Yes, this is safe. No, it is not very clean. */
344        if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
345                return -ENOMEM;
346        memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
347        client->adapter = i2cdev_adaps[minor];
348        file->private_data = client;
349
350        if (i2cdev_adaps[minor]->inc_use)
351                i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
352        MOD_INC_USE_COUNT;
353
354#ifdef DEBUG
355        printk("i2c-dev.o: opened i2c-%d\n",minor);
356#endif
357        return 0;
358}
359
360static int i2cdev_release (struct inode *inode, struct file *file)
361{
362        unsigned int minor = MINOR(inode->i_rdev);
363        kfree(file->private_data);
364        file->private_data=NULL;
365#ifdef DEBUG
366        printk("i2c-dev.o: Closed: i2c-%d\n", minor);
367#endif
368        MOD_DEC_USE_COUNT;
369        if (i2cdev_adaps[minor]->dec_use)
370                i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
371        return 0;
372}
373
374int i2cdev_attach_adapter(struct i2c_adapter *adap)
375{
376        int i;
377
378        if ((i = i2c_adapter_id(adap)) < 0) {
379                printk("i2c-dev.o: Unknown adapter ?!?\n");
380                return -ENODEV;
381        }
382        if (i >= I2CDEV_ADAPS_MAX) {
383                printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
384                return -ENODEV;
385        }
386
387        if (! i2cdev_adaps[i]) {
388                i2cdev_adaps[i] = adap;
389                printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
390        } else {
391                i2cdev_adaps[i] = NULL;
392#ifdef DEBUG
393                printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
394#endif
395        }
396
397        return 0;
398}
399
400int i2cdev_detach_client(struct i2c_client *client)
401{
402        return 0;
403}
404
405static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
406                           void *arg)
407{
408        return -1;
409}
410
411int __init i2c_dev_init(void)
412{
413        int res;
414
415        printk("i2c-dev.o: i2c /dev entries driver module\n");
416
417        i2cdev_initialized = 0;
418        if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
419                printk("i2c-dev.o: unable to get major %d for i2c bus\n",
420                       I2C_MAJOR);
421                return -EIO;
422        }
423        i2cdev_initialized ++;
424
425        if ((res = i2c_add_driver(&i2cdev_driver))) {
426                printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
427                i2cdev_cleanup();
428                return res;
429        }
430        i2cdev_initialized ++;
431        return 0;
432}
433
434int i2cdev_cleanup(void)
435{
436        int res;
437
438        if (i2cdev_initialized >= 2) {
439                if ((res = i2c_del_driver(&i2cdev_driver))) {
440                        printk("i2c-dev.o: Driver deregistration failed, "
441                               "module not removed.\n");
442                        return res;
443                }
444        i2cdev_initialized ++;
445        }
446
447        if (i2cdev_initialized >= 1) {
448                if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
449                        printk("i2c-dev.o: unable to release major %d for i2c bus\n",
450                               I2C_MAJOR);
451                        return res;
452                }
453                i2cdev_initialized --;
454        }
455        return 0;
456}
457
458EXPORT_NO_SYMBOLS;
459
460#ifdef MODULE
461
462MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
463MODULE_DESCRIPTION("I2C /dev entries driver");
464
465int init_module(void)
466{
467        return i2c_dev_init();
468}
469
470int cleanup_module(void)
471{
472        return i2cdev_cleanup();
473}
474
475#endif /* def MODULE */
476
Note: See TracBrowser for help on using the browser.