home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lxapi32.zip / Linux / I2C / i2c-dev.c < prev    next >
C/C++ Source or Header  |  2002-04-26  |  15KB  |  560 lines

  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. /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
  27.  
  28. /* The devfs code is contributed by Philipp Matthias Hahn 
  29.    <pmhahn@titan.lahn.de> */
  30.  
  31. /* $Id: i2c-dev.c,v 1.2 2002/04/26 23:09:27 smilcke Exp $ */
  32.  
  33. #include <linux/config.h>
  34. #include <linux/kernel.h>
  35. #include <linux/module.h>
  36. #include <linux/fs.h>
  37. #include <linux/slab.h>
  38. #include <linux/version.h>
  39. #if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
  40. #include <linux/smp_lock.h>
  41. #endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
  42. #ifdef CONFIG_DEVFS_FS
  43. #include <linux/devfs_fs_kernel.h>
  44. #endif
  45.  
  46.  
  47. /* If you want debugging uncomment: */
  48. /* #define DEBUG */
  49.  
  50. #include <linux/init.h>
  51. #include <asm/uaccess.h>
  52.  
  53. #include <linux/i2c.h>
  54. #include <linux/i2c-dev.h>
  55.  
  56. #ifdef MODULE
  57. extern int init_module(void);
  58. extern int cleanup_module(void);
  59. #endif /* def MODULE */
  60.  
  61. /* struct file_operations changed too often in the 2.1 series for nice code */
  62.  
  63. #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
  64. static loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin);
  65. #endif
  66. static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
  67.                             loff_t *offset);
  68. static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
  69.                              loff_t *offset);
  70.  
  71. static int i2cdev_ioctl (struct inode *inode, struct file *file, 
  72.                          unsigned int cmd, unsigned long arg);
  73. static int i2cdev_open (struct inode *inode, struct file *file);
  74.  
  75. static int i2cdev_release (struct inode *inode, struct file *file);
  76.  
  77. static int i2cdev_attach_adapter(struct i2c_adapter *adap);
  78. static int i2cdev_detach_client(struct i2c_client *client);
  79. static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
  80.                            void *arg);
  81.  
  82. #ifdef MODULE
  83. static
  84. #else
  85. extern
  86. #endif
  87.        int __init i2c_dev_init(void);
  88. static int i2cdev_cleanup(void);
  89.  
  90. static struct file_operations i2cdev_fops = {
  91. #if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
  92.     owner:        THIS_MODULE,
  93. #endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
  94. #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
  95.     llseek:        i2cdev_lseek,
  96. #else
  97.     llseek:        no_llseek,
  98. #endif
  99.     read:        i2cdev_read,
  100.     write:        i2cdev_write,
  101.     ioctl:        i2cdev_ioctl,
  102.     open:        i2cdev_open,
  103.     release:    i2cdev_release,
  104. };
  105.  
  106. #define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
  107. static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
  108. #ifdef CONFIG_DEVFS_FS
  109. static devfs_handle_t devfs_i2c[I2CDEV_ADAPS_MAX];
  110. static devfs_handle_t devfs_handle = NULL;
  111. #endif
  112.  
  113. static struct i2c_driver i2cdev_driver = {
  114.     name:        "i2c-dev dummy driver",
  115.     id:        I2C_DRIVERID_I2CDEV,
  116.     flags:        I2C_DF_DUMMY,
  117.     attach_adapter:    i2cdev_attach_adapter,
  118.     detach_client:    i2cdev_detach_client,
  119.     command:    i2cdev_command,
  120. /*    inc_use:    NULL,
  121.     dec_use:    NULL, */
  122. };
  123.  
  124. static struct i2c_client i2cdev_client_template = {
  125.     name:        "I2C /dev entry",
  126.     id:        1,
  127.     flags:        0,
  128.     addr:        -1,
  129. /*    adapter:    NULL, */
  130.     driver:        &i2cdev_driver,
  131. /*    data:        NULL */
  132. };
  133.  
  134. static int i2cdev_initialized;
  135.  
  136. #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,9)
  137. /* Note that the lseek function is called llseek in 2.1 kernels. But things
  138.    are complicated enough as is. */
  139. loff_t i2cdev_lseek (struct file *file, loff_t offset, int origin)
  140. {
  141. #ifdef DEBUG
  142.     struct inode *inode = file->f_dentry->d_inode;
  143.     printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
  144.            MINOR(inode->i_rdev),(long) offset,origin);
  145. #endif /* DEBUG */
  146.     return -ESPIPE;
  147. }
  148. #endif
  149.  
  150. static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
  151.                             loff_t *offset)
  152. {
  153.     char *tmp;
  154.     int ret;
  155.  
  156. #ifdef DEBUG
  157.     struct inode *inode = file->f_dentry->d_inode;
  158. #endif /* DEBUG */
  159.  
  160.     struct i2c_client *client = (struct i2c_client *)file->private_data;
  161.  
  162.     /* copy user space data to kernel space. */
  163.     tmp = kmalloc(count,GFP_KERNEL);
  164.     if (tmp==NULL)
  165.         return -ENOMEM;
  166.  
  167. #ifdef DEBUG
  168.     printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
  169.            count);
  170. #endif
  171.  
  172.     ret = i2c_master_recv(client,tmp,count);
  173.     if (ret >= 0)
  174.         ret = copy_to_user(buf,tmp,count)?-EFAULT:ret;
  175.     kfree(tmp);
  176.     return ret;
  177. }
  178.  
  179. static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
  180.                              loff_t *offset)
  181. {
  182.     int ret;
  183.     char *tmp;
  184.     struct i2c_client *client = (struct i2c_client *)file->private_data;
  185.  
  186. #ifdef DEBUG
  187.     struct inode *inode = file->f_dentry->d_inode;
  188. #endif /* DEBUG */
  189.  
  190.     /* copy user space data to kernel space. */
  191.     tmp = kmalloc(count,GFP_KERNEL);
  192.     if (tmp==NULL)
  193.         return -ENOMEM;
  194.     if (copy_from_user(tmp,buf,count)) {
  195.         kfree(tmp);
  196.         return -EFAULT;
  197.     }
  198.  
  199. #ifdef DEBUG
  200.     printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
  201.            count);
  202. #endif
  203.     ret = i2c_master_send(client,tmp,count);
  204.     kfree(tmp);
  205.     return ret;
  206. }
  207.  
  208. int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 
  209.                   unsigned long arg)
  210. {
  211.     struct i2c_client *client = (struct i2c_client *)file->private_data;
  212.     struct i2c_rdwr_ioctl_data rdwr_arg;
  213.     struct i2c_smbus_ioctl_data data_arg;
  214.     union i2c_smbus_data temp;
  215.     struct i2c_msg *rdwr_pa;
  216.     int i,datasize,res;
  217.     unsigned long funcs;
  218.  
  219. #ifdef DEBUG
  220.     printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
  221.            MINOR(inode->i_rdev),cmd, arg);
  222. #endif /* DEBUG */
  223.  
  224.     switch ( cmd ) {
  225.     case I2C_SLAVE:
  226.     case I2C_SLAVE_FORCE:
  227.         if ((arg > 0x3ff) || 
  228.             (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
  229.             return -EINVAL;
  230.         if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
  231.             return -EBUSY;
  232.         client->addr = arg;
  233.         return 0;
  234.     case I2C_TENBIT:
  235.         if (arg)
  236.             client->flags |= I2C_M_TEN;
  237.         else
  238.             client->flags &= ~I2C_M_TEN;
  239.         return 0;
  240.     case I2C_FUNCS:
  241.         funcs = i2c_get_functionality(client->adapter);
  242.         return (copy_to_user((unsigned long *)arg,&funcs,
  243.                              sizeof(unsigned long)))?-EFAULT:0;
  244.  
  245.         case I2C_RDWR:
  246.         if (copy_from_user(&rdwr_arg, 
  247.                    (struct i2c_rdwr_ioctl_data *)arg, 
  248.                    sizeof(rdwr_arg)))
  249.             return -EFAULT;
  250.  
  251.         rdwr_pa = (struct i2c_msg *)
  252.             kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 
  253.             GFP_KERNEL);
  254.  
  255.         if (rdwr_pa == NULL) return -ENOMEM;
  256.  
  257.         res = 0;
  258.         for( i=0; i<rdwr_arg.nmsgs; i++ )
  259.         {
  260.                 if(copy_from_user(&(rdwr_pa[i]),
  261.                     &(rdwr_arg.msgs[i]),
  262.                     sizeof(rdwr_pa[i])))
  263.             {
  264.                     res = -EFAULT;
  265.                 break;
  266.             }
  267.             rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
  268.             if(rdwr_pa[i].buf == NULL)
  269.             {
  270.                 res = -ENOMEM;
  271.                 break;
  272.             }
  273.             if(copy_from_user(rdwr_pa[i].buf,
  274.                 rdwr_arg.msgs[i].buf,
  275.                 rdwr_pa[i].len))
  276.             {
  277.                     kfree(rdwr_pa[i].buf);
  278.                     res = -EFAULT;
  279.                 break;
  280.             }
  281.         }
  282.         if (!res) 
  283.         {
  284.             res = i2c_transfer(client->adapter,
  285.                 rdwr_pa,
  286.                 rdwr_arg.nmsgs);
  287.         }
  288.         while(i-- > 0)
  289.         {
  290.             if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD))
  291.             {
  292.                 if(copy_to_user(
  293.                     rdwr_arg.msgs[i].buf,
  294.                     rdwr_pa[i].buf,
  295.                     rdwr_pa[i].len))
  296.                 {
  297.                     res = -EFAULT;
  298.                 }
  299.             }
  300.             kfree(rdwr_pa[i].buf);
  301.         }
  302.         kfree(rdwr_pa);
  303.         return res;
  304.  
  305.     case I2C_SMBUS:
  306.         if (copy_from_user(&data_arg,
  307.                            (struct i2c_smbus_ioctl_data *) arg,
  308.                            sizeof(struct i2c_smbus_ioctl_data)))
  309.             return -EFAULT;
  310.         if ((data_arg.size != I2C_SMBUS_BYTE) && 
  311.             (data_arg.size != I2C_SMBUS_QUICK) &&
  312.             (data_arg.size != I2C_SMBUS_BYTE_DATA) && 
  313.             (data_arg.size != I2C_SMBUS_WORD_DATA) &&
  314.             (data_arg.size != I2C_SMBUS_PROC_CALL) &&
  315.             (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
  316.             (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
  317. #ifdef DEBUG
  318.             printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
  319.                    data_arg.size);
  320. #endif
  321.             return -EINVAL;
  322.         }
  323.         /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 
  324.            so the check is valid if size==I2C_SMBUS_QUICK too. */
  325.         if ((data_arg.read_write != I2C_SMBUS_READ) && 
  326.             (data_arg.read_write != I2C_SMBUS_WRITE)) {
  327. #ifdef DEBUG
  328.             printk("i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
  329.                    data_arg.read_write);
  330. #endif
  331.             return -EINVAL;
  332.         }
  333.  
  334.         /* Note that command values are always valid! */
  335.  
  336.         if ((data_arg.size == I2C_SMBUS_QUICK) ||
  337.             ((data_arg.size == I2C_SMBUS_BYTE) && 
  338.             (data_arg.read_write == I2C_SMBUS_WRITE)))
  339.             /* These are special: we do not use data */
  340.             return i2c_smbus_xfer(client->adapter, client->addr,
  341.                                   client->flags,
  342.                                   data_arg.read_write,
  343.                                   data_arg.command,
  344.                                   data_arg.size, NULL);
  345.  
  346.         if (data_arg.data == NULL) {
  347. #ifdef DEBUG
  348.             printk("i2c-dev.o: data is NULL pointer in ioctl I2C_SMBUS.\n");
  349. #endif
  350.             return -EINVAL;
  351.         }
  352.  
  353.         if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
  354.             (data_arg.size == I2C_SMBUS_BYTE))
  355.             datasize = sizeof(data_arg.data->byte);
  356.         else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
  357.                  (data_arg.size == I2C_SMBUS_PROC_CALL))
  358.             datasize = sizeof(data_arg.data->word);
  359.         else /* size == I2C_SMBUS_BLOCK_DATA */
  360.             datasize = sizeof(data_arg.data->block);
  361.  
  362.         if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
  363.             (data_arg.read_write == I2C_SMBUS_WRITE)) {
  364.             if (copy_from_user(&temp, data_arg.data, datasize))
  365.                 return -EFAULT;
  366.         }
  367.         res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
  368.               data_arg.read_write,
  369.               data_arg.command,data_arg.size,&temp);
  370.         if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
  371.                   (data_arg.read_write == I2C_SMBUS_READ))) {
  372.             if (copy_to_user(data_arg.data, &temp, datasize))
  373.                 return -EFAULT;
  374.         }
  375.         return res;
  376.  
  377.     default:
  378.         return i2c_control(client,cmd,arg);
  379.     }
  380.     return 0;
  381. }
  382.  
  383. int i2cdev_open (struct inode *inode, struct file *file)
  384. {
  385.     unsigned int minor = MINOR(inode->i_rdev);
  386.     struct i2c_client *client;
  387.  
  388.     if ((minor >= I2CDEV_ADAPS_MAX) || ! (i2cdev_adaps[minor])) {
  389. #ifdef DEBUG
  390.         printk("i2c-dev.o: Trying to open unattached adapter i2c-%d\n",
  391.                minor);
  392. #endif
  393.         return -ENODEV;
  394.     }
  395.  
  396.     /* Note that we here allocate a client for later use, but we will *not*
  397.        register this client! Yes, this is safe. No, it is not very clean. */
  398.     if(! (client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL)))
  399.         return -ENOMEM;
  400.     memcpy(client,&i2cdev_client_template,sizeof(struct i2c_client));
  401.     client->adapter = i2cdev_adaps[minor];
  402.     file->private_data = client;
  403.  
  404.     if (i2cdev_adaps[minor]->inc_use)
  405.         i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
  406. #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0)
  407.     MOD_INC_USE_COUNT;
  408. #endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */
  409.  
  410. #ifdef DEBUG
  411.     printk("i2c-dev.o: opened i2c-%d\n",minor);
  412. #endif
  413.     return 0;
  414. }
  415.  
  416. static int i2cdev_release (struct inode *inode, struct file *file)
  417. {
  418.     unsigned int minor = MINOR(inode->i_rdev);
  419.     kfree(file->private_data);
  420.     file->private_data=NULL;
  421. #ifdef DEBUG
  422.     printk("i2c-dev.o: Closed: i2c-%d\n", minor);
  423. #endif
  424. #if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0)
  425.     MOD_DEC_USE_COUNT;
  426. #endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */
  427.     if (i2cdev_adaps[minor]->dec_use)
  428.         i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
  429.     return 0;
  430. }
  431.  
  432. int i2cdev_attach_adapter(struct i2c_adapter *adap)
  433. {
  434.     int i;
  435.     char name[8];
  436.  
  437.     if ((i = i2c_adapter_id(adap)) < 0) {
  438.         printk("i2c-dev.o: Unknown adapter ?!?\n");
  439.         return -ENODEV;
  440.     }
  441.     if (i >= I2CDEV_ADAPS_MAX) {
  442.         printk("i2c-dev.o: Adapter number too large?!? (%d)\n",i);
  443.         return -ENODEV;
  444.     }
  445.  
  446.     sprintf (name, "%d", i);
  447.     if (! i2cdev_adaps[i]) {
  448.         i2cdev_adaps[i] = adap;
  449. #ifdef CONFIG_DEVFS_FS
  450.         devfs_i2c[i] = devfs_register (devfs_handle, name,
  451.             DEVFS_FL_DEFAULT, I2C_MAJOR, i,
  452.             S_IFCHR | S_IRUSR | S_IWUSR,
  453.             &i2cdev_fops, NULL);
  454. #endif
  455.         printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
  456.     } else {
  457.         /* This is actually a detach_adapter call! */
  458. #ifdef CONFIG_DEVFS_FS
  459.         devfs_unregister(devfs_i2c[i]);
  460. #endif
  461.         i2cdev_adaps[i] = NULL;
  462. #ifdef DEBUG
  463.         printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
  464. #endif
  465.     }
  466.  
  467.     return 0;
  468. }
  469.  
  470. int i2cdev_detach_client(struct i2c_client *client)
  471. {
  472.     return 0;
  473. }
  474.  
  475. static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
  476.                            void *arg)
  477. {
  478.     return -1;
  479. }
  480.  
  481. int __init i2c_dev_init(void)
  482. {
  483.     int res;
  484.  
  485.     printk("i2c-dev.o: i2c /dev entries driver module\n");
  486.  
  487.     i2cdev_initialized = 0;
  488. #ifdef CONFIG_DEVFS_FS
  489.     if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) {
  490. #else
  491.     if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
  492. #endif
  493.         printk("i2c-dev.o: unable to get major %d for i2c bus\n",
  494.                I2C_MAJOR);
  495.         return -EIO;
  496.     }
  497. #ifdef CONFIG_DEVFS_FS
  498.     devfs_handle = devfs_mk_dir(NULL, "i2c", NULL);
  499. #endif
  500.     i2cdev_initialized ++;
  501.  
  502.     if ((res = i2c_add_driver(&i2cdev_driver))) {
  503.         printk("i2c-dev.o: Driver registration failed, module not inserted.\n");
  504.         i2cdev_cleanup();
  505.         return res;
  506.     }
  507.     i2cdev_initialized ++;
  508.     return 0;
  509. }
  510.  
  511. int i2cdev_cleanup(void)
  512. {
  513.     int res;
  514.  
  515.     if (i2cdev_initialized >= 2) {
  516.         if ((res = i2c_del_driver(&i2cdev_driver))) {
  517.             printk("i2c-dev.o: Driver deregistration failed, "
  518.                    "module not removed.\n");
  519.             return res;
  520.         }
  521.     i2cdev_initialized --;
  522.     }
  523.  
  524.     if (i2cdev_initialized >= 1) {
  525. #ifdef CONFIG_DEVFS_FS
  526.         devfs_unregister(devfs_handle);
  527.         if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) {
  528. #else
  529.         if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
  530. #endif
  531.             printk("i2c-dev.o: unable to release major %d for i2c bus\n",
  532.                    I2C_MAJOR);
  533.             return res;
  534.         }
  535.         i2cdev_initialized --;
  536.     }
  537.     return 0;
  538. }
  539.  
  540. EXPORT_NO_SYMBOLS;
  541.  
  542. #ifdef MODULE
  543.  
  544. MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
  545. MODULE_DESCRIPTION("I2C /dev entries driver");
  546. MODULE_LICENSE("GPL");
  547.  
  548. int init_module(void)
  549. {
  550.     return i2c_dev_init();
  551. }
  552.  
  553. int cleanup_module(void)
  554. {
  555.     return i2cdev_cleanup();
  556. }
  557.  
  558. #endif /* def MODULE */
  559.  
  560.