i2c-dev.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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