ct8c242代码分析记录

1.file_operations结构体:
2.misc_register/misc_deregister:该函数是用来注册一个杂项设备的。返回值为一个整数,如果注册成功返回0,注册失败则返回失败的错误代码。
3.miscdevice:misc_register要注册的设备结构,这个结构体是misc设备基本的结构体,在注册misc设备的时候必须要声明并初始化一个这样的结构体,但其中一般只需填充name minor fops字段就可以了
4.register_chrdev与misc_register:
5.i2c_set_clientdata://初始化I2c资源
6.disable_irq_nosync
7.i2c_check_functionality:用来判定设配器的能力,函数用于返回algorithm所支持的通信协议,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等
8.i2c_check_functionality(client->adapter, I2C_FUNC_I2C)   这一行代码可以使用I2C协议和设备进行通信。它进行连续的读写,中间没有间歇。只有当适配器支持I2C_FUNC_I2C此命令才有效。
9.INIT_WORK:可以理解为INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func
10.mutex_init
11.wake_lock_init:该函数设置锁的名字,类型,最后将新建的锁挂接到一个专门链接这些非锁状态的链表inactive_locks上(新建的wakelock初期都是出于非锁状态的,除非显示调用函数wake_lock来上锁)。接着如果使用函数wake_lock()来给特定的wakelock上锁的话,会将该锁从链表inactive_locks上移动到对应类型的专用链表上active_wake_locks[type]上。
12.create_singlethread_workqueue
13.input_allocate_device:申请并初始化一个输入设备。通过输入设备,驱动程序才能和用户交互。
14.input_register_device
15.regulator_get
16.INIT_WORK
17.input_allocate_device
18.sysfs_create_group

 

 

/*xiaofei modify end*/

 

 

 


static int cy8ctst242_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
 struct cy8ctst242_ts_data *cy8ctst242_ts;
 struct input_dev *input_dev;
 struct device_node *np = client->dev.of_node;        //device_node: 设备节点
 const char *fw_name;
 int len,temp_val,err = 0;
#ifdef CY8C242_PROXIMITY
 struct input_dev *input_proximity;
#endif 
 //struct common_ts_platform_data *pdata = client->dev.platform_data; 
 struct common_ts_platform_data *pdata = &common_ts_info;
 TPDBG("Cy8c242_ts cy8ctst242_ts_probe\n"); 
 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {       //用来判定设配器的能力,函数用于返回algorithm所支持的通信协议,比如I2C_FUNC_I2C,I2C_FUNC_10BIT_ADDR等
  err = -ENODEV;
  goto exit_check_functionality_failed;
 }

 cy8ctst242_ts = kzalloc(sizeof(*cy8ctst242_ts), GFP_KERNEL);//用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0. GFP_KERNEL:内核内存的正常分配. 可能睡眠.
 if (!cy8ctst242_ts) {
  err = -ENOMEM;
  goto exit_alloc_data_failed;
 }
 g_cy8ctst242_ts = cy8ctst242_ts;
 cy8ctst242_ts->platform_data = pdata;
 this_client = client; 
 cy8ctst242_ts->client = client;
 i2c_set_clientdata(client, cy8ctst242_ts);  //i2c_set_clientdata:初始化I2c资源
/*****************************************fw升级用的一些属性start*********************************************************/
 fw_name = "Junda_8076d_vd807.iic";
 err = of_property_read_string(np, "cy8c242,fw-name", &fw_name);    //读取字符串属性
 if (err && (err != -EINVAL)) {
  dev_err(&client->dev, "Unable to read fw name\n");
  goto prase_dt_err; }
 if (fw_name) {
  len = strlen(fw_name);
  if (len > CY_FW_NAME_MAX_LEN - 1) {
   dev_err(&client->dev, "Invalid firmware name\n");
   goto prase_dt_err;
  }

  strlcpy(cy8ctst242_ts->fw_name, fw_name, len + 1);
 }
 err = of_property_read_u32(np, "cy8c242,fw-upgrade-id", &temp_val);
 if (err && (err!= -EINVAL)) {
  dev_err(&client->dev, "Unable to read fw upgrade id1\n");
  goto prase_dt_err;
 } else if (err!= -EINVAL)
  cy8ctst242_ts->update_fw_version=  temp_val;
/*****************************************************end**********************************************************/
 if(cy8ctst242_ts_hw_init()<0)   //初始化cy8ctst242硬件配置
  goto exit_create_singlethread;
 mutex_init(&cy8ctst242_ts->lock);  //创建互斥锁
 wake_lock_init(&cy8ctst242_ts->wake_lock, WAKE_LOCK_SUSPEND, CY8C242_NAME);  //用于初始化一个新锁,type参数指定了锁的类型  WAKE_LOCK_SUSPEND – 这种锁如果被某个task持有,那么系统将无法进入休眠   名字??!
*********************************************************************************************************************
 INIT_WORK(&cy8ctst242_ts->pen_event_work, cy8ctst242_ts_pen_irq_work);   // #define INIT_WORK(_work, _func, _data),可以理解为INIT_WORK会在你定义的_work工作队列里面增加一个工作任务,该任务就是_func。
 INIT_WORK(&cy8ctst242_ts->fw_update_work,fw_update_work);
#ifdef CY8C242_PROXIMITY
 INIT_DELAYED_WORK(&cy8ctst242_ts->delayed_work, cy8ctst242_ts_proximity_work);   // 定时器中断工作队列函数的调用  一般与schedule_delayed_work同步使用  schedule_delayed_work(&g_cy8ctst242_ts->delayed_work, msecs_to_jiffies(200));  延迟一定时间去执行一个具体的任务,功能与schedule_work类似,多了一个延迟时间,输入参数:@work_struct:具体任务对象指针  @delay:延迟时间
#endif
 cy8ctst242_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));  //用于创建workqueue,只创建一个内核线程。输入参数:  可用PS来查看创建的线程
 if (!cy8ctst242_ts->ts_workqueue) {
  err = -ESRCH;
  goto exit_create_singlethread;
 }

#ifdef CFG_DETECT_UP_EVENT
 dev_dbg(&client->dev,"%s: add up event timer \n",__func__);
 init_timer(&_st_up_evnet_timer);  //初始化结构体_st_up_evnet_timer  init_timer() 必须在其他timer相关函数执行前调用,对结构体初始化
 _st_up_evnet_timer.function = cy8ctst242_force_read_up_event;  延时结束时执行的回调函数,注意这里传递一个无符号长整型数字
 _st_up_evnet_timer.data = 1;
 _sui_last_point_cnt = 0;
 msleep(10);
#endif

 dev_dbg(&client->dev,"%s IRQ number is %d", client->name, client->irq);
 
 input_dev = input_allocate_device();  //   /*分配一个设备结构体*/  input_allocate_device()函数在内存中为输入设备结构体分配一个空间,并对其主要的成员进行了初始化.   
 if (!input_dev) {
  err = -ENOMEM;
  dev_err(&client->dev, "failed to allocate input device\n");
  goto exit_input_dev_alloc_failed;
 }

 cy8ctst242_ts->input_dev = input_dev;

/*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 start*/  产品判断
        if(get_hipad_board_id()==HIPAD_BOARD_ID_CP5217){
               screen_max_y=SCREEN_MAX_Y_CP5217;
         }else if(get_hipad_board_id()==HIPAD_BOARD_ID_CP5310){
               screen_max_y=SCREEN_MAX_Y_CP5310;
          }
/*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 end*/
   
#ifdef CONFIG_CY8CTST242_MULTITOUCH
 set_bit(EV_KEY, input_dev->evbit);    //set_bit 告诉input输入子系统支持哪些事件,哪些按键   EV_KEY: 用来描述键盘,按键或者类似键盘设备的状态变化
 set_bit(EV_ABS, input_dev->evbit);    //EV_ABS  :用来描述相对坐标轴上数值的变化,例如:描述触摸屏上坐标的值。
 //set_bit(EV_SYN, input_dev->evbit);   
 set_bit(BTN_TOUCH, input_dev->keybit);  //BTN_TOUCH : 用于触摸接触事件
 set_bit(INPUT_PROP_DIRECT, input_dev->propbit);  //INPUT_PROP_DIRECT: 特性表明设备的坐标直接和屏幕坐标向对应


 //set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
 //set_bit(ABS_MT_POSITION_X, input_dev->absbit);
 //set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
 //set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);

 //__set_bit(KEY_MENU,  input_dev->keybit);
 //__set_bit(KEY_BACK,  input_dev->keybit);
 //__set_bit(KEY_HOME,  input_dev->keybit);
 //__set_bit(KEY_SEARCH,  input_dev->keybit);

 input_set_abs_params(input_dev,
   ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
 /*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 start*/
 //input_set_abs_params(input_dev,
 //  ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
 input_set_abs_params(input_dev,
   ABS_MT_POSITION_Y, 0, screen_max_y, 0, 0);
 /*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 end*/
 input_set_abs_params(input_dev,
   ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
 input_set_abs_params(input_dev,ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);

#else
 set_bit(ABS_X, input_dev->absbit);
 set_bit(ABS_Y, input_dev->absbit);
 set_bit(ABS_PRESSURE, input_dev->absbit);
 set_bit(BTN_TOUCH, input_dev->keybit);
 set_bit(EV_ABS, input_dev->evbit);
 set_bit(EV_KEY, input_dev->evbit);

 input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
 /*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 start*/
 //input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
 input_set_abs_params(input_dev, ABS_Y, 0, screen_max_y, 0, 0);
 /*guliangzeng add for cp5217 cp5310 virtual_key  self-adaption 20140126 end*/
 input_set_abs_params(input_dev,
   ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);
#endif

 
#ifdef TOUCH_VIRTUAL_KEYS
 cy8ctst242_ts_virtual_keys_init();   //触摸屏下方的三个按键初始化
#endif
 cy8ctst242_dev_info();    //创建TP_INFO   既sys/tp_info/name
 input_dev->name  = CY8C242_TS_DEVICE;  //dev_name(&client->dev)
 err = input_register_device(input_dev);    //函数注册输入设备结构体  用getevent命令查看输入设备是否存在
 if (err) {
  dev_err(&client->dev,
    "cy8ctst242_ts_probe: failed to register input device: %s\n",
    dev_name(&client->dev));
  goto exit_input_register_device_failed;
 }
/***********************************同上********************************************
#ifdef CY8C242_PROXIMITY     
 input_proximity = input_allocate_device();
 if (!input_proximity) {
  err = -ENOMEM;
  dev_err(&client->dev, "failed to allocate input proximity\n");
  goto exit_input_dev_alloc_failed;
 }
 cy8ctst242_ts->input_proximity = input_proximity;
 input_set_abs_params(input_proximity, ABS_DISTANCE, 0, 1, 0, 0);
 set_bit(EV_ABS, input_proximity->evbit);
 input_proximity->name = "cy8c242_proximity";
 err = input_register_device(input_proximity);
 if (err) {
  dev_err(&client->dev,
    "failed to register input proximity: %s\n",
    dev_name(&client->dev));
  goto exit_input_register_device_failed;
 }
 /*make sure CTP already finish startup process */
 msleep(10);
#endif 

/*******************************************************************************

 dev_dbg(&client->dev,"==register_early_suspend =");
#if defined (CONFIG_HAS_EARLYSUSPEND)
 
 cy8ctst242_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
 cy8ctst242_ts->early_suspend.suspend = cy8ctst242_ts_suspend;
 cy8ctst242_ts->early_suspend.resume  = cy8ctst242_ts_resume;
 register_early_suspend(&cy8ctst242_ts.early_suspend);  在android系统中设定了一种特殊的电源管理模式即早期睡眠earlysuspend,他是系统进入待机的第一种状态,在android中设定了一些特殊的设备在此阶段关闭,主要是lcd及其背光。这些设备可以通过编程设定,主要实在设备的驱动程序中通过调用register_early_suspend()函数来注册。当系统在设定的空闲时间内没有任何活动事件发生时,系统就会自动进入earlysuspend状态。进入earlysuspend状态后系统会检测锁链表,看是否存在处于活动的锁,如果没有则进入挂起状态,如果有则等待。当系统进入挂起状态后,系统里的所有外设都已经处于掉电状态,这些设备挂起之前的状态都保存在内存中,当系统被设定的外中断唤醒时,这些设备均能通过设备驱动程序中已经注册的resume()函数来恢复原状态。

#endif
 msleep(10);

 err = misc_register(&cy8c242_misc_device);  misc设备在misc_register注册的时候链接到这个链表,在misc_deregister中解除链接 可以看出,这个函数首先遍历misc_list链表,查找所用的次设备号是否已经被注册,防止冲突。如果是动态次设备号则分配一个,然后调用MKDEV生成设备号,从这里可以看出所有的misc设备共享一个主设备号MISC_MAJOR,然后调用device_create,生成设备文件。最后加入到misc_list链表中。    关于device_create,class_create 作用:  class_create函数在misc.c中的模块初始化中被调用,现在一起说一下。这两个函数看起来很陌生,没有在ldd3中发现过,看源代码的时候发现class_create会调用底层组件__class_regsiter()是说明它是注册一个类。而device_create是创建一个设备,他是创建设备的便捷实现调用了device_register函数。他们都提供给linux设备模型使用,从linux内核2.6的某个版本之后,devfs不复存在,udev成为devfs的替代。相比devfs,udev有很多优势。
01.struct class *myclass = class_create(THIS_MODULE, “my_device_driver”); 
02.class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”); 
   struct class *myclass = class_create(THIS_MODULE, “my_device_driver”);
   class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “my_device”);   这样就创建了一个类和设备,模块被加载时,udev daemon就会自动在/dev下创建my_device设备文件节点。这样就省去了自己创建设备文件的麻烦。这样也有助于动态设备的管理。

 if (err < 0) {
  pr_err("Register cy8c242 misc device failed\n");
  goto err_misc_register;
 }

#ifdef CY8C242_PROXIMITY
 err = misc_register(&cy8c242_proximity_misc_device);   同上
 if (err < 0) {
  pr_err("Register cy8c242 proximity misc device failed\n");
  goto err_misc_register;
 }
#endif
#ifdef SYSFS
 //cy8ctst242_create_sysfs(client);
#endif
err = request_irq(client->irq, cy8ctst242_ts_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, cy8ctst242_ts);
在linux内核中用于申请中断的函数是request_irq(),函数原型在Kernel/irq/manage.c中定义:

int request_irq(unsigned int irq, irq_handler_t handler,
                         unsigned long irqflags, const char *devname, void *dev_id)

irq是要申请的硬件中断号。

handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。

irqflags是中断处理的属性,若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)

devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

request_irq()返回0表示成功,返回-INVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用且不能共享。

 if (err < 0) {
  dev_err(&client->dev, "cy8ctst242_probe: request irq failed\n");
  goto exit_irq_request_failed;
 }

 /* fangxiaofei modify for add cy8c242_ts 2013-11-26*/
 cy8ctst242_ts_reset();
 /* fangxiaofei modify for add cy8c242_ts 2013-11-26*/
 cy8c242_ts_del_time_sync();
 msleep(10);
 cy8c242_ts_add_time();
 err = device_create_file(&client->dev, &dev_attr_update_fw);   //添加设备属性   ????属性在那看到?  把这一句注释掉呢!
 if (err) {
  dev_err(&client->dev, "sys file creation failed\n");
  goto free_fw_update_sys;
 }
 dev_dbg(&client->dev,"%s: ==probe OK =\n",__func__);
 return 0;
   free_fw_update_sys:
exit_irq_request_failed:
     free_irq(client->irq, cy8ctst242_ts);
err_misc_register:   
exit_input_dev_alloc_failed:
exit_input_register_device_failed:
     input_free_device(input_dev);
     cancel_work_sync(&cy8ctst242_ts->pen_event_work);
     destroy_workqueue(cy8ctst242_ts->ts_workqueue);
exit_create_singlethread:
prase_dt_err: 
     i2c_set_clientdata(client, NULL);
     kfree(cy8ctst242_ts);
 g_cy8ctst242_ts=NULL;
exit_alloc_data_failed:
exit_check_functionality_failed:
     dev_err(&client->dev,"%s failed\n", __func__);
 return err;
}

 

 

 

static int cy8ctst242_ts_hw_init(void)
{
 int err = -1;
 struct common_ts_platform_data *pdata = g_cy8ctst242_ts->platform_data;
 struct i2c_client *client = g_cy8ctst242_ts->client;
 TPDBG("Cy8c242_ts cy8ctst242_ts_hw_init\n"); 
 if(pdata->power_onoff!=NULL)
  pdata->power_onoff(1);    //ic上电
 if(pdata->reset_gpio_number!= -1)
 {
  err=gpio_request(pdata->reset_gpio_number, "ts_rst");   //其原型为 int gpio_request(unsigned gpio, const char *label) 先说说其参数,gpio则为你要申请的哪一个管脚,label则是为其取一个名字。debugfs有效,一个/sys/kernel/debug/gpio文件在那里将被找到
  if(err<0)
   goto gpio_request_rst_fail;
 }
 cy8ctst242_ts_reset();  //TP reset
 if(err<0)
  goto gpio_readwrite_fail;
 if(pdata->irq_gpio_number!= -1)
 {
  err=gpio_request(pdata->irq_gpio_number,"ts_irq");  //irq命名
  if(err<0)
   goto gpio_request_irq_fail;
  gpio_direction_input(pdata->irq_gpio_number);     //可以调用gpio_direction_input和gpio_direction_output函数设置gpio输入输出方向
  client->irq = gpio_to_irq(pdata->irq_gpio_number);  //gpio_to_irq函数通过指定GPIO口映射到指定的IRQ中断号  gpio_to_irq你得到应该是irq的入口地址。
 }
 return 0;
gpio_request_irq_fail: 
gpio_readwrite_fail:
 gpio_free(pdata->reset_gpio_number);  //用户的驱动程序可调用gpio_request和gpio_free使用或释放该gpio
gpio_request_rst_fail:
 if(pdata->power_onoff!=NULL)
  pdata->power_onoff(0);
 return err;
}

 

/* heziqin modify bug for tp suspend end 2014.1.24 */
static void cy8ctst242_ts_reset(void)
{
 struct common_ts_platform_data *pdata = g_cy8ctst242_ts->platform_data;
 TPDBG("Cy8c242_ts cy8ctst242_ts_reset\n"); 
 if(pdata!=NULL && pdata->reset_gpio_number!= -1)
 {
  dev_dbg(&this_client->dev,"%s", __func__);

  gpio_direction_output(pdata->reset_gpio_number, 1);   //设置GPIO方向
  gpio_set_value(pdata->reset_gpio_number, 0);      //GPIO赋值
  msleep(1);
  gpio_set_value(pdata->reset_gpio_number, 1);
  msleep(10);
  gpio_set_value(pdata->reset_gpio_number, 0);
  msleep(100);
 }
      /*guliangzeng add for bug6114 proximity only work once 20140126 start*/
      #ifdef CY8C242_PROXIMITY
      cy8c242_proximity_set_enable(proximity_status);     //TP  距离传感势能   贴脸熄灭
      #endif
      /*guliangzeng add for bug6114 proximity only work once 20140126 end*/
}

 

 

static void cy8ctst242_ts_virtual_keys_init(void)
{
 int ret;
 struct kobject *properties_kobj;
 TPDBG("Cy8c242_ts cy8ctst242_ts_virtual_keys_init\n"); 
 properties_kobj = kobject_create_and_add("board_properties", NULL);   // kobject_create_and_add动态创建了一个kobject结构体,将其初始化,将其加入到kobject层次中,并最终返回所创建的 kobject的指针,当然如果函数执行失败,则返回NULL;在sys目录下创建board_properties文件夹
 if (properties_kobj)
  ret = sysfs_create_group(properties_kobj,  //sysfs_create_file()在kobj对应的目录下创建attr对应的属性文件  既properties_attr_group对应的 "virtualkeys.cy8c242_ts" 这个文件
    &properties_attr_group);
 if (!properties_kobj || ret)
  pr_err("failed to create board_properties\n");    
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值