驱动模块加载和卸载
module_init(flashlight_init);
module_exit(flashlight_exit);
static int __init flashlight_init(void)
{
int ret = 0;
logI("[flashlight_probe] start ~");
ret = platform_device_register (&flashlight_platform_device); // 注册设备
if (ret) {
logE("[flashlight_probe] platform_device_register fail ~");
return ret;
}
ret = platform_driver_register(&flashlight_platform_driver); // 注册驱动
if(ret){
logE("[flashlight_probe] platform_driver_register fail ~");
return ret;
}
register_low_battery_notify(&Lbat_protection_powerlimit_flash, LOW_BATTERY_PRIO_FLASHLIGHT);
register_battery_percent_notify(&bat_per_protection_powerlimit_flashlight, BATTERY_PERCENT_PRIO_FLASHLIGHT);
// register_battery_oc_notify(&bat_oc_protection_powerlimit, BATTERY_OC_PRIO_FLASHLIGHT);
logI("[flashlight_probe] done! ~");
return ret;
}
设备注册
static struct platform_device flashlight_platform_device = {
.name = FLASHLIGHT_DEVNAME, // 设备名必须与驱动名匹配
.id = 0,
.dev = {
}
};
驱动注册
static struct platform_driver flashlight_platform_driver =
{
.probe = flashlight_probe, // 探测函数
.remove = flashlight_remove,
.shutdown = flashlight_shutdown,
.driver = {
.name = FLASHLIGHT_DEVNAME,
.owner = THIS_MODULE,
},
};
#define ALLOC_DEVNO
static int flashlight_probe(struct platform_device *dev)
{
int ret = 0, err = 0;
logI("[flashlight_probe] start ~");
#ifdef ALLOC_DEVNO
ret = alloc_chrdev_region(&flashlight_devno, 0, 1, FLASHLIGHT_DEVNAME); // 动态申请字符设备
if (ret) {
logE("[flashlight_probe] alloc_chrdev_region fail: %d ~", ret);
goto flashlight_probe_error;
} else {
logI("[flashlight_probe] major: %d, minor: %d ~", MAJOR(flashlight_devno), MINOR(flashlight_devno));
}
cdev_init(&flashlight_cdev, &flashlight_fops); // 初始化设备操作集
flashlight_cdev.owner = THIS_MODULE;
err = cdev_add(&flashlight_cdev, flashlight_devno, 1); // 设备操作集链接到系统中
if (err) {
logE("[flashlight_probe] cdev_add fail: %d ~", err);
goto flashlight_probe_error;
}
#else
#define FLASHLIGHT_MAJOR 242
ret = register_chrdev(FLASHLIGHT_MAJOR, FLASHLIGHT_DEVNAME, &flashlight_fops); // 手动注册字符设备
if (ret != 0) {
logE("[flashlight_probe] Unable to register chardev on major=%d (%d) ~", FLASHLIGHT_MAJOR, ret);
return ret;
}
flashlight_devno = MKDEV(FLASHLIGHT_MAJOR, 0);
#endif
flashlight_class = class_create(THIS_MODULE, "flashlightdrv"); // 创建类节点 /sys/class/flashlightdrv
if (IS_ERR(flashlight_class)) {
logE("[flashlight_probe] Unable to create class, err = %d ~", (int)PTR_ERR(flashlight_class));
goto flashlight_probe_error;
}
flashlight_device = device_create(flashlight_class, NULL, flashlight_devno, NULL, FLASHLIGHT_DEVNAME); 注册设备节点 /dev/kd_camera_flashlight
if(NULL == flashlight_device){
logE("[flashlight_probe] device_create fail ~");
goto flashlight_probe_error;
}
//initialize members
spin_lock_init(&flashlight_private.lock); // 初始化自旋锁
init_waitqueue_head(&flashlight_private.read_wait); // 初始化等待队列
//init_MUTEX(&flashlight_private.sem);
sema_init(&flashlight_private.sem, 1); // 初始化信号量
logI("[flashlight_probe] Done ~");
return 0;
flashlight_probe_error:
#ifdef ALLOC_DEVNO
if (err == 0)
cdev_del(&flashlight_cdev);
if (ret == 0)
unregister_chrdev_region(flashlight_devno, 1);
#else
if (ret == 0)
unregister_chrdev(MAJOR(flashlight_devno), FLASHLIGHT_DEVNAME);
#endif
return -1;
}
static struct file_operations flashlight_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = flashlight_ioctl,
.open = flashlight_open,
.release = flashlight_release,
#ifdef CONFIG_COMPAT
.compat_ioctl = my_ioctl_compat,
#endif
};
static int flashlight_open(struct inode *inode, struct file *file)
{
int i4RetValue = 0;
static int bInited=0;
if(bInited==0) // 该动作执行一次
{
globalInit();
bInited=1;
}
logI("[flashlight_open] E ~");
return i4RetValue;
}
static FLASHLIGHT_FUNCTION_STRUCT *g_pFlashInitFunc[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev][e_Max_Part_Num_Per_Dev];
static int gLowBatDuty[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev];
static int g_strobePartId[e_Max_Sensor_Dev_Num][e_Max_Strobe_Num_Per_Dev];
int globalInit(void) // 初始化参数
{
int i;
int j;
int k;
logI("globalInit");
for(i=0;i<e_Max_Sensor_Dev_Num;i++)
for(j=0;j<e_Max_Strobe_Num_Per_Dev;j++)
{
gLowBatDuty[i][j]=-1;
g_strobePartId[i][j]=1;
for(k=0;k<e_Max_Part_Num_Per_Dev;k++)
{
g_pFlashInitFunc[i][j][k]=0;
}
}
return 0;
}
//上层调用底层的IOCTL接口函数操作
static long flashlight_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err;
// int dir;
err = flashlight_ioctl_core(file, cmd, arg); // 调用核心接口
//dir = _IOC_DIR(cmd);
//if(dir &_IOC_READ)
{
// copy_to_user
}
return err;
}
typedef struct
{
int sensorDev;
int strobeId;
int arg;
}kdStrobeDrvArg;
static long flashlight_ioctl_core(struct file *file, unsigned int cmd, unsigned long arg)
{
int partId;
int sensorDevIndex;
int strobeIndex;
int partIndex;
int i4RetValue = 0;
kdStrobeDrvArg kdArg;
unsigned long copyRet;
copyRet = copy_from_user(&kdArg , (void *)arg , sizeof(kdStrobeDrvArg)); // 获取上次要操作的flashlight 设备信息
logI("flashlight_ioctl cmd=0x%x(nr=%d), senorDev=0x%x ledId=0x%x arg=0x%lx",cmd, _IOC_NR(cmd), kdArg.sensorDev, kdArg.strobeId ,(unsigned long)kdArg.arg);
sensorDevIndex = getSensorDevIndex(kdArg.sensorDev); // 获得主 副摄像头
strobeIndex = getStrobeIndex(kdArg.strobeId); // 判断取值范围是否是1~2
if(sensorDevIndex<0 || strobeIndex<0 )
return -1;
partId = g_strobePartId[sensorDevIndex][strobeIndex]; // flashlight_open初始化默认是1
partIndex = getPartIndex(partId); // 取值范围是否符合1~2
if(partIndex<0)
return -1;
switch(cmd)
{
case FLASH_IOC_GET_PROTOCOL_VERSION:
i4RetValue=1;
break;
case FLASH_IOC_IS_LOW_POWER: // 上报低电量值1给上层
logI("FLASH_IOC_IS_LOW_POWER");
{
int isLow=0;
if(gLowPowerPer!=BATTERY_PERCENT_LEVEL_0 || gLowPowerVbat!=LOW_BATTERY_LEVEL_0 )
isLow=1;
logI("FLASH_IOC_IS_LOW_POWER %d %d %d",gLowPowerPer,gLowPowerVbat,isLow);
kdArg.arg = isLow;
if(copy_to_user((void __user *) arg , (void*)&kdArg , sizeof(kdStrobeDrvArg)))
{
logE("[FLASH_IOC_IS_LOW_POWER] ioctl copy to user failed ~");
return -EFAULT;
}
}
break;
case FLASH_IOC_LOW_POWER_DETECT_START: // 开始检测低电量
logI("FLASH_IOC_LOW_POWER_DETECT_START");
gLowBatDuty[sensorDevIndex][strobeIndex]=kdArg.arg;
break;
case FLASH_IOC_LOW_POWER_DETECT_END: // 设置当前低电量检测结束标志
logI("FLASH_IOC_LOW_POWER_DETECT_END");
gLowBatDuty[sensorDevIndex][strobeIndex]=-1;
break;
case FLASHLIGHTIOC_X_SET_DRIVER: // 根据上层传下来的设备信息,执行flashlight的open函数,并且获得对应闪光灯的操作函数集地址
i4RetValue = setFlashDrv(kdArg.sensorDev, kdArg.strobeId);
break;
case FLASH_IOC_GET_PART_ID:
case FLASH_IOC_GET_MAIN_PART_ID:
case FLASH_IOC_GET_SUB_PART_ID:
case FLASH_IOC_GET_MAIN2_PART_ID:
{
int partId;
partId = strobe_getPartId(kdArg.sensorDev, kdArg.strobeId);
g_strobePartId[sensorDevIndex][strobeIndex]=partId; // 判断是不是前后摄像头,若是的话返回1,否则返回100;
kdArg.arg = partId;
if(copy_to_user((void __user *) arg , (void*)&kdArg , sizeof(kdStrobeDrvArg)))
{
logE("[FLASH_IOC_GET_PART_ID] ioctl copy to user failed ~");
return -EFAULT;
}
logI("FLASH_IOC_GET_PART_ID line=%d partId=%d",__LINE__,partId);
}
break;
case FLASH_IOC_SET_ONOFF:
{
FLASHLIGHT_FUNCTION_STRUCT *pF;
pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
if(pF!=0)
{
kicker_pbm_by_flash(kdArg.arg);
i4RetValue = pF->flashlight_ioctl(cmd,kdArg.arg); //设置闪光的constant_flashlight_ioctl函数
}
else
{
logE("[FLASH_IOC_SET_ONOFF] function pointer is wrong -");
}
}
break;
case FLASH_IOC_UNINIT:
{
FLASHLIGHT_FUNCTION_STRUCT *pF;
pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
if(pF!=0)
{
i4RetValue = pF->flashlight_release((void*)0); //调用对应的constant_flashlight_release函数
pF=0;
}
else
{
logE("[FLASH_IOC_UNINIT] function pointer is wrong ~");
}
}
break;
default :
{
FLASHLIGHT_FUNCTION_STRUCT *pF;
pF = g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex];
if(pF!=0)
{
i4RetValue = pF->flashlight_ioctl(cmd,kdArg.arg); //设置闪光的constant_flashlight_ioctl函数
}
else
{
logE("[default] function pointer is wrong ~");
}
}
break;
}
return i4RetValue;
}
// 执行对应闪光灯芯片驱动的open 函数接口
static int setFlashDrv(int sensorDev, int strobeId)
{
int partId;
int sensorDevIndex;
int strobeIndex;
int partIndex;
FLASHLIGHT_FUNCTION_STRUCT** ppF=0;
sensorDevIndex = getSensorDevIndex(sensorDev);
strobeIndex = getStrobeIndex(strobeId);
if(sensorDevIndex<0 || strobeIndex<0 )
return -1;
partId = g_strobePartId[sensorDevIndex][strobeIndex];
partIndex = getPartIndex(partId);
if(partIndex<0)
return -1;
logI("setFlashDrv sensorDev=%d, strobeId=%d, partId=%d ~",sensorDev, strobeId, partId);
ppF = &g_pFlashInitFunc[sensorDevIndex][strobeIndex][partIndex]; // 函数集地址
if(sensorDev==e_CAMERA_MAIN_SENSOR) // 根据主副摄像头获得前闪光灯与后闪光灯的操作函数地址
{
#if defined(DUMMY_FLASHLIGHT)
strobeInit_dummy(ppF);
#else
if(strobeId==1)
{
if(partId==1)
constantFlashlightInit(ppF); // 获取函数地址
else if(partId==2)
strobeInit_main_sid1_part2(ppF);
}
else if(strobeId==2)
{
if(partId==1)
strobeInit_main_sid2_part1(ppF);
else if(partId==2)
strobeInit_main_sid2_part2(ppF);
}
#endif
}
else if(sensorDev==e_CAMERA_SUB_SENSOR)
{
if(strobeId==1)
{
if(partId==1)
subStrobeInit(ppF);
else if(partId==2)
strobeInit_sub_sid1_part2(ppF);
}
else if(strobeId==2)
{
if(partId==1)
strobeInit_sub_sid2_part1(ppF);
else if(partId==2)
strobeInit_sub_sid2_part2(ppF);
}
}
if((*ppF)!=0)
{
(*ppF)->flashlight_open(0); // 执行对应函数 constant_flashlight_open
logI("setFlashDrv ok %d",__LINE__);
}
else
{
logE("set function pointer not found!!");
return -1;
}
return 0;
}
下面我们来看看IOCTL中调用的几个接口函数。
FLASHLIGHT_FUNCTION_STRUCT constantFlashlightFunc=
{
constant_flashlight_open,
constant_flashlight_release,
constant_flashlight_ioctl
};
MUINT32 constantFlashlightInit(PFLASHLIGHT_FUNCTION_STRUCT *pfFunc)
{
if (pfFunc != NULL)
{
*pfFunc = &constantFlashlightFunc;
}
return 0;
}
static int constant_flashlight_open(void *pArg)
{
int i4RetValue = 0;
PK_DBG("constant_flashlight_open line=%d\n", __LINE__);
if (0 == strobe_Res) //全局静态变量, strobe_Res=0
{
FL_Init(); // 初始化闪光灯对应的IC寄存器
timerInit(); // 初始化工作队列,定时1s钟关闭闪光灯
}
PK_DBG("constant_flashlight_open line=%d\n", __LINE__);
spin_lock_irq(&g_strobeSMPLock);
if(strobe_Res) // 判断闪光灯是否是第一次打开
{
PK_ERR(" busy!\n");
i4RetValue = -EBUSY;
}
else //
{
strobe_Res += 1;
}
spin_unlock_irq(&g_strobeSMPLock);
PK_DBG("constant_flashlight_open line=%d\n", __LINE__);
return i4RetValue;
}
static int constant_flashlight_release(void *pArg)
{
PK_DBG(" constant_flashlight_release\n");
if (strobe_Res) // 若闪光灯已经打开,就关闭闪光灯
{
spin_lock_irq(&g_strobeSMPLock);
strobe_Res = 0; // 复位打开闪光灯标志位
spin_unlock_irq(&g_strobeSMPLock);
FL_Uninit(); // 关闭闪光灯 -->FL_Disable 设置闪光灯IC寄存器关闭灯
}
PK_DBG(" Done\n");
return 0;
}
static int constant_flashlight_ioctl(unsigned int cmd, unsigned long arg)
{
int i4RetValue = 0;
int ior_shift;
int iow_shift;
int iowr_shift;
ior_shift = cmd - (_IOR(FLASHLIGHT_MAGIC,0, int));
iow_shift = cmd - (_IOW(FLASHLIGHT_MAGIC,0, int));
iowr_shift = cmd - (_IOWR(FLASHLIGHT_MAGIC,0, int));
PK_DBG("LM3642 constant_flashlight_ioctl() line=%d ior_shift=%d, iow_shift=%d iowr_shift=%d arg=%d\n",__LINE__, ior_shift, iow_shift, iowr_shift,(int)arg);
switch(cmd)
{
case FLASH_IOC_SET_TIME_OUT_TIME_MS: // 设置闪光灯打开超时时间
PK_DBG("FLASH_IOC_SET_TIME_OUT_TIME_MS: %d\n",(int)arg);
g_timeOutTimeMs=arg;
break;
case FLASH_IOC_SET_DUTY : // 设置闪光灯的模式 比如 打闪 手电筒 预闪模式等
PK_DBG("FLASHLIGHT_DUTY: %d\n",(int)arg);
FL_dim_duty(arg); // 设置duty值
break;
case FLASH_IOC_SET_STEP:
PK_DBG("FLASH_IOC_SET_STEP: %d\n",(int)arg);
break;
case FLASH_IOC_SET_ONOFF : // 设置闪关灯的打开与关闭
PK_DBG("FLASHLIGHT_ONOFF: %d\n",(int)arg);
if(arg==1)
{
int s;
int ms;
if(g_timeOutTimeMs>1000)
{
s = g_timeOutTimeMs/1000;
ms = g_timeOutTimeMs - s*1000;
}
else
{
s = 0;
ms = g_timeOutTimeMs;
}
if(g_timeOutTimeMs!=0) // 根据设置的超时时间启动定时器,如超过超时时间关闭闪光灯
{ //控制闪关灯打开时间小于1s
ktime_t ktime;
ktime = ktime_set( s, ms*1000000 );
hrtimer_start( &g_timeOutTimer, ktime, HRTIMER_MODE_REL );
}
FL_Enable(); // 打开是闪光灯 根据duty值使能不同模式的闪光灯
}
else
{
FL_Disable(); // 关闭是闪光灯
hrtimer_cancel( &g_timeOutTimer ); // 关闭定时器
}
break;
default :
PK_DBG(" No such command \n");
i4RetValue = -EPERM;
break;
}
return i4RetValue;
}
由于平台使用的flashlight为LM3642,因此针对这个芯片我们来看看它的打开与关闭闪光灯以及控制不同模式的闪光灯。比如,预闪 手电筒 主闪等模式。
int FL_Enable(void)
{
char buf[2];
// char bufR[2];
if(g_duty<0) // 设置duty值范围
g_duty=0;
else if(g_duty>16)
g_duty=16;
if(g_duty<=2) // 根据duty值设置不同闪关灯效果
{
int val;
if(g_bLtVersion==1)
{
if(g_duty==0)
val=3;
else if(g_duty==1)
val=5;
else //if(g_duty==2)
val=7;
}
else
{
if(g_duty==0)
val=1;
else if(g_duty==1)
val=2;
else //if(g_duty==2)
val=3;
}
buf[0]=9;
buf[1]=val<<4;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
buf[0]=10;
buf[1]=0x02;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
}
else
{
int val;
val = (g_duty-1);
buf[0]=9;
buf[1]=val;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
buf[0]=10;
buf[1]=0x03;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
}
PK_DBG(" FL_Enable line=%d\n",__LINE__);
readReg(0);
readReg(1);
readReg(6);
readReg(8);
readReg(9);
readReg(0xa);
readReg(0xb);
return 0;
}
// 关闭闪光灯
int FL_Disable(void)
{
char buf[2];
buf[0]=10;
buf[1]=0x00;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
PK_DBG(" FL_Disable line=%d\n",__LINE__);
return 0;
}
// 设置不同的duty值
int FL_dim_duty(kal_uint32 duty)
{
PK_DBG(" FL_dim_duty line=%d\n",__LINE__);
g_duty = duty;
return 0;
}
// 初始化LM3642寄存器
int FL_Init(void)
{
int regVal0;
char buf[2];
buf[0]=0xa;
buf[1]=0x0;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
buf[0]=0x8;
buf[1]=0x47;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
buf[0]=9;
buf[1]=0x35;
//iWriteRegI2C(buf , 2, STROBE_DEVICE_ID);
LM3642_write_reg(LM3642_i2c_client, buf[0], buf[1]);
//static int LM3642_read_reg(struct i2c_client *client, u8 reg)
//regVal0 = readReg(0);
regVal0 = LM3642_read_reg(LM3642_i2c_client, 0);
if(regVal0==1)
g_bLtVersion=1;
else
g_bLtVersion=0;
PK_DBG(" FL_Init regVal0=%d isLtVer=%d\n",regVal0, g_bLtVersion);
/*
if(mt_set_gpio_mode(FLASH_GPIO_ENT,GPIO_MODE_00)){PK_DBG("[constant_flashlight] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(FLASH_GPIO_ENT,GPIO_DIR_OUT)){PK_DBG("[constant_flashlight] set gpio dir failed!! \n");}
if(mt_set_gpio_out(FLASH_GPIO_ENT,GPIO_OUT_ZERO)){PK_DBG("[constant_flashlight] set gpio failed!! \n");}
if(mt_set_gpio_mode(FLASH_GPIO_ENF,GPIO_MODE_00)){PK_DBG("[constant_flashlight] set gpio mode failed!! \n");}
if(mt_set_gpio_dir(FLASH_GPIO_ENF,GPIO_DIR_OUT)){PK_DBG("[constant_flashlight] set gpio dir failed!! \n");}
if(mt_set_gpio_out(FLASH_GPIO_ENF,GPIO_OUT_ZERO)){PK_DBG("[constant_flashlight] set gpio failed!! \n");}
*/
PK_DBG(" FL_Init line=%d\n",__LINE__);
return 0;
}
// 取消闪光灯
int FL_Uninit(void)
{
FL_Disable();
return 0;
}
``
mtk平台闪光灯流程分析
最新推荐文章于 2023-10-11 17:04:01 发布