Freescale mma845x三轴加速度传感器驱动分析

最近刚看完freescale mma8451的驱动,并且一直了驱动,自己也没怎么改代码,不过读了一下代码,还是有点体会的,下面我就来分析一下。

首先看下代码结构,有兴趣的可以从一下方式获得代码,git@github.com:zhangjie201412/WorkSpace.git ,最好是先发mail给我,

jay@jay:~/mygit$ tree
.
└── kernel
    ├── arch
    │   └── arm
    │       └── mach-mx5
    │           └── mx53_smd.c
    ├── drivers
    │   └── hwmon
    │       └── mma845x
    │           ├── Makefile
    │           ├── mma845x.c
    │           ├── mma845x.h
    │           ├── mma_char.c
    │           ├── mma_core.c
    │           ├── mma_input.c
    │           ├── mma_regs.h
    │           ├── mma_sysfs.c
    │           └── mma_sysfs.h
    └── include
        └── linux
            └── mma845x.h

其中一个头文件,然后是一个驱动包,里面内容蛮丰富的,还有就是要在板级文件里面注册platform的device端,我这里是基于iMX53的Android BSP

首先咱还是来找源头吧,找啊找,看名字就知道我们先要分析这个mma_core.c文件

  1. static int __init init_mma845x(void)  
  2. {  
  3.     /* 
  4.      * register driver  
  5.      */  
  6.     printk(KERN_INFO "add mma i2c driver\n");  
  7.     return i2c_add_driver(&i2c_mma845x_driver);  
  8. }  
  9.   
  10. /*! 
  11. * This function implements "exit" routine for driver 
  12. */  
  13. static void __exit exit_mma845x(void)  
  14. {  
  15.     printk(KERN_INFO "del mma i2c driver.\n");  
  16. #ifdef CONFIG_EARLYSUSPEND   
  17.     // Register early_suspend and late_wakeup handlers   
  18.     unregister_early_suspend(&mma845x_early_suspend_desc);  
  19. #endif   
  20.     return i2c_del_driver(&i2c_mma845x_driver);  
  21. }  
  22.   
  23. module_init(init_mma845x);  
  24. module_exit(exit_mma845x);  
static int __init init_mma845x(void)
{
    /*
     * register driver 
     */
    printk(KERN_INFO "add mma i2c driver\n");
    return i2c_add_driver(&i2c_mma845x_driver);
}

/*!
* This function implements "exit" routine for driver
*/
static void __exit exit_mma845x(void)
{
    printk(KERN_INFO "del mma i2c driver.\n");
#ifdef CONFIG_EARLYSUSPEND
    // Register early_suspend and late_wakeup handlers
    unregister_early_suspend(&mma845x_early_suspend_desc);
#endif
    return i2c_del_driver(&i2c_mma845x_driver);
}

module_init(init_mma845x);
module_exit(exit_mma845x);

这个初始化和卸载模块就不多说了,注册了i2c类型的驱动,接着去platform文件中找注册的device端,mx53_smd.c

  1. //+++add head file for g-sensor   
  2. #include <linux/mma845x.h>   
  3.   
  4. //++++add for mma driver   
  5. static struct mxc_mma845x_platform_data mma845x_data = {  
  6.     .gpio_pin_get = NULL,  
  7.     .gpio_pin_put = NULL,  
  8.     .int1 = gpio_to_irq(MX53_SMD_ACCL_INT1_IN), // ACCL_INT1 is gpio for MMA845X INT1   
  9.   
  10.     .int2 = gpio_to_irq(MX53_SMD_ACCL_INT2_IN), // ACCL_INT2 is gpio for MMA845X INT2   
  11. };  
  12. //-----add by Jay end   
  13.   
  14. static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {  
  15.     {  
  16.     .type = "mma845x",  
  17.     .addr = 0x1C,  
  18. //  .irq = gpio_to_irq(MX53_SMD_ACCL_INT1_IN),  //+++++add by Jay for g-sensor interrupt mode   
  19.     .platform_data = (void *)&mma845x_data, //+++add by Jay   
  20.      },  
  21.     {  
  22.     .type = "ov5642",  
  23.     .addr = 0x3C,  
  24.     .platform_data = (void *)&camera_data,  
  25.      },  
  26.     {  
  27.     .type = "mma7660",  
  28.     .addr = 0x4C,  
  29.      },  
  30. };  
//+++add head file for g-sensor
#include <linux/mma845x.h>

//++++add for mma driver
static struct mxc_mma845x_platform_data mma845x_data = {
	.gpio_pin_get = NULL,
	.gpio_pin_put = NULL,
	.int1 = gpio_to_irq(MX53_SMD_ACCL_INT1_IN), // ACCL_INT1 is gpio for MMA845X INT1

	.int2 = gpio_to_irq(MX53_SMD_ACCL_INT2_IN), // ACCL_INT2 is gpio for MMA845X INT2
};
//-----add by Jay end

static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
	{
	.type = "mma845x",
	.addr = 0x1C,
//	.irq = gpio_to_irq(MX53_SMD_ACCL_INT1_IN),	//+++++add by Jay for g-sensor interrupt mode
	.platform_data = (void *)&mma845x_data,	//+++add by Jay
	 },
	{
	.type = "ov5642",
	.addr = 0x3C,
	.platform_data = (void *)&camera_data,
	 },
	{
	.type = "mma7660",
	.addr = 0x4C,
	 },
};

这里,填充了mma845x驱动的一些platform_data

然后是注册,

  1. i2c_register_board_info(0, mxc_i2c0_board_info,  
  2.             ARRAY_SIZE(mxc_i2c0_board_info));  
	i2c_register_board_info(0, mxc_i2c0_board_info,
				ARRAY_SIZE(mxc_i2c0_board_info));

这个函数会把i2c0上的所有驱动都挂到platform driver的device上去,进行匹配,这里我要提示的一点是,这里的2根GPIO 中断引脚,我们要设置为input

  1. //+++++add by Jay for g-sensor interrupt mode to get data   
  2. gpio_request(MX53_SMD_ACCL_INT1_IN, "gsensor-irq");  
  3. msleep(5);  
  4. gpio_direction_input(MX53_SMD_ACCL_INT1_IN);  
  5. //-----end add  
	//+++++add by Jay for g-sensor interrupt mode to get data
	gpio_request(MX53_SMD_ACCL_INT1_IN, "gsensor-irq");
	msleep(5);
	gpio_direction_input(MX53_SMD_ACCL_INT1_IN);
	//-----end add

接下来分析mma_core.c中的probe函数,这里是最终要的一个函数了

  1. /*! 
  2. * This function implements probe routine for driver 
  3. * client     : pointer to i2c client 
  4. * id         : i2c device id 
  5. * return 0         : Success 
  6. * return -ENOMEM   : Memory allocation for pDev failed 
  7. * return -ENODEV   : Platform data not found 
  8. */  
  9. static int mma845x_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  10. {  
  11.     int ret = 0,  
  12.     i = 0;  
  13.     struct ChipInfo_t *pChip = NULL;  
  14.     struct mxc_mma_device_t *pDev = NULL;  
  15.     int             mask = 0;  
  16.      
  17.     plat_data =  
  18.     (struct mxc_mma845x_platform_data *) client->dev.platform_data;  
  19.     if (plat_data == NULL) {  
  20.     dev_err(&client->dev, "lack of platform data!\n");  
  21.     return -ENODEV;  
  22.     }  
  23.   
  24.     pDev = kzalloc(sizeof(struct mxc_mma_device_t), GFP_KERNEL);  
  25.     if (!pDev) {  
  26.     pDev = NULL;  
  27.     return -ENOMEM;  
  28.     }  
  29.   
  30.      printk(KERN_INFO "\r\nProbing Module: %s %s\r\n", MODULE_NAME, DRIVER_VERSION);  
  31.      printk(KERN_INFO "Freescale Android 2.3 Release: %s\r\n", ANDROID_RELEASE);   
  32.      printk(KERN_INFO "Build Date: %s [%s]\r\n", __DATE__, __TIME__);  
  33.       
  34.     i2c_set_clientdata(client, pDev);  
  35.   
  36.     /* 
  37.      * bind the right device to the driver  
  38.      */  
  39.     ret = IdentifyChipset(client);  
  40.     if (ret < 0) {  
  41.      printk(KERN_INFO "%s:: Unable to identify device.\r\n", __func__);  
  42.     return -EIO;  
  43.     }  
  44.   
  45.     /* 
  46.      * Associate chip layer  
  47.      */  
  48.     for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {  
  49.     if (ChipTable[i]->ChipId == ret) {  
  50.         pChip = ChipTable[i];  
  51.         pChip->ChipId = ret;  
  52.         pChip->client = client;  
  53.         pChip->ChipType = ChipType;  
  54.         break;  
  55.     }  
  56.     }  
  57.   
  58.     if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {  
  59.      printk(KERN_INFO "Chipset not supported by MMA driver\r\n");  
  60.     return -ENOMEM;  
  61.     }  
  62.   
  63.     gpChip = pChip;  
  64.     gpDev = pDev;  
  65.     SetDefaultVal(pChip);  
  66.   
  67.     /* 
  68.      * Inialize default event codes  
  69.      */  
  70.     pDev->fm_event_type = 0x25;  
  71.     pDev->ornt_event_type = 0x26;  
  72.     pDev->trans_event_type = 0x27;  
  73.     pDev->event_type_single = 0x28;  
  74.     pDev->event_type_double = 0x29;  
  75.   
  76.     pDev->aflag = 1;  
  77.     /* 
  78.      * Initialize chipset  
  79.      */  
  80.     pChip->Init(pChip);  
  81.   
  82.     pDev->pChip = pChip;  
  83.     pDev->version = 1;  
  84.   
  85.     /* 
  86.      * configure gpio as input for interrupt monitor  
  87.      */  
  88.   
  89.     if(plat_data->gpio_pin_get)  
  90.         plat_data->gpio_pin_get();  
  91.   
  92.     /* 
  93.      * Register character device  
  94.      */  
  95.     pDev->major = register_chrdev(0, "mma", &mma_fops);  
  96.     if (ret < 0) {  
  97.      printk(KERN_INFO "%s:: Unable to register device\r\n", __func__);  
  98.     goto error_disable_power;  
  99.     }  
  100.   
  101.     strcpy(pDev->devname, "mma");  
  102.     printk(KERN_INFO "%s:: Registered char dev \"%s\" @ %d\r\n", __func__,  
  103.     pDev->devname, pDev->major);  
  104.   
  105.     /* 
  106.      * Initialize input layer  
  107.      */  
  108.     InitializeInputInterface(pDev);  
  109.   
  110.     /* 
  111.      * Create sysfs entries  
  112.      */  
  113.     InitializeSysfs( (struct i2c_client *)client);  
  114.   
  115.     /* 
  116.      * Initialize semaphore for interrupt 
  117.      */  
  118.     sema_init(&chip_ready, 0);  
  119.   
  120.     setup_timer(&stall_timer, stall_timer_fn, 0);  
  121.     hIstThread = kthread_run(IntServiceThread, pDev, "mxc845x_ist");  
  122.     if (IS_ERR(hIstThread)) {  
  123.      printk(KERN_INFO "Error creating mxc845x ist.\n");  
  124.     goto error_free_irq1;  
  125.     }  
  126.     if (plat_data->int1 > 0)  {     
  127.         set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);  
  128.   
  129.         ret = request_irq(plat_data->int1, mma845x_interrupt,  
  130.                   IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  131.   
  132.         if (ret) {  
  133.         dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  134.             plat_data->int1, ret);  
  135.         goto error_disable_power;  
  136.         }  
  137.     }  
  138.     else {  
  139.         gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);  
  140.         poll_mode = 1;  
  141.     }  
  142.     if (plat_data->int2 > 0){  
  143.          printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,  
  144.        plat_data->int2);  
  145.   
  146.      set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);  
  147.      ret = request_irq(plat_data->int2, mma845x_interrupt,  
  148.               IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  149.      if (ret) {  
  150.         dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  151.         plat_data->int2, ret);  
  152.         goto error_free_irq1;  
  153.      }  
  154.    }  
  155. #ifdef CONFIG_EARLYSUSPEND   
  156.     register_early_suspend(&mma845x_early_suspend_desc);  
  157. #endif  
/*!
* This function implements probe routine for driver
* client     : pointer to i2c client
* id         : i2c device id
* return 0         : Success
* return -ENOMEM   : Memory allocation for pDev failed
* return -ENODEV   : Platform data not found
*/
static int mma845x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0,
    i = 0;
    struct ChipInfo_t *pChip = NULL;
    struct mxc_mma_device_t *pDev = NULL;
    int             mask = 0;
   
    plat_data =
	(struct mxc_mma845x_platform_data *) client->dev.platform_data;
    if (plat_data == NULL) {
	dev_err(&client->dev, "lack of platform data!\n");
	return -ENODEV;
    }

    pDev = kzalloc(sizeof(struct mxc_mma_device_t), GFP_KERNEL);
    if (!pDev) {
	pDev = NULL;
	return -ENOMEM;
    }

     printk(KERN_INFO "\r\nProbing Module: %s %s\r\n", MODULE_NAME, DRIVER_VERSION);
     printk(KERN_INFO "Freescale Android 2.3 Release: %s\r\n", ANDROID_RELEASE); 
     printk(KERN_INFO "Build Date: %s [%s]\r\n", __DATE__, __TIME__);
    
    i2c_set_clientdata(client, pDev);

    /*
     * bind the right device to the driver 
     */
    ret = IdentifyChipset(client);
    if (ret < 0) {
	 printk(KERN_INFO "%s:: Unable to identify device.\r\n", __func__);
	return -EIO;
    }

    /*
     * Associate chip layer 
     */
    for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {
	if (ChipTable[i]->ChipId == ret) {
	    pChip = ChipTable[i];
	    pChip->ChipId = ret;
	    pChip->client = client;
	    pChip->ChipType = ChipType;
	    break;
	}
    }

    if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {
	 printk(KERN_INFO "Chipset not supported by MMA driver\r\n");
	return -ENOMEM;
    }

    gpChip = pChip;
    gpDev = pDev;
    SetDefaultVal(pChip);

    /*
     * Inialize default event codes 
     */
    pDev->fm_event_type = 0x25;
    pDev->ornt_event_type = 0x26;
    pDev->trans_event_type = 0x27;
    pDev->event_type_single = 0x28;
    pDev->event_type_double = 0x29;

    pDev->aflag = 1;
    /*
     * Initialize chipset 
     */
    pChip->Init(pChip);

    pDev->pChip = pChip;
    pDev->version = 1;

    /*
     * configure gpio as input for interrupt monitor 
     */

    if(plat_data->gpio_pin_get)
	    plat_data->gpio_pin_get();

    /*
     * Register character device 
     */
    pDev->major = register_chrdev(0, "mma", &mma_fops);
    if (ret < 0) {
	 printk(KERN_INFO "%s:: Unable to register device\r\n", __func__);
	goto error_disable_power;
    }

    strcpy(pDev->devname, "mma");
    printk(KERN_INFO "%s:: Registered char dev \"%s\" @ %d\r\n", __func__,
	pDev->devname, pDev->major);

    /*
     * Initialize input layer 
     */
    InitializeInputInterface(pDev);

    /*
     * Create sysfs entries 
     */
    InitializeSysfs( (struct i2c_client *)client);

    /*
     * Initialize semaphore for interrupt
     */
    sema_init(&chip_ready, 0);

    setup_timer(&stall_timer, stall_timer_fn, 0);
    hIstThread = kthread_run(IntServiceThread, pDev, "mxc845x_ist");
    if (IS_ERR(hIstThread)) {
	 printk(KERN_INFO "Error creating mxc845x ist.\n");
	goto error_free_irq1;
    }
    if (plat_data->int1 > 0)  {   
	    set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);

	    ret = request_irq(plat_data->int1, mma845x_interrupt,
			      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);

	    if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
			plat_data->int1, ret);
		goto error_disable_power;
	    }
    }
    else {
		gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);
		poll_mode = 1;
	}
    if (plat_data->int2 > 0){
    	 printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,
	   plat_data->int2);

   	 set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);
   	 ret = request_irq(plat_data->int2, mma845x_interrupt,
		      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);
     if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
		plat_data->int2, ret);
		goto error_free_irq1;
     }
   }
#ifdef CONFIG_EARLYSUSPEND
    register_early_suspend(&mma845x_early_suspend_desc);
#endif

注释也写的蛮清楚的但是咱还是一起来看一下

  1.    plat_data =  
  2. (struct mxc_mma845x_platform_data *) client->dev.platform_data;  
  3.    if (plat_data == NULL) {  
  4. dev_err(&client->dev, "lack of platform data!\n");  
  5. return -ENODEV;  
  6.    }  
    plat_data =
	(struct mxc_mma845x_platform_data *) client->dev.platform_data;
    if (plat_data == NULL) {
	dev_err(&client->dev, "lack of platform data!\n");
	return -ENODEV;
    }

这里是由probe函数传进来的client参数来得到platform_data,就是我们在板级文件中填充的那些个结构体,我觉得Linux设计的这个platform架构的驱动很好,他可以很好的把驱动和设备隔离开来,虽然有的时候还是会联系到一起,但是对于可移植性更强了,因为,驱动只是对设备的统一管理,而platform device端只需要配置cpu的gpio跟deivce的连接情况,还有一些soc中继承的功能的配置以及注册。

  1.    pDev = kzalloc(sizeof(struct mxc_mma_device_t), GFP_KERNEL);  
  2.    if (!pDev) {  
  3. pDev = NULL;  
  4. return -ENOMEM;  
  5.    }  
  6.   
  7.     printk(KERN_INFO "\r\nProbing Module: %s %s\r\n", MODULE_NAME, DRIVER_VERSION);  
  8.     printk(KERN_INFO "Freescale Android 2.3 Release: %s\r\n", ANDROID_RELEASE);   
  9.     printk(KERN_INFO "Build Date: %s [%s]\r\n", __DATE__, __TIME__);  
    pDev = kzalloc(sizeof(struct mxc_mma_device_t), GFP_KERNEL);
    if (!pDev) {
	pDev = NULL;
	return -ENOMEM;
    }

     printk(KERN_INFO "\r\nProbing Module: %s %s\r\n", MODULE_NAME, DRIVER_VERSION);
     printk(KERN_INFO "Freescale Android 2.3 Release: %s\r\n", ANDROID_RELEASE); 
     printk(KERN_INFO "Build Date: %s [%s]\r\n", __DATE__, __TIME__);

接着这里是给我们驱动中定义的mxc_mma_device_t结构体分配内存,然后是一些kernel info的打印没什么好说了。

还是先来看一下这个结构体吧,

  1. /*sensor platform data structure for mma8451/mma8452/mma8453*/  
  2. struct mxc_mma845x_platform_data {  
  3.     void (*gpio_pin_get) (void);  
  4.     void (*gpio_pin_put) (void);  
  5.     int int1;  
  6.     int int2;  
  7. };  
/*sensor platform data structure for mma8451/mma8452/mma8453*/
struct mxc_mma845x_platform_data {
	void (*gpio_pin_get) (void);
	void (*gpio_pin_put) (void);
	int int1;
	int int2;
};

这个结构体比较简单,定义了2个中断号,还有中断GPIO的get和put,我们这边对这2个函数没有实现,我猜想get函数是对中断GPIO的配置,put是对中断GPIO的free,拙见而已,

  1.  i2c_set_clientdata(client, pDev);  
  2.   
  3.   /* 
  4.    * bind the right device to the driver  
  5.    */  
  6.   ret = IdentifyChipset(client);  
  7.   if (ret < 0) {  
  8. printk(KERN_INFO "%s:: Unable to identify device.\r\n", __func__);  
  9. eturn -EIO;  
  10.   }  
  11.   
  12.   /* 
  13.    * Associate chip layer  
  14.    */  
  15.   for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {  
  16. f (ChipTable[i]->ChipId == ret) {  
  17.    pChip = ChipTable[i];  
  18.    pChip->ChipId = ret;  
  19.    pChip->client = client;  
  20.    pChip->ChipType = ChipType;  
  21.    break;  
  22.   
  23.   }  
  24.   
  25.   if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {  
  26. printk(KERN_INFO "Chipset not supported by MMA driver\r\n");  
  27. eturn -ENOMEM;  
  28.   }  
  29.   
  30.   gpChip = pChip;  
  31.   gpDev = pDev;  
  32.   SetDefaultVal(pChip);  
  33.   
  34.   /* 
  35.    * Inialize default event codes  
  36.    */  
  37.   pDev->fm_event_type = 0x25;  
  38.   pDev->ornt_event_type = 0x26;  
  39.   pDev->trans_event_type = 0x27;  
  40.   pDev->event_type_single = 0x28;  
  41.   pDev->event_type_double = 0x29;  
  42.   
  43.   pDev->aflag = 1;  
  44.   /* 
  45.    * Initialize chipset  
  46.    */  
  47.   pChip->Init(pChip);  
  48.   
  49.   pDev->pChip = pChip;  
  50.   pDev->version = 1;  
  51.   
  52.   /* 
  53.    * configure gpio as input for interrupt monitor  
  54.    */  
  55.   
  56.   if(plat_data->gpio_pin_get)  
  57.    plat_data->gpio_pin_get();  
  58.   
  59.   /* 
  60.    * Register character device  
  61.    */  
   i2c_set_clientdata(client, pDev);

    /*
     * bind the right device to the driver 
     */
    ret = IdentifyChipset(client);
    if (ret < 0) {
	 printk(KERN_INFO "%s:: Unable to identify device.\r\n", __func__);
	return -EIO;
    }

    /*
     * Associate chip layer 
     */
    for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {
	if (ChipTable[i]->ChipId == ret) {
	    pChip = ChipTable[i];
	    pChip->ChipId = ret;
	    pChip->client = client;
	    pChip->ChipType = ChipType;
	    break;
	}
    }

    if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {
	 printk(KERN_INFO "Chipset not supported by MMA driver\r\n");
	return -ENOMEM;
    }

    gpChip = pChip;
    gpDev = pDev;
    SetDefaultVal(pChip);

    /*
     * Inialize default event codes 
     */
    pDev->fm_event_type = 0x25;
    pDev->ornt_event_type = 0x26;
    pDev->trans_event_type = 0x27;
    pDev->event_type_single = 0x28;
    pDev->event_type_double = 0x29;

    pDev->aflag = 1;
    /*
     * Initialize chipset 
     */
    pChip->Init(pChip);

    pDev->pChip = pChip;
    pDev->version = 1;

    /*
     * configure gpio as input for interrupt monitor 
     */

    if(plat_data->gpio_pin_get)
	    plat_data->gpio_pin_get();

    /*
     * Register character device 
     */

这里首先是对mma_845x器件身份的识别,来看下IdentifyChipset函数

  1. /*! 
  2. * This function Identify the chip connected on bus and associate client driver for the chipset  
  3. * client   : i2c_client pointer for i2c bus attached to device 
  4. * return chip_id : Chip id of identified device 
  5. * return -1      : Device not identified 
  6. */  
  7. static int IdentifyChipset(struct i2c_client *client)  
  8. {  
  9.     int             retVal = 0;  
  10.     int             ChipIdentified = 0;  
  11.   
  12.     retVal = i2c_smbus_read_byte_data(client, REG(WHO_AM_I));  
  13.     switch (retVal) {  
  14.     case ID_MMA8451:  
  15.     {  
  16.         printk("%s:: Found MMA8451 chipset with chip ID 0x%02x\r\n",  
  17.            __func__, retVal);  
  18.         ChipIdentified = 1;  
  19.     }  
  20.     break;  
  21.   
  22.     case ID_MMA8452:  
  23.     {  
  24.         printk("%s:: Found MMA8452 chipset with chip ID 0x%02x\r\n",  
  25.            __func__, retVal);  
  26.         ChipIdentified = 1;  
  27.     }  
  28.     break;  
  29.   
  30.     case ID_MMA8453:  
  31.     {  
  32.         printk("%s:: Found MMA8453 chipset with chip ID 0x%02x\r\n",  
  33.            __func__, retVal);  
  34.         ChipIdentified = 1;  
  35.     }  
  36.     break;  
  37.   
  38.     default:  
  39.     {  
  40.         printk("%s:: Not a valid MMA845X chipset. Chip ID 0x%02x\r\n",  
  41.            __func__, retVal);  
  42.         ChipIdentified = 0;  
  43.     }  
  44.     break;  
/*!
* This function Identify the chip connected on bus and associate client driver for the chipset 
* client   : i2c_client pointer for i2c bus attached to device
* return chip_id : Chip id of identified device
* return -1      : Device not identified
*/
static int IdentifyChipset(struct i2c_client *client)
{
    int             retVal = 0;
    int             ChipIdentified = 0;

    retVal = i2c_smbus_read_byte_data(client, REG(WHO_AM_I));
    switch (retVal) {
    case ID_MMA8451:
	{
	    printk("%s:: Found MMA8451 chipset with chip ID 0x%02x\r\n",
		   __func__, retVal);
	    ChipIdentified = 1;
	}
	break;

    case ID_MMA8452:
	{
	    printk("%s:: Found MMA8452 chipset with chip ID 0x%02x\r\n",
		   __func__, retVal);
	    ChipIdentified = 1;
	}
	break;

    case ID_MMA8453:
	{
	    printk("%s:: Found MMA8453 chipset with chip ID 0x%02x\r\n",
		   __func__, retVal);
	    ChipIdentified = 1;
	}
	break;

    default:
	{
	    printk("%s:: Not a valid MMA845X chipset. Chip ID 0x%02x\r\n",
		   __func__, retVal);
	    ChipIdentified = 0;
	}
	break;

读i2c bus上面mma传感器的WHO_AM_I 寄存器,来判断连上的是哪个device

  1.    /* 
  2.     * Associate chip layer  
  3.     */  
  4.    for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {  
  5. if (ChipTable[i]->ChipId == ret) {  
  6.     pChip = ChipTable[i];  
  7.     pChip->ChipId = ret;  
  8.     pChip->client = client;  
  9.     pChip->ChipType = ChipType;  
  10.     break;  
  11. }  
  12.    }  
  13.   
  14.    if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {  
  15.  printk(KERN_INFO "Chipset not supported by MMA driver\r\n");  
  16. return -ENOMEM;  
  17.    }  
  18.   
  19.    gpChip = pChip;  
  20.    gpDev = pDev;  
  21.    SetDefaultVal(pChip);  
    /*
     * Associate chip layer 
     */
    for (i = 0; i < sizeof(ChipTable) / sizeof(ChipTable[0]); i++) {
	if (ChipTable[i]->ChipId == ret) {
	    pChip = ChipTable[i];
	    pChip->ChipId = ret;
	    pChip->client = client;
	    pChip->ChipType = ChipType;
	    break;
	}
    }

    if (i >= (sizeof(ChipTable) / sizeof(ChipTable[0]))) {
	 printk(KERN_INFO "Chipset not supported by MMA driver\r\n");
	return -ENOMEM;
    }

    gpChip = pChip;
    gpDev = pDev;
    SetDefaultVal(pChip);

这里首先是对芯片层的一些赋值,找到这里我们注册的是哪款芯片,然后把i2c client,chip id, chiptype等信息赋值给这里的局部变量,然后再把局部变量赋值给全局的几个指针,然后再试对芯片寄存器设置一些默认值。

  1. /* 
  2.  * Inialize default event codes  
  3.  */  
  4. pDev->fm_event_type = 0x25;  
  5. pDev->ornt_event_type = 0x26;  
  6. pDev->trans_event_type = 0x27;  
  7. pDev->event_type_single = 0x28;  
  8. pDev->event_type_double = 0x29;  
  9.   
  10. pDev->aflag = 1;  
  11. /* 
  12.  * Initialize chipset  
  13.  */  
  14. pChip->Init(pChip);  
  15.   
  16. pDev->pChip = pChip;  
  17. pDev->version = 1;  
    /*
     * Inialize default event codes 
     */
    pDev->fm_event_type = 0x25;
    pDev->ornt_event_type = 0x26;
    pDev->trans_event_type = 0x27;
    pDev->event_type_single = 0x28;
    pDev->event_type_double = 0x29;

    pDev->aflag = 1;
    /*
     * Initialize chipset 
     */
    pChip->Init(pChip);

    pDev->pChip = pChip;
    pDev->version = 1;

然后是初始化芯片的事件类型,这里这块芯片分很多事件类型,有撞击事件,横竖切换事件等,接下来如果pChip结构体中Init成员函数非空的话就执行这个函数。

  1.    /* 
  2.     * Register character device  
  3.     */  
  4.    pDev->major = register_chrdev(0, "mma", &mma_fops);  
  5.    if (ret < 0) {  
  6.  printk(KERN_INFO "%s:: Unable to register device\r\n", __func__);  
  7. goto error_disable_power;  
  8.    }  
  9.   
  10.    strcpy(pDev->devname, "mma");  
  11.    printk(KERN_INFO "%s:: Registered char dev \"%s\" @ %d\r\n", __func__,  
  12. pDev->devname, pDev->major);  
    /*
     * Register character device 
     */
    pDev->major = register_chrdev(0, "mma", &mma_fops);
    if (ret < 0) {
	 printk(KERN_INFO "%s:: Unable to register device\r\n", __func__);
	goto error_disable_power;
    }

    strcpy(pDev->devname, "mma");
    printk(KERN_INFO "%s:: Registered char dev \"%s\" @ %d\r\n", __func__,
	pDev->devname, pDev->major);

接下来注册了一个字符类型的驱动,咱来看看这个驱动是干啥用的,最主要的还是看mma_fops这个文件操作结构体中实现了哪些个东西,mma_char.c

  1. /*  
  2.  * This structure is the file operations structure, which specifies what 
  3.  * callbacks functions the kernel should call when a user mode process 
  4.  * attempts to perform these operations on the device. 
  5.  */  
  6. const struct file_operations mma_fops = {  
  7.     .owner   = THIS_MODULE,  
  8.     .open    = mma_open,  
  9.     .ioctl   = mma_ioctl,  
  10.     .release = mma_release,  
  11.     .read    = mma_read,  
  12. };  
/* 
 * This structure is the file operations structure, which specifies what
 * callbacks functions the kernel should call when a user mode process
 * attempts to perform these operations on the device.
 */
const struct file_operations mma_fops = {
	.owner	 = THIS_MODULE,
	.open	 = mma_open,
	.ioctl 	 = mma_ioctl,
	.release = mma_release,
	.read 	 = mma_read,
};

这里有打开关闭,读,还有ioctl功能,

  1. /*! 
  2. * Open call for accelerometer char driver.  
  3. * inode : Pointer to the node to be opened. 
  4. * file  : Pointer to file structure. 
  5. * return 0    : After successful opening.   
  6. */  
  7.   
  8. static int mma_open(struct inode * inode, struct file * file)  
  9. {  
  10.     pContext_t p = file->private_data;  
  11.   
  12.     if (!p) {  
  13.         p = kmalloc(sizeof(*p), GFP_KERNEL);  
  14.         if (!p)  
  15.             return -ENOMEM;  
  16.   
  17.         p->threshold = 5;  
  18.         p->read_pos = 0;  
  19.         sema_init(&p->sem, 1);  
  20.         file->private_data = p;  
  21.     }  
  22.     return 0;     
  23. }  
/*!
* Open call for accelerometer char driver. 
* inode : Pointer to the node to be opened.
* file  : Pointer to file structure.
* return 0    : After successful opening.  
*/

static int mma_open(struct inode * inode, struct file * file)
{
	pContext_t p = file->private_data;

	if (!p) {
		p = kmalloc(sizeof(*p), GFP_KERNEL);
		if (!p)
			return -ENOMEM;

		p->threshold = 5;
		p->read_pos = 0;
		sema_init(&p->sem, 1);
		file->private_data = p;
	}
	return 0;	
}

首先是open函数,这里还要先看下pContext_t这个结构体

  1. typedef struct  
  2. {  
  3.     struct semaphore sem;  
  4.     int threshold;  
  5.     int read_pos;  
  6. }Context_t, *pContext_t;  
typedef struct
{
	struct semaphore sem;
	int threshold;
	int read_pos;
}Context_t, *pContext_t;

里面有3个成员变量,乍看之下还不清楚是用来干嘛的,先不管,接着往下看就明白了,回到open函数中,首先把文件结构体中的数据给这个结构体,然后判断,这里的意思应该是如果open函数被打开了一次那么就会执行if中的代码,如果已经被打开了,那么就直接返回零,if语句中也就是多结构体的初始化,还有初始化了一个信号量,然后把p指针传给file->private,代表已经被打开了,非空。

  1. /*! 
  2. * Release call for accelerometer char driver.  
  3. * inode : Pointer to the node to be opened. 
  4. * file  : Pointer to file structure. 
  5. * return 0    : After successful release of resources.   
  6. */  
  7.   
  8. static int mma_release(struct inode *inode, struct file *file)  
  9. {  
  10.     pContext_t p = file->private_data;  
  11.   
  12.     if (p)   
  13.     {  
  14.         mutex_destroy(&p->lock);  
  15.         kfree(p);  
  16.         p = NULL;  
  17.     }  
  18.   
  19.     return 0;  
  20. }  
/*!
* Release call for accelerometer char driver. 
* inode : Pointer to the node to be opened.
* file  : Pointer to file structure.
* return 0    : After successful release of resources.  
*/

static int mma_release(struct inode *inode, struct file *file)
{
	pContext_t p = file->private_data;

	if (p) 
	{
		mutex_destroy(&p->lock);
		kfree(p);
		p = NULL;
	}

	return 0;
}

release中的代码就不多说了,跟open函数正好相反。

然后是比较重要的ioctl和read function

  1. /*! 
  2. * read call for accelerometer char driver.  
  3. * inode    : Pointer to the node to be opened. 
  4. * file     : Pointer to file structure. 
  5. * command  : contains command for register. 
  6. * arg      : contains data required to apply settings specified in cmd. 
  7. * return  0      : For successful     
  8. */  
  9.   
  10. static int mma_ioctl(struct inode *inode, struct file *filp,  
  11.           unsigned int command, unsigned long arg)  
  12. {  
  13.     pContext_t dev = filp->private_data;  
  14.     u32 threshold = 0;  
  15.       
  16.     switch(command)  
  17.     {  
  18.         case MMA_GET_THRESHOLD:  
  19.             {  
  20.   
  21.                 if (copy_to_user(&arg, &(dev->threshold), sizeof(u32)))  
  22.                     {  
  23.                     printk("ioctl, copy to user failed\n");  
  24.                     return -EFAULT;  
  25.                 }  
  26.             }  
  27.             break;  
  28.   
  29.         case MMA_GET_THRESHOLD_VALUE:  
  30.             {  
  31.   
  32.                 return dev->threshold;  
  33.             }  
  34.             break;  
  35.   
  36.         case MMA_SET_THRESHOLD:  
  37.             {  
  38.                 if (copy_from_user(&threshold, &arg, sizeof(u32)))  
  39.                     {  
  40.                     return -EFAULT;  
  41.                 }  
  42.                 if(threshold <= 0)  
  43.                 {  
  44.                     return -EINVAL;  
  45.                 }  
  46.                   
  47.                 dev->threshold = threshold;  
  48.             }  
  49.             break;  
  50.   
  51.         case MMA_SET_THRESHOLD_VALUE:  
  52.             {  
  53.                 threshold = arg;  
  54.                 if(threshold <= 0)  
  55.                 {  
  56.                     printk("Invalid value [0x%x]\r\n", threshold);  
  57.                     return -EINVAL;  
  58.                 }  
  59.                 dev->threshold = threshold;  
  60.             }  
  61.             break;  
  62.   
  63.         case MMA_GET_ACCLEROMETER_FLAG:  
  64.             {  
  65.   
  66.                 return GetAcclerometerFlag();  
  67.             }  
  68.             break;  
  69.   
  70.         case MMA_SET_ACCLEROMETER_FLAG:  
  71.             {  
  72.                 int AcclFlag = arg;  
  73.   
  74.                 return SetAcclerometerFlag(AcclFlag);  
  75.             }  
  76.             break;  
  77.   
  78.         default:  
  79.             {  
  80.                 printk("%s:: Invalid IOCTL [0x%x]\r\n", __func__, command);  
  81.             }  
  82.     }  
  83.     return 0;  
  84. }  
/*!
* read call for accelerometer char driver. 
* inode    : Pointer to the node to be opened.
* file     : Pointer to file structure.
* command  : contains command for register.
* arg      : contains data required to apply settings specified in cmd.
* return  0      : For successful	 
*/

static int mma_ioctl(struct inode *inode, struct file *filp,
		  unsigned int command, unsigned long arg)
{
	pContext_t dev = filp->private_data;
	u32 threshold = 0;
	
	switch(command)
	{
		case MMA_GET_THRESHOLD:
			{

				if (copy_to_user(&arg, &(dev->threshold), sizeof(u32)))
			       	{
					printk("ioctl, copy to user failed\n");
					return -EFAULT;
				}
			}
			break;

		case MMA_GET_THRESHOLD_VALUE:
			{

				return dev->threshold;
			}
			break;

		case MMA_SET_THRESHOLD:
			{
				if (copy_from_user(&threshold, &arg, sizeof(u32)))
			       	{
					return -EFAULT;
				}
				if(threshold <= 0)
				{
					return -EINVAL;
				}
				
				dev->threshold = threshold;
			}
			break;

		case MMA_SET_THRESHOLD_VALUE:
			{
				threshold = arg;
				if(threshold <= 0)
				{
					printk("Invalid value [0x%x]\r\n", threshold);
					return -EINVAL;
				}
				dev->threshold = threshold;
			}
			break;

		case MMA_GET_ACCLEROMETER_FLAG:
			{

				return GetAcclerometerFlag();
			}
			break;

		case MMA_SET_ACCLEROMETER_FLAG:
			{
				int AcclFlag = arg;

				return SetAcclerometerFlag(AcclFlag);
			}
			break;

		default:
			{
				printk("%s:: Invalid IOCTL [0x%x]\r\n", __func__, command);
			}
	}
	return 0;
}

这个ioctl函数很简单,通过switch case语句,把用户传进去的参数分类,然后做出不同的动作,其中有对threshold的设置,读取,对acclerometer_flag的设置和获取等动作。

  1. /*! 
  2. * read call for pressure char driver.  
  3. * file  : Pointer to file structure. 
  4. * buf    : Pointer to user buffer in which data will be read. 
  5. * size  : Size of data be read. 
  6. * ppos  : Pointer to Offset in the file. 
  7. * return  1. no of bytes read - For successful read \ 
  8.          2. ENOMEM - file private data pointer is NULL    
  9. */  
  10.   
  11. static ssize_t mma_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)  
  12. {  
  13.     int retval = 0;  
  14.     unsigned short nr = 0;  
  15.     pContext_t dev = file->private_data;  
  16.     int bytestocopy = 0;  
  17.     unsigned long bytescopied = 0;  
  18.     char __user *buff = buf;  
  19.   
  20.     unsigned short hdr = 0xffff;  
  21.   
  22.     if (!dev)   
  23.     {  
  24.         return -ENOMEM;  
  25.     }  
  26.   
  27.     /* Acquire semaphore to manage re-entrancy */  
  28.     if (down_interruptible(&dev->sem))  
  29.         return -ERESTARTSYS;  
  30.   
  31.   
  32.     /* Loop till data available has crossed the watermark */  
  33.     nr = GetAvailableData(dev->read_pos);  
  34.     while (nr < dev->threshold )   
  35.     {   
  36.         /* Wait on accelerometer queue (AcclQ) till condition GetAvailableData(dev->read_pos) >= dev->threshold gets satisfied */  
  37.         if (wait_event_interruptible(AcclDataQ,   
  38.                     (GetAvailableData(dev->read_pos) >= dev->threshold)))  
  39.             return -ERESTARTSYS;  
  40.         nr = GetAvailableData(dev->read_pos);  
  41.     }  
  42.   
  43.     bytescopied = copy_to_user(buff, &hdr, sizeof(unsigned short));  
  44.     retval += sizeof(unsigned short);  
  45.     buff += sizeof(unsigned short);  
  46.     bytescopied = copy_to_user(buff, &nr, sizeof(unsigned short));  
  47.   
  48.     retval += sizeof(unsigned short);  
  49.     buff += sizeof(unsigned short);  
  50.   
  51.     /* Loop here to copy bytes to user buffer */  
  52.     while(nr)  
  53.     {  
  54.         if(dev->read_pos + nr >= ACCL_FIFO_SIZE)  
  55.         {  
  56.             bytestocopy = ACCL_FIFO_SIZE - dev->read_pos ;  
  57.         }  
  58.         else  
  59.         {  
  60.             bytestocopy = nr;  
  61.         }  
  62.   
  63.         /* Copy the required records to user buffer */  
  64.         bytescopied = copy_to_user(buff, &AcclDataFifo[dev->read_pos], bytestocopy * sizeof(AcclData_t));  
  65.   
  66.         retval += bytestocopy * sizeof(AcclData_t);  
  67.         buff += bytestocopy * sizeof(AcclData_t);  
  68.           
  69.         nr -= bytestocopy;  
  70.   
  71.         /* Increment the read_pos */  
  72.         dev->read_pos += bytestocopy;  
  73.         if(dev->read_pos >= ACCL_FIFO_SIZE)  
  74.             dev->read_pos -= ACCL_FIFO_SIZE;  
  75.     }  
  76.     /* release the lock */  
  77.     up(&dev->sem);   
  78.     /* Return the number of bytes written to buffer */  
  79.     return retval;  
  80. }  
/*!
* read call for pressure char driver. 
* file  : Pointer to file structure.
* buf 	 : Pointer to user buffer in which data will be read.
* size  : Size of data be read.
* ppos  : Pointer to Offset in the file.
* return  1. no of bytes read - For successful read \
   	     2. ENOMEM - file private data pointer is NULL	 
*/

static ssize_t mma_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	int retval = 0;
	unsigned short nr = 0;
	pContext_t dev = file->private_data;
	int bytestocopy = 0;
	unsigned long bytescopied = 0;
	char __user *buff = buf;

	unsigned short hdr = 0xffff;

	if (!dev) 
	{
		return -ENOMEM;
	}

	/* Acquire semaphore to manage re-entrancy */
	if (down_interruptible(&dev->sem))
		return -ERESTARTSYS;


	/* Loop till data available has crossed the watermark */
	nr = GetAvailableData(dev->read_pos);
	while (nr < dev->threshold ) 
	{ 
		/* Wait on accelerometer queue (AcclQ) till condition GetAvailableData(dev->read_pos) >= dev->threshold gets satisfied */
		if (wait_event_interruptible(AcclDataQ, 
					(GetAvailableData(dev->read_pos) >= dev->threshold)))
			return -ERESTARTSYS;
		nr = GetAvailableData(dev->read_pos);
	}

	bytescopied = copy_to_user(buff, &hdr, sizeof(unsigned short));
	retval += sizeof(unsigned short);
	buff += sizeof(unsigned short);
	bytescopied = copy_to_user(buff, &nr, sizeof(unsigned short));

	retval += sizeof(unsigned short);
	buff += sizeof(unsigned short);

	/* Loop here to copy bytes to user buffer */
	while(nr)
	{
		if(dev->read_pos + nr >= ACCL_FIFO_SIZE)
		{
			bytestocopy = ACCL_FIFO_SIZE - dev->read_pos ;
		}
		else
		{
			bytestocopy = nr;
		}

		/* Copy the required records to user buffer */
		bytescopied = copy_to_user(buff, &AcclDataFifo[dev->read_pos], bytestocopy * sizeof(AcclData_t));

		retval += bytestocopy * sizeof(AcclData_t);
		buff += bytestocopy * sizeof(AcclData_t);
		
		nr -= bytestocopy;

		/* Increment the read_pos */
		dev->read_pos += bytestocopy;
		if(dev->read_pos >= ACCL_FIFO_SIZE)
			dev->read_pos -= ACCL_FIFO_SIZE;
	}
	/* release the lock */
	up(&dev->sem); 
	/* Return the number of bytes written to buffer */
	return retval;
}

这个函数看上去很复杂,其实就做了一件事情,调用copy_to_user把数据传到用户空间,其实这里我很不明白这个字符驱动到底跟我们的mma器件有什么关系,因为这里read函数中我没有看到一点关于i2cread 的内容,所以我觉得,这里这个字符驱动是多余的,不过这里对等待队列的读操作有待学习。

我们也可以自己再这里加上对I2C的读操作来把这里的read函数挂到用户空间,我想这里的ioctl函数应该是来设置threshold的,应该是用在HAL层中来被设置的。

而这里的read函数也可以当做poll模式下来读取xyz的数据,大家可以看到在read中有作比较,当读回来的数据大于threshold时才把数据copy到用户空间。

OK,这个字符驱动暂时介绍到这边,下面我们接着看mma_core.c中的probe函数

  1.    /* 
  2.     * Initialize input layer  
  3.     */  
  4.    InitializeInputInterface(pDev);  
  5.   
  6.    /* 
  7.     * Create sysfs entries  
  8.     */  
  9.    InitializeSysfs( (struct i2c_client *)client);  
  10.   
  11.    /* 
  12.     * Initialize semaphore for interrupt 
  13.     */  
  14.    sema_init(&chip_ready, 0);  
  15.   
  16.    setup_timer(&stall_timer, stall_timer_fn, 0);  
  17.    hIstThread = kthread_run(IntServiceThread, pDev, "mxc845x_ist");  
  18.    if (IS_ERR(hIstThread)) {  
  19.  printk(KERN_INFO "Error creating mxc845x ist.\n");  
  20. goto error_free_irq1;  
  21.    }  
  22.    if (plat_data->int1 > 0)  {     
  23.     set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);  
  24.   
  25.     ret = request_irq(plat_data->int1, mma845x_interrupt,  
  26.               IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  27.   
  28.     if (ret) {  
  29.     dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  30.         plat_data->int1, ret);  
  31.     goto error_disable_power;  
  32.     }  
  33.    }  
  34.    else {  
  35.     gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);  
  36.     poll_mode = 1;  
  37. }  
  38.    if (plat_data->int2 > 0){  
  39.      printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,  
  40.    plat_data->int2);  
  41.   
  42.      set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);  
  43.      ret = request_irq(plat_data->int2, mma845x_interrupt,  
  44.           IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  45.     if (ret) {  
  46.     dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  47.     plat_data->int2, ret);  
  48.     goto error_free_irq1;  
  49.     }  
  50.   }  
    /*
     * Initialize input layer 
     */
    InitializeInputInterface(pDev);

    /*
     * Create sysfs entries 
     */
    InitializeSysfs( (struct i2c_client *)client);

    /*
     * Initialize semaphore for interrupt
     */
    sema_init(&chip_ready, 0);

    setup_timer(&stall_timer, stall_timer_fn, 0);
    hIstThread = kthread_run(IntServiceThread, pDev, "mxc845x_ist");
    if (IS_ERR(hIstThread)) {
	 printk(KERN_INFO "Error creating mxc845x ist.\n");
	goto error_free_irq1;
    }
    if (plat_data->int1 > 0)  {   
	    set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);

	    ret = request_irq(plat_data->int1, mma845x_interrupt,
			      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);

	    if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
			plat_data->int1, ret);
		goto error_disable_power;
	    }
    }
    else {
		gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);
		poll_mode = 1;
	}
    if (plat_data->int2 > 0){
    	 printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,
	   plat_data->int2);

   	 set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);
   	 ret = request_irq(plat_data->int2, mma845x_interrupt,
		      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);
     if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
		plat_data->int2, ret);
		goto error_free_irq1;
     }
   }

这里是一些列的初始化,input sybsystem、文件系统、信号量、定时器、线程的初始化,先看输入子系统初始化过程

  1. int InitializeInputInterface(struct mxc_mma_device_t *pDev)  
  2. {  
  3.     int RetVal = 0;  
  4.     int i = 0;  
  5.   
  6.     if(pDev == NULL)  
  7.     {  
  8.         printk("%s: pDev => NULL pointer\r\n", __func__);  
  9.         return -EPERM;  
  10.     }  
  11.   
  12.     pDev->inp1 = input_allocate_device();  
  13.   
  14.     if (!pDev->inp1)  
  15.         {  
  16.         RetVal = -ENOMEM;  
  17.         printk(KERN_ERR  
  18.                "%s: Failed to allocate input device-1\n", __func__);  
  19.         return RetVal;  
  20.     }  
  21.   
  22.     set_bit(EV_ABS, pDev->inp1->evbit);                       // Accelerometer readings   
  23.   
  24.     /* yaw */  
  25.     input_set_abs_params(pDev->inp1, ABS_RX, 0, 360, 0, 0);  
  26.     /* pitch */  
  27.     input_set_abs_params(pDev->inp1, ABS_RY, -180, 180, 0, 0);  
  28.     /* roll */  
  29.     input_set_abs_params(pDev->inp1, ABS_RZ, -90, 90, 0, 0);  
  30.   
  31.     /* x-axis acceleration */  
  32.     input_set_abs_params(pDev->inp1, ABS_X, -32768, 32767, 0, 0);  
  33.     /* y-axis acceleration */  
  34.     input_set_abs_params(pDev->inp1, ABS_Y, -32768, 32767, 0, 0);  
  35.     /* z-axis acceleration */  
  36.     input_set_abs_params(pDev->inp1, ABS_Z, -32768, 32767, 0, 0);  
  37.   
  38.     pDev->inp1->name = "mma8451";  
  39.   
  40.     RetVal = input_register_device(pDev->inp1);  
  41.   
  42.     if (RetVal)   
  43.     {  
  44.         printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, pDev->inp1->name);  
  45.         return RetVal;  
  46.     }  
  47.       
  48.     /* Register input device 2 */  
  49.     pDev->inp2 = input_allocate_device();  
  50.   
  51.     if (!pDev->inp2)  
  52.         {  
  53.         RetVal = -ENOMEM;  
  54.         printk(KERN_ERR "%s: Failed to allocate input device-2\n", __func__);  
  55.         return RetVal;  
  56.     }  
  57.   
  58.     /* Initialize all event codes as this is a configurable param and may change runtime from user space */  
  59.     for(i = 0x20; i < 0x40; i++)  
  60.         input_set_abs_params(pDev->inp2, i, 0, 255, 0, 0);  
  61.   
  62.     pDev->inp2->mscbit[0] = BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);  
  63.   
  64.   
  65.     pDev->inp2->name = "Accl1";  
  66.   
  67.     set_bit(EV_ABS, pDev->inp2->evbit);  
  68.     set_bit(EV_KEY, pDev->inp2->evbit);  
  69.     set_bit(EV_MSC, pDev->inp2->evbit);  
  70.   
  71.     RetVal = input_register_device(pDev->inp2);  
  72.   
  73.     bitmap_fill(pDev->inp2->keybit, KEY_MAX);  
  74.   
  75.     if (RetVal)   
  76.     {  
  77.         printk(KERN_ERR "%s: Unable to register input device: %s\n", __func__, pDev->inp2->name);  
  78.         return RetVal;  
  79.     }  
  80.     return RetVal;    
  81. }  
int InitializeInputInterface(struct mxc_mma_device_t *pDev)
{
	int RetVal = 0;
	int i = 0;

	if(pDev == NULL)
	{
		printk("%s: pDev => NULL pointer\r\n", __func__);
		return -EPERM;
	}

	pDev->inp1 = input_allocate_device();

	if (!pDev->inp1)
       	{
		RetVal = -ENOMEM;
		printk(KERN_ERR
		       "%s: Failed to allocate input device-1\n", __func__);
		return RetVal;
	}

	set_bit(EV_ABS, pDev->inp1->evbit);						// Accelerometer readings

	/* yaw */
	input_set_abs_params(pDev->inp1, ABS_RX, 0, 360, 0, 0);
	/* pitch */
	input_set_abs_params(pDev->inp1, ABS_RY, -180, 180, 0, 0);
	/* roll */
	input_set_abs_params(pDev->inp1, ABS_RZ, -90, 90, 0, 0);

	/* x-axis acceleration */
	input_set_abs_params(pDev->inp1, ABS_X, -32768, 32767, 0, 0);
	/* y-axis acceleration */
	input_set_abs_params(pDev->inp1, ABS_Y, -32768, 32767, 0, 0);
	/* z-axis acceleration */
	input_set_abs_params(pDev->inp1, ABS_Z, -32768, 32767, 0, 0);

	pDev->inp1->name = "mma8451";

	RetVal = input_register_device(pDev->inp1);

	if (RetVal) 
	{
		printk(KERN_ERR "%s: Unable to register input device: %s\n",__func__, pDev->inp1->name);
		return RetVal;
	}
	
	/* Register input device 2 */
	pDev->inp2 = input_allocate_device();

	if (!pDev->inp2)
       	{
		RetVal = -ENOMEM;
		printk(KERN_ERR "%s: Failed to allocate input device-2\n", __func__);
		return RetVal;
	}

	/* Initialize all event codes as this is a configurable param and may change runtime from user space */
	for(i = 0x20; i < 0x40; i++)
		input_set_abs_params(pDev->inp2, i, 0, 255, 0, 0);

	pDev->inp2->mscbit[0] = BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN);


	pDev->inp2->name = "Accl1";

	set_bit(EV_ABS, pDev->inp2->evbit);
	set_bit(EV_KEY, pDev->inp2->evbit);
	set_bit(EV_MSC, pDev->inp2->evbit);

	RetVal = input_register_device(pDev->inp2);

	bitmap_fill(pDev->inp2->keybit, KEY_MAX);

	if (RetVal) 
	{
		printk(KERN_ERR "%s: Unable to register input device: %s\n", __func__, pDev->inp2->name);
		return RetVal;
	}
	return RetVal;	
}

分别调用input_allocate_device和input_register_device函数来注册input 驱动,然后就是设置input 驱动的类型,下面还注册了一个输入设备这里我的理解是这样的,input1主要是输出xyz方向上的重力加速度分量,而input2主要是用来输出一些碰撞和震动,还有横竖切换等事件。

下面是初始化文件系统

  1. /*! 
  2. * This method is used to Initialize Sysfs.  
  3. * client   : Pointer to i2c_client structure. 
  4. * return -EPERM  : Device pointer is NULL. 
  5. * return  0      : Success.  
  6. */  
  7. struct class *sensor_class_obj = NULL;  
  8. int InitializeSysfs(struct i2c_client *client)  
  9. {  
  10.     int RetVal = 0;  
  11.     int i = 0;  
  12.     int Iterator = 0;  
  13.     int Instance = 0;  
  14.     struct mxc_mma_device_t *pDev = i2c_get_clientdata(client);  
  15.     struct ChipInfo_t *pChip = pDev->pChip;  
  16.     struct SysfsInfo_t *pSysfsInfo = pChip->pSysfsInfo;  
  17.   
  18.     if(pDev == NULL)  
  19.     {  
  20.         printk("%s: pDev => NULL pointer\r\n", __func__);  
  21.         return -EPERM;  
  22.     }  
  23.   
  24.     if(sensor_class_obj == NULL)  
  25.     {  
  26.         pDev->class = class_create(THIS_MODULE, "sensor");  
  27.         if (IS_ERR(pDev->class))   
  28.         {  
  29.             printk(KERN_ERR "Unable to create class for Mxc MMA\n");  
  30.             RetVal = PTR_ERR(pDev->class);  
  31.         }  
  32.         sensor_class_obj = pDev->class;  
  33.     }  
  34.         else  
  35.     {  
  36.         pDev->class = sensor_class_obj;  
  37.     }  
  38.     client->dev.class = pDev->class;  
  39.   
  40.     pDev->sys_device = device_create(pDev->class, NULL, MKDEV(pDev->major, 0), pDev,"mma");  
  41.   
  42.     if (IS_ERR(pDev->sys_device))  
  43.         {  
  44.         printk(KERN_ERR "Unable to create class device for Mxc Ipu\n");  
  45.         RetVal = PTR_ERR(pDev->sys_device);  
  46.         return RetVal;  
  47.     }  
  48.   
  49.     dev_set_drvdata( (struct device *)&pDev->sys_device, pDev);  
  50.   
  51.     for(Iterator = 0; Iterator < pChip->SysfsInfoSize; Iterator++)  
  52.     {  
  53.         for(Instance = 0; Instance < pSysfsInfo[Iterator].Instance; Instance++)  
  54.         {         
  55.             /* Create motion_detection device */  
  56.             if(pSysfsInfo[Iterator].grpName != NULL)  
  57.             {  
  58.                 pDev->sys_motion_dev = device_create(pDev->class, pDev->sys_device, MKDEV(0, 0), pDev,  
  59.                         "%s%d", pSysfsInfo[Iterator].grpName, Instance);  
  60.             }  
  61.             else  
  62.             {  
  63.                 pDev->sys_motion_dev = pDev->sys_device;  
  64.             }  
  65.   
  66.             for(i=0; i < pSysfsInfo[Iterator].TotalEntries; i++)  
  67.             {  
  68.                 if(sysfs_create_file(&pDev->sys_motion_dev->kobj, &pSysfsInfo[Iterator].AttrEntry[i].attr) < 0)  
  69.                 printk("%s sys file creation failed.\r\n", pSysfsInfo[Iterator].AttrEntry[i].attr.name);  
  70.             }  
  71.         }  
  72.     }  
  73.     return RetVal;    
  74. }  
  75. EXPORT_SYMBOL(sensor_class_obj);  
/*!
* This method is used to Initialize Sysfs. 
* client   : Pointer to i2c_client structure.
* return -EPERM  : Device pointer is NULL.
* return  0      : Success. 
*/
struct class *sensor_class_obj = NULL;
int InitializeSysfs(struct i2c_client *client)
{
	int RetVal = 0;
	int i = 0;
	int Iterator = 0;
	int Instance = 0;
	struct mxc_mma_device_t *pDev = i2c_get_clientdata(client);
	struct ChipInfo_t *pChip = pDev->pChip;
	struct SysfsInfo_t *pSysfsInfo = pChip->pSysfsInfo;

	if(pDev == NULL)
	{
		printk("%s: pDev => NULL pointer\r\n", __func__);
		return -EPERM;
	}

	if(sensor_class_obj == NULL)
	{
		pDev->class = class_create(THIS_MODULE, "sensor");
		if (IS_ERR(pDev->class)) 
		{
			printk(KERN_ERR "Unable to create class for Mxc MMA\n");
			RetVal = PTR_ERR(pDev->class);
		}
		sensor_class_obj = pDev->class;
	}
		else
	{
		pDev->class = sensor_class_obj;
	}
	client->dev.class = pDev->class;

	pDev->sys_device = device_create(pDev->class, NULL, MKDEV(pDev->major, 0), pDev,"mma");

	if (IS_ERR(pDev->sys_device))
       	{
		printk(KERN_ERR "Unable to create class device for Mxc Ipu\n");
		RetVal = PTR_ERR(pDev->sys_device);
		return RetVal;
	}

	dev_set_drvdata( (struct device *)&pDev->sys_device, pDev);

	for(Iterator = 0; Iterator < pChip->SysfsInfoSize; Iterator++)
	{
		for(Instance = 0; Instance < pSysfsInfo[Iterator].Instance; Instance++)
		{		
			/* Create motion_detection device */
			if(pSysfsInfo[Iterator].grpName != NULL)
			{
				pDev->sys_motion_dev = device_create(pDev->class, pDev->sys_device, MKDEV(0, 0), pDev,
						"%s%d", pSysfsInfo[Iterator].grpName, Instance);
			}
			else
			{
				pDev->sys_motion_dev = pDev->sys_device;
			}

			for(i=0; i < pSysfsInfo[Iterator].TotalEntries; i++)
			{
				if(sysfs_create_file(&pDev->sys_motion_dev->kobj, &pSysfsInfo[Iterator].AttrEntry[i].attr) < 0)
				printk("%s sys file creation failed.\r\n", pSysfsInfo[Iterator].AttrEntry[i].attr.name);
			}
		}
	}
	return RetVal;	
}
EXPORT_SYMBOL(sensor_class_obj);

这里代码很多,在mma_sysfs.c中,其实一点都不难,就是太多了有点复杂,看过内核驱动模型的同学应该很熟悉这里,这里就是建立了一个名为sensor的class,来作为这些文件的父类,具体的我不多说了,这里的文件太多了,也讲不完,可以一边参照data sheet一边看这里的文件时用来干嘛的,这里read/write 的时候就分别会回调这里相关的函数,然后去设置寄存器。大家可以看到下面就是这里建立的文件系统

/sys/class/sensor # ls -l
lrwxrwxrwx    1 root     root             0 Jan  2 01:10 mma -> ../../devices/virtual/sensor/mma
lrwxrwxrwx    1 root     root             0 Jan  2 01:10 motion_detection0 -> ../../devices/virtual/sensor/mma/motion_detection0
lrwxrwxrwx    1 root     root             0 Jan  2 01:10 orientation_detection0 -> ../../devices/virtual/sensor/mma/orientation_detection0
lrwxrwxrwx    1 root     root             0 Jan  2 01:10 tap_detection0 -> ../../devices/virtual/sensor/mma/tap_detection0
lrwxrwxrwx    1 root     root             0 Jan  2 01:10 transient_detection0 -> ../../devices/virtual/sensor/mma/transient_detection0
/sys/class/sensor # 

然后是初始化信号量和定时器,这里就不多说了。

接下来是创建了一个线程并执行他,这个线程是一个死循环,也就是我们这里最关键的一个函数,之后再说。

  1.   if (plat_data->int1 > 0)  {     
  2.    set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);  
  3.   
  4.    ret = request_irq(plat_data->int1, mma845x_interrupt,  
  5.           IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  6.   
  7.    if (ret) {  
  8. dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  9.     plat_data->int1, ret);  
  10. goto error_disable_power;  
  11.    }  
  12.   }  
  13.   else {  
  14. gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);  
  15. poll_mode = 1;  
  16.   
  17.   if (plat_data->int2 > 0){  
  18.      printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,  
  19.   plat_data->int2);  
  20.   
  21.      set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);  
  22.      ret = request_irq(plat_data->int2, mma845x_interrupt,  
  23.       IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);  
  24.    if (ret) {  
  25. dev_err(&client->dev, "request_irq(%d) returned error %d\n",  
  26. plat_data->int2, ret);  
  27. goto error_free_irq1;  
  28.    }  
    if (plat_data->int1 > 0)  {   
	    set_irq_type(plat_data->int1, IRQF_TRIGGER_FALLING);

	    ret = request_irq(plat_data->int1, mma845x_interrupt,
			      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);

	    if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
			plat_data->int1, ret);
		goto error_disable_power;
	    }
    }
    else {
		gpChip->DisableInt(INT_EN_FIFO | INT_EN_DRDY);
		poll_mode = 1;
	}
    if (plat_data->int2 > 0){
    	 printk(KERN_INFO "%s:: Configuring interrupt IRQ [%d]\r\n", __func__,
	   plat_data->int2);

   	 set_irq_type(plat_data->int2, IRQF_TRIGGER_FALLING);
   	 ret = request_irq(plat_data->int2, mma845x_interrupt,
		      IRQF_TRIGGER_FALLING, DEVICE_NAME, pDev);
     if (ret) {
		dev_err(&client->dev, "request_irq(%d) returned error %d\n",
		plat_data->int2, ret);
		goto error_free_irq1;
     }

然后这里是申请中断,如果我们使用中断模式的话就申请中断,如果没有使用中断模式的话这里有一个flag,poll_mode被设置成1,初始化的时候是0.

porbe函数就先讲到这里,这里主要还是做了一些初始化的东西,下面来分析一下这个驱动是如何工作的,其实相关的就是这里最重要的2个东西,一个是定时器,还有一个是这个thread的处理,我们下面接着看

  1. /*! 
  2. * This function implements interrupt handler routine  
  3. * irq : Interrupt number 
  4. * dev_id 
  5. * return IRQ_RETVAL 
  6. */  
  7. static irqreturn_t mma845x_interrupt(int irq, void *dev_id)  
  8. {  
  9. //+++add for debug   
  10. //printk("mma--irq\n");   
  11.     up(&chip_ready);  
  12.     return IRQ_RETVAL(1);  
  13. }  
  14.   
  15. /*! 
  16. * This routine implements a call back for stall timer  
  17. * data : Pointer to device data structure 
  18. * return NONE 
  19. */  
  20. static void stall_timer_fn(unsigned long data)  
  21. {  
  22. //++++add for debug   
  23. //printk("mma-- poll\n");   
  24.     up(&chip_ready);  
  25. }  
/*!
* This function implements interrupt handler routine 
* irq : Interrupt number
* dev_id
* return IRQ_RETVAL
*/
static irqreturn_t mma845x_interrupt(int irq, void *dev_id)
{
//+++add for debug
//printk("mma--irq\n");
    up(&chip_ready);
    return IRQ_RETVAL(1);
}

/*!
* This routine implements a call back for stall timer 
* data : Pointer to device data structure
* return NONE
*/
static void stall_timer_fn(unsigned long data)
{
//++++add for debug
//printk("mma-- poll\n");
    up(&chip_ready);
}

首先看下这里的中断响应函数和定时器响应函数,这里基本啥也没做,就是释放信号量,关键就在这,我们接着看

  1. static int IntServiceThread(void *data)  
  2. {  
  3.     wait_queue_t    wait;  
  4.     int             ret = 0;  
  5.     struct mxc_mma_device_t *pDev = (struct mxc_mma_device_t *) data;  
  6.     struct ChipInfo_t *pChip = pDev->pChip;  
  7.     char buff[256];  
  8.   
  9.     init_waitqueue_entry(&wait, current);  
  10.   
  11.     mod_timer(&stall_timer, jiffies + (HZ));  
  12.     while (!done) {  
  13.   
  14.     do {  
  15.         ret = down_interruptible(&chip_ready);  
  16.     } while (ret == -EINTR);  
  17.   
  18.     if (!poll_mode) {  
  19.         ret = pChip->GetIntSrc();  
  20.     }   
  21.     else   
  22.         ret = SRC_DRDY;  
  23.   
  24.   
  25.     if (SRC_DRDY & ret) {  
  26.         pChip->Read(ACCL_DATA, (void *) buff);  
  27.   
  28.         UpdateAcclFiFo(buff);  
  29.         if (!IsSuspended) {  
  30.         if (pDev->aflag == 1)  
  31.             ReportEvent(pDev, ACCL_DATA, buff);  
  32.         }  
  33.     }  
  34.   
  35.     if (SRC_FIFO & ret) {  
  36.             int             count = 0,  
  37.             i = 0;  
  38.             char *pBuff = (char *) buff;  
  39.             printk(KERN_DEBUG "\t[FIFO] [%ld]\r\n", jiffies);  
  40.             count = pChip->Read(FIFO_DATA, (void *) buff);  
  41.   
  42.             for (i = 0; i < count; i++) {  
  43.             UpdateAcclFiFo(pBuff + (i * sizeof(AcclData_t)));  
  44.             if (!IsSuspended) {  
  45.                     if (pDev->aflag == 1)  
  46.                     ReportEvent(pDev, ACCL_DATA,  
  47.                         pBuff + (i * sizeof(AcclData_t)));  
  48.         }  
  49.         }  
  50.     }  
  51.   
  52.     /* 
  53.      * Orientation  
  54.      */  
  55.     if (SRC_LNDPRT & ret) {  
  56.         char           *pBuff = (char *) buff;  
  57.         pChip->Read(ACCL_LNDPRT, (void *) buff);  
  58.         if (!IsSuspended)  
  59.         ReportEvent(pDev, ACCL_LNDPRT, pBuff);  
  60.     }  
  61.   
  62.     /* 
  63.      * Motion / Freefall interrupt  
  64.      */  
  65.     if (SRC_FF_MT & ret) {  
  66.         pChip->Read(ACCL_FF_MT, (void *) buff);  
  67.         if (!IsSuspended)  
  68.         ReportEvent(pDev, ACCL_FF_MT, buff);  
  69.     }  
  70.   
  71.     if (SRC_FF_MT_2 & ret) {  
  72.         pChip->Read(ACCL_FF_MT_2, (void *) buff);  
  73.         if (!IsSuspended)  
  74.         ReportEvent(pDev, ACCL_FF_MT_2, buff);  
  75.     }  
  76.   
  77.     /* 
  78.      * Motion / Freefall interrupt  
  79.      */  
  80.     if (SRC_PULSE & ret) {  
  81.         pChip->Read(ACCL_PULSE, (void *) buff);  
  82.         if (!IsSuspended)  
  83.         ReportEvent(pDev, ACCL_PULSE, buff);  
  84.     }  
  85.   
  86.     if (SRC_TRANS & ret) {  
  87.         pChip->Read(ACCL_TRANS, (void *) buff);  
  88.         if (!IsSuspended)  
  89.         ReportEvent(pDev, ACCL_TRANS, buff);  
  90.     }  
  91.     if (!IsSuspended) {  
  92.         if (!poll_mode) {  
  93.             mod_timer(&stall_timer, jiffies + (HZ));  
  94.         }  
  95.         else   
  96.             mod_timer(&stall_timer, jiffies + pChip->poll_time);  
  97.     }  
  98.       
  99.     }  
  100.     return 0;  
  101. }  
static int IntServiceThread(void *data)
{
    wait_queue_t    wait;
    int             ret = 0;
    struct mxc_mma_device_t *pDev = (struct mxc_mma_device_t *) data;
    struct ChipInfo_t *pChip = pDev->pChip;
    char buff[256];

    init_waitqueue_entry(&wait, current);

    mod_timer(&stall_timer, jiffies + (HZ));
    while (!done) {

	do {
	    ret = down_interruptible(&chip_ready);
	} while (ret == -EINTR);

	if (!poll_mode) {
		ret = pChip->GetIntSrc();
	} 
	else 
		ret = SRC_DRDY;


	if (SRC_DRDY & ret) {
	    pChip->Read(ACCL_DATA, (void *) buff);

	    UpdateAcclFiFo(buff);
	    if (!IsSuspended) {
		if (pDev->aflag == 1)
		    ReportEvent(pDev, ACCL_DATA, buff);
	    }
	}

	if (SRC_FIFO & ret) {
	    	int             count = 0,
			i = 0;
	    	char *pBuff = (char *) buff;
	    	printk(KERN_DEBUG "\t[FIFO] [%ld]\r\n", jiffies);
	    	count = pChip->Read(FIFO_DATA, (void *) buff);

	    	for (i = 0; i < count; i++) {
			UpdateAcclFiFo(pBuff + (i * sizeof(AcclData_t)));
			if (!IsSuspended) {
		    		if (pDev->aflag == 1)
					ReportEvent(pDev, ACCL_DATA,
				    	pBuff + (i * sizeof(AcclData_t)));
		}
	    }
	}

	/*
	 * Orientation 
	 */
	if (SRC_LNDPRT & ret) {
	    char           *pBuff = (char *) buff;
	    pChip->Read(ACCL_LNDPRT, (void *) buff);
	    if (!IsSuspended)
		ReportEvent(pDev, ACCL_LNDPRT, pBuff);
	}

	/*
	 * Motion / Freefall interrupt 
	 */
	if (SRC_FF_MT & ret) {
	    pChip->Read(ACCL_FF_MT, (void *) buff);
	    if (!IsSuspended)
		ReportEvent(pDev, ACCL_FF_MT, buff);
	}

	if (SRC_FF_MT_2 & ret) {
	    pChip->Read(ACCL_FF_MT_2, (void *) buff);
	    if (!IsSuspended)
		ReportEvent(pDev, ACCL_FF_MT_2, buff);
	}

	/*
	 * Motion / Freefall interrupt 
	 */
	if (SRC_PULSE & ret) {
	    pChip->Read(ACCL_PULSE, (void *) buff);
	    if (!IsSuspended)
		ReportEvent(pDev, ACCL_PULSE, buff);
	}

	if (SRC_TRANS & ret) {
	    pChip->Read(ACCL_TRANS, (void *) buff);
	    if (!IsSuspended)
		ReportEvent(pDev, ACCL_TRANS, buff);
	}
	if (!IsSuspended) {
		if (!poll_mode) {
		    mod_timer(&stall_timer, jiffies + (HZ));
		}
		else 
		    mod_timer(&stall_timer, jiffies + pChip->poll_time);
	}
	
    }
    return 0;
}

看下我们的线程,一开始是初始化了一堆变量,然后把data转化为我们这里的一个ChipInfo_t结构体指针,然后初始化等待队列,然后是修改定时器下次定时到达时间为1秒钟,然后是一个while循环,看下这个循环中到底做了啥事情。

首先是一个do while来试图获取信号量,这里信号量被初始化为0,所以这边是得不到的,就会一直等在这边,前面我们看过定时器和中断函数中都做了对信号量的释放动作,联想到这边就是说,我们的线程不是一直在走的,只有当发生定时器时间到达和中断发生了,才会让我们这里的线程继续往下走,也就实现了这里的polling和interrupt 这2中模式。

这个线程下面的代码我们都能猜到,就是通过I2C读取芯片中的数据,然后利用input子系统push到用户空间,如果是polling mode的话就修改下次定时到达的时间,这里的设计还是满巧妙的,有待学习,特别是我觉得代码写的比较规范。

下面来一张图来分析这里的处理流程。


画的太丑了,见谅!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值