include <linux/kernel.h>
include <linux/module.h>
include <linux/device.h>
include <linux/notifier.h>
include <linux/fs.h>
include <linux/slab.h>
include <linux/init.h>
include <linux/list.h>
include <linux/jiffies.h>
include <linux/uaccess.h>
include <linux/gpio.h>
include <linux/platform_device.h>
include <linux/of_gpio.h>
include <linux/irq.h>
include <linux/poll.h>
include <linux/interrupt.h>
include <linux/delay.h>
include <linux/gpio/consumer.h>
include <linux/gpio/driver.h>
include <linux/gpio.h>
include <linux/sched.h>
include <linux/kthread.h>
include <linux/delay.h>
include <linux/unistd.h>
include <linux/hrtimer.h>
include “version.h”
include “usr_debug.h”
include “iomanager.h”
include “usr_io.h”
define DRIVER_DESC “iomanager”
define DRIVER_VER “0.0.1”
define DEAULT_OUTPUT_VALUE 0
define TRIG_OUT_NUMBER 1
define DEVICE_NAME “iomanager”
define CLASS_NAME DEVICE_NAME
define IRQ_NAME “usr_gpio_in_irq”
define IRQ_DLP_NAME “dlp_trig_out_irq”
static struct gpio_inout_dev *gdev;
static struct fasync_struct *share_async;
static IO_INPUT_FLAG triggerPin = 0; //触发管脚
static ktime_t g_ktime_on, g_ktime_off;
static int g_pwm_count = 0;
static int g_pwm_target_count = 1; // 任意个方波
static int led_blink_ms = 100;
module_param(led_blink_ms, int, 0644);
MODULE_PARM_DESC(led_blink_ms, “led or beep duration in ms:100~500”);
static int trig_pulse_us= 150;
module_param(trig_pulse_us, int, 0644);
MODULE_PARM_DESC(trig_pulse_us, “trig_pulse_us:”);
static int flash_allowed=1;
module_param(flash_allowed, int, 0644);
MODULE_PARM_DESC(flash_allowed, “flash_allowed:0=disabled,1=enabled”);
static const struct of_device_id of_gpio_manager_match = {
{ .compatible = "gpio-iomanager", },
{}
};
MODULE_DEVICE_TABLE(of, of_gpio_manager_match);
//static unsigned int irqNum = 0;
// static u8 dlp1_num = 0;
// static u8 dlp2_num = 0;
// static u8 dlp3_num = 0;
// static u8 dlp4_num = 0;
// static void signalHandlerTrig(IO_INPUT_FLAG triggerPin)
// {
// static uint num=0;
// if(num==32){
// num=0;
// }
// num++;
// sss++;
// if(0 == (irqNum % 800))
// {
// printk(“signalHandlerTrig %d\n”,irqNum);
// }
// switch(triggerPin)
// {
// case IO_DLP_1:
// if(num>8){
// printk(“IO_DLP_1 TRIGE ERROR %d %d\n”, num, irqNum);
// }
// dlp1_num++;
// if(8<=dlp1_num)
// {
// dlp1_num = 0;
// kill_fasync(&share_async, SIGIO, POLLIN);
// }
// break;
// case IO_DLP_2:
// if(num<9 || num>16){
// printk(“IO_DLP_2 TRIGE ERROR %d %d\n”, num, irqNum);
// }
// dlp2_num++;
// if(8<=dlp2_num)
// {
// dlp2_num = 0;
// kill_fasync(&share_async, SIGIO, POLLIN);
// }
// break;
// case IO_DLP_3:
// if(num<17 || num>24){
// printk(“IO_DLP_3 TRIGE ERROR %d %d\n”, num, irqNum);
// }
// dlp3_num++;
// if(8<=dlp3_num)
// {
// dlp3_num = 0;
// kill_fasync(&share_async, SIGIO, POLLIN);
// }
// break;
// case IO_DLP_4:
// if(num<25){
// printk(“IO_DLP_4 TRIGE ERROR %d %d\n”, num, irqNum);
// }
// dlp4_num++;
// if(8<=dlp4_num)
// {
// dlp4_num = 0;
// kill_fasync(&share_async, SIGIO, POLLIN);
// }
// break;
// default:
// break;
// }
// return;
// }
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
//bool isDlp = false;
//bool idExt2D = false;
struct gpio_inout_dev *data;
bool gpioValue;
disable_irq_nosync(irq);
data = dev_id;
if(irq == data->irq_nums[2])
{
gpioValue = gpiod_get_value(gdev->input_gpios->desc[IO_DLP_1]);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], gpioValue?1:0);
}
else if(irq == data->irq_nums[3])
{
gpioValue = gpiod_get_value(gdev->input_gpios->desc[IO_DLP_2]);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], gpioValue?1:0);
}
else if(irq == data->irq_nums[4])
{
gpioValue = gpiod_get_value(gdev->input_gpios->desc[IO_DLP_3]);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], gpioValue?1:0);
}
else if(irq == data->irq_nums[5])
{
gpioValue = gpiod_get_value(gdev->input_gpios->desc[IO_DLP_4]);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], gpioValue?1:0);
}
else if(irq == data->irq_nums[6])
{
triggerPin = CAM_TOUT_0;
}
else if(irq == data->irq_nums[7])
{
triggerPin = CAM_TOUT_1;
}
else if(irq == data->irq_nums[8])
{
triggerPin = CAM_TOUT_2;
}
else if(irq == data->irq_nums[0])
{
triggerPin = IO_INPUT_1;//外部2D输入
if(1 == gdev->wq_2D->light_param.mode)
{
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 1);
usleep_range(gdev->wq_2D->light_param.modeParam.exterConfig.ext_xtrig_expo, \
gdev->wq_2D->light_param.modeParam.exterConfig.ext_xtrig_expo + TRIG_OUT_PULSE_US_JIT);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 0);
}
kill_fasync(&share_async, SIGIO, POLLIN);
}
else if(irq == data->irq_nums[1])
{
triggerPin = IO_INPUT_2;
kill_fasync(&share_async, SIGIO, POLLIN);
}
// #if 1
// if(false == isDlp)
// kill_fasync(&share_async, SIGIO, POLLIN);
// #else
// gdev->wq[0].param.outState = 1;
// gdev->wq[0].param.defaultState = 0;
// gdev->wq[0].param.holdTime = 600;
// gdev->wq[0].thread_flag = 1;
// wake_up(&gdev->wq[0].waitQueue);
// endif
enable_irq(irq);
return IRQ_HANDLED;
}
static int iomanager_fasync(int fd,struct file *pfile,int on)
{
return fasync_helper(fd,pfile,on, &share_async);
}
static int iomanager_open(struct inode *inode,struct file *file)
{
return 0;
}
static ssize_t iomanager_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
{
return 0;
}
static ssize_t iomanager_write(struct file *file, const char __user *buf,size_t count, loff_t *offset)
{
return 0;
}
static int iomanager_release(struct inode *inode,struct file *file)
{
return 0;
}
int set_io_output_square_wave(void *mData) //
{
IO_PLUSE_SET *data = (IO_PLUSE_SET *)mData;
vc_info(gdev->dev, “index:%d outState:%d defaultState:%d holdTime:%d\n”, data->index, data->outState, data->defaultState, data->holdTime);
if(0 == data->holdTime)
{
gpiod_set_value(gdev->output_gpios->desc[data->index], data->outState);
}
else
{
vc_info(gdev->dev, “data->holdTime:%d\r\n”, data->holdTime);
gpiod_set_value(gdev->output_gpios->desc[data->index], data->outState);
usleep_range(data->holdTime, data->holdTime + TRIG_OUT_PULSE_US_JIT);
gpiod_set_value(gdev->output_gpios->desc[data->index], data->defaultState);
}
return 0;
}
int set_io_led_flash(void *mData) //
{
unsigned int us;
u8 times;
IO_FLASH_SET *data = (IO_FLASH_SET *)mData;
u8 loop_index;
vc_info(gdev->dev, “index:%d times:%d period:%d \n”, data->index, data->times, data->period);
us = data->period*1000;
times = data->times;
times = times>10 ? 10 : times;
if(0 == us)
{
gpiod_set_value(gdev->flash_gpios->desc[data->index], 1);
return 0;
}
for(loop_index=0;loop_index<times;loop_index++)
{
vc_info(gdev->dev, “-------%d\n”, loop_index);
gpiod_set_value(gdev->flash_gpios->desc[data->index], 1);
usleep_range(us, us + TRIG_OUT_PULSE_US_JIT);
gpiod_set_value(gdev->flash_gpios->desc[data->index], 0);
usleep_range(us, us + TRIG_OUT_PULSE_US_JIT);
}
return 0;
}
static int my_led_flash_fn(void *data)
{
WORK_STRUCT *ws = (WORK_STRUCT*)data;
while (!kthread_should_stop()) {
wait_event_interruptible(ws->waitQueue, ws->thread_flag || kthread_should_stop());
if (kthread_should_stop())
break;
set_io_led_flash(&ws->flash_param);
ws->thread_flag = 0; // 清除标志位
}
return 0;
}
static void rgb_set_led_pin(struct gpio_descs *gpios, u8 states)
{
uint8_t i = 0;
for(i=0;i<4;i++)
{
if(states & (1<<i))
{
gpiod_set_value(gpios->desc[i], (0 != (states & (1<<(i+4))))?1:0);
}
}
}
enum hrtimer_restart pwm_timer_callback(struct hrtimer *timer)
{
static bool state = false;
// gpio_set_value(gpio_pin, state);
// printk(“g_pwm_count:%d set pin %d states:0x%x\r\n”, g_pwm_count, state, gdev->wq_rgb->rgb_param.states[g_pwm_count>>1]);
if(false == state)
{
//拉高xtrig
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 1);
rgb_set_led_pin(gdev->rgb_gpios, gdev->wq_rgb->rgb_param.states[g_pwm_count>>1]);
}
else if(true == state)
{
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 0);
rgb_set_led_pin(gdev->rgb_gpios, 0x0f);
}
state = !state;
if (++g_pwm_count >= g_pwm_target_count * 2)
return HRTIMER_NORESTART;
hrtimer_forward_now(timer, state ? g_ktime_on : g_ktime_off);
return HRTIMER_RESTART;
}
enum hrtimer_restart expo_sync_timer_callback(struct hrtimer *timer)
{
static bool state = false;
// printk(“g_pwm_count:%d state:%d \n”, g_pwm_count, state);
if(false == state)//上升沿
{
gpiod_set_value(gdev->output_gpios->desc[IO_SET_OUT_SYNC], 1);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 1);
}
else if(true == state)//下降沿
{
gpiod_set_value(gdev->output_gpios->desc[IO_SET_OUT_SYNC], 0);
gpiod_set_value(gdev->output_gpios->desc[CAM_XTRIG_1], 0);
}
state = !state;
if (++g_pwm_count >= g_pwm_target_count * 2)
return HRTIMER_NORESTART;
hrtimer_forward_now(timer, state ? g_ktime_on : g_ktime_off);
return HRTIMER_RESTART;
}
void setUsrPwmFunc(USR_PWM_TIMER *param)
{
static struct hrtimer pwm_timer;
g_ktime_on = ktime_set(0, (param->pulseTime) * 1000);
g_ktime_off = ktime_set(0, (param->periodTime - param->pulseTime) * 1000);
g_pwm_target_count = param->count;
g_pwm_count = 0;
hrtimer_init(&pwm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pwm_timer.function = param->callBack;
hrtimer_start(&pwm_timer, ktime_set(0, 0), HRTIMER_MODE_REL); // 从高电平开始
}
static int my_rgb_flash_fn(void *data)
{
WORK_STRUCT *ws = (WORK_STRUCT *)data;
USR_PWM_TIMER usrTime;
while (!kthread_should_stop()) {
wait_event_interruptible(ws->waitQueue, ws->thread_flag || kthread_should_stop());
if (kthread_should_stop())
break;
// printk(“num:%d\r\n”, ws->rgb_param.num);
// printk(“exposureTime:%d \r\n”, ws->rgb_param.exposureTime);
// printk(“periodTime:%d \r\n”, ws->rgb_param.periodTime);
// printk(“0x%x 0x%x 0x%x 0x%x \r\n”, ws->rgb_param.states[0], ws->rgb_param.states[1], ws->rgb_param.states[2], ws->rgb_param.states[3]);
if(ws->rgb_param.exposureTime >= ws->rgb_param.periodTime)
{
ws->thread_flag = 0; // 清除标志位
return -1;
}
usrTime.pulseTime = ws->rgb_param.exposureTime;
usrTime.periodTime = ws->rgb_param.periodTime;
usrTime.count = ws->rgb_param.num;
usrTime.callBack = pwm_timer_callback;
setUsrPwmFunc(&usrTime);
ws->thread_flag = 0; // 清除标志位
}
return 0;
}
static int my_2d_exposure_fn(void *data)
{
WORK_STRUCT *ws = (WORK_STRUCT *)data;
INTERNAL_CONFIG *interConf;
EXTERNAL_CONFIG *exterConf;
USR_PWM_TIMER usrTime;
while (!kthread_should_stop()) {
wait_event_interruptible(ws->waitQueue, ws->thread_flag || kthread_should_stop());
if (kthread_should_stop())
break;
if(0 == ws->light_param.mode)
{
interConf = &ws->light_param.modeParam.interConfig;
// printk(“sync_num:%d \n”, interConf->sync_num);
// printk(“sync_expo:%d \n”, interConf->sync_expo);
// printk(“sync_period:%d \n”, interConf->sync_period);
usrTime.pulseTime = interConf->sync_expo;
usrTime.periodTime = interConf->sync_period;
usrTime.count = interConf->sync_num;
usrTime.callBack = expo_sync_timer_callback;
setUsrPwmFunc(&usrTime);
}
else if(1 == ws->light_param.mode)
{
exterConf = &ws->light_param.modeParam.exterConfig;
// printk(“ext_in_2d_mode:%d \n”, exterConf->ext_in_2d_mode);
// printk(“ext_sync_expo:%d \n”, exterConf->ext_sync_expo);
// printk(“ext_xtrig_expo:%d \n”, exterConf->ext_xtrig_expo);
gpiod_set_value(gdev->output_gpios->desc[IO_SET_OUT_SYNC], 1); //输出一个脉冲
usleep_range(exterConf->ext_sync_expo, exterConf->ext_sync_expo + TRIG_OUT_PULSE_US_JIT);
gpiod_set_value(gdev->output_gpios->desc[IO_SET_OUT_SYNC], 0);
irq_set_irq_type(gdev->irq_nums[IO_INPUT_1], (0 == exterConf->ext_in_2d_mode)? IRQ_TYPE_EDGE_RISING: IRQ_TYPE_EDGE_FALLING);//等待外部的脉冲输入
}
ws->thread_flag = 0; // 清除标志位
}
return 0;
}
static int my_thread_fn(void *data) //脉冲输出的线程
{
WORK_STRUCT *ws = (WORK_STRUCT *)data;
while (!kthread_should_stop()) {
wait_event_interruptible(ws->waitQueue, ws->thread_flag || kthread_should_stop());
if (kthread_should_stop())
break;
set_io_output_square_wave(&ws->param);
ws->thread_flag = 0; // 清除标志位
}
return 0;
}
// static void
static long iomanager_ioctl(struct file *fp,unsigned int cmd,unsigned long arg)
{
u8 index = 0;
IO_FLASH_SET mIoFlashSet;
IO_PLUSE_SET mIoPluseSet;
IO_RGB_SET mRgbSet;
SET_IO_TRIGGER_TYPE ioTrigType;
IO_2D_SUPPORT_LIGHT_PARAM *lightParam = &gdev->wq_2D->light_param;
u8 dlpStatus = 0;
int ret = 0;
switch (cmd)
{
case IO_GET_TRIGGER_PIN:
return triggerPin;
break;
case IO_GET_PIN_STATUS:
if (copy_from_user(&index, (u8*)arg, sizeof(u8)))
return -EINVAL;
vc_info(gdev->dev, “index:%d \n”, index);
if(index <= gdev->num_id)
return gpiod_get_value(gdev->id_gpios->desc[index]);
return -1;
break;
case IO_TEST:
// vc_info(gdev->dev, “test\n”);
break;
case IO_SET_OUT:
if (copy_from_user(&mIoPluseSet, (struct IO_PLUSE_SET *)arg, sizeof(IO_PLUSE_SET)))
return -EINVAL;
index = mIoPluseSet.index;
if(index >= gdev->num_outputs)
{
vc_err(gdev->dev, “set IO_SET_OUT index:%d cross %d\n”, index, gdev->num_outputs);
return -EINVAL;
}
memcpy(&gdev->wq[index].param, &mIoPluseSet, sizeof(IO_PLUSE_SET));
gdev->wq[index].thread_flag = 1;
wake_up(&gdev->wq[index].waitQueue);
break;
case IO_SET_FLASH_LED:
if (copy_from_user(&mIoFlashSet, (struct IO_FLASH_SET *)arg, sizeof(IO_FLASH_SET)))
return -EINVAL;
index = mIoFlashSet.index;
if (index > gdev->num_flash) // 避免越界访问
return -EINVAL;
memcpy(&gdev->wq_flash[index].flash_param, &mIoFlashSet, sizeof(mIoFlashSet));
gdev->wq_flash[index].thread_flag = 1;
wake_up(&gdev->wq_flash[index].waitQueue);
break;
case IO_SET_DLP_STATUS:
if (copy_from_user(&dlpStatus, (u8 *)arg, sizeof(u8)))
return -EINVAL;
vc_info(gdev->dev, “dlpStatus:%d \n”, dlpStatus);
gpiod_set_value(gdev->dlp_gpios->desc[0], dlpStatus);
break;
case IO_SET_RGB_PARAM:
if (copy_from_user(&mRgbSet, (struct IO_RGB_SET *)arg, sizeof(mRgbSet)))
return -EINVAL;
vc_info(gdev->dev, “mRgbSet.num:%d \n”, mRgbSet.num);
memcpy(&gdev->wq_rgb->rgb_param, &mRgbSet, sizeof(mRgbSet));
gdev->wq_rgb->thread_flag = 1;
wake_up(&gdev->wq_rgb->waitQueue);
break;
case IO_SET_IO_TRIGGER_PARAM:
if (copy_from_user(&ioTrigType, (struct SET_IO_TRIGGER_TYPE *)arg, sizeof(SET_IO_TRIGGER_TYPE)))
return -EINVAL;
vc_info(gdev->dev, “ioTrigType.num:%d ioTrigType.\n”, ioTrigType.num, ioTrigType.trigType);
if(IO_INPUT_2 < ioTrigType.num)
{
return -1;
}
ret = irq_set_irq_type(gdev->irq_nums[ioTrigType.num], (0 == ioTrigType.trigType)? IRQ_TYPE_EDGE_RISING: IRQ_TYPE_EDGE_FALLING); // 动态切换为双沿
if(0 != ret)
{
vc_err(gdev->dev, “irq_set_irq_type set ret:%d \n”, ret);
return -2;
}
break;
case IO_2D_SET_MODE_PARAM:
if (copy_from_user(lightParam, (struct IO_2D_SUPPORT_LIGHT_PARAM *)arg, sizeof(IO_2D_SUPPORT_LIGHT_PARAM)))
return -EINVAL;
// if(0 == lightParam->mode) //debug调试
// {
// vc_info(gdev->dev, “sync_num:%d \n”, lightParam->modeParam.interConfig.sync_num);
// vc_info(gdev->dev, “sync_expo:%d \n”, lightParam->modeParam.interConfig.sync_expo);
// vc_info(gdev->dev, “sync_period:%d \n”, lightParam->modeParam.interConfig.sync_period);
// }
// else
// {
// vc_info(gdev->dev, “ext_in_2d_mode:%d \n”, lightParam->modeParam.exterConfig.ext_in_2d_mode);
// vc_info(gdev->dev, “ext_sync_expo:%d \n”, lightParam->modeParam.exterConfig.ext_sync_expo);
// vc_info(gdev->dev, “ext_xtrig_expo:%d \n”, lightParam->modeParam.exterConfig.ext_xtrig_expo);
// }
gdev->wq_2D->thread_flag = 1;
wake_up(&gdev->wq_2D->waitQueue);
break;
default:
break;
}
return 0;
}
static const struct file_operations iomanager_fops = {
.owner = THIS_MODULE,
.open = iomanager_open,
.read = iomanager_read,
.write = iomanager_write,
.fasync = iomanager_fasync,
.release= iomanager_release,
.unlocked_ioctl = iomanager_ioctl,
};
static int iomanager_probe(struct platform_device *pdev)
{
int i = 0;
int ret = 0;
char thread_name[10]={0};
struct device *dev = &pdev->dev;
u8 index = 0;
dev_info(dev, “branch:%s %s time:%s\n”, GIT_BRANCH, GIT_COMMIT, PROGRAM_DATE);
//dev_err(dev,“1111111111111\n”);
gdev = devm_kzalloc(dev, sizeof(struct gpio_inout_dev), GFP_KERNEL);
if (!gdev)
return -ENOMEM;
gdev->dlp_gpios = devm_gpiod_get_array(dev, “dlp”, GPIOD_OUT_HIGH);
if (IS_ERR(gdev->dlp_gpios))
return PTR_ERR(gdev->dlp_gpios);
gdev->num_dlp = gdev->dlp_gpios->ndescs;
vc_info(dev, “gdev->num_dlp:%d \r\n”, gdev->num_dlp);
gdev->input_gpios = devm_gpiod_get_array(dev, “input”, GPIOD_IN);
if (IS_ERR(gdev->input_gpios))
return PTR_ERR(gdev->input_gpios);
gdev->num_inputs = gdev->input_gpios->ndescs;
vc_info(dev, “gdev->num_inputs:%d \r\n”, gdev->num_inputs);
gdev->id_gpios = devm_gpiod_get_array(dev, “id”, GPIOD_IN);
if (IS_ERR(gdev->id_gpios))
return PTR_ERR(gdev->id_gpios);
gdev->num_id = gdev->id_gpios->ndescs;
vc_info(dev, “gdev->num_id:%d \r\n”, gdev->num_id);
gdev->output_gpios = devm_gpiod_get_array(dev, “output”, GPIOD_OUT_LOW);
if (IS_ERR(gdev->output_gpios))
return PTR_ERR(gdev->output_gpios);
gdev->num_outputs = gdev->output_gpios->ndescs;
vc_info(dev, “gdev->num_outputs:%d \r\n”, gdev->num_outputs);
//配置XTRIGx管脚为高电平
index = gdev->num_outputs;
// gpiod_set_value(gdev->output_gpios->desc[index-1], 1);
// gpiod_set_value(gdev->output_gpios->desc[index-2], 1);
gdev->flash_gpios = devm_gpiod_get_array(dev, “flash”, GPIOD_OUT_LOW);
if (IS_ERR(gdev->flash_gpios))
{
vc_err(dev, “gdev->flash_gpios get error \r\n”);
return PTR_ERR(gdev->flash_gpios);
}
gdev->num_flash = gdev->flash_gpios->ndescs;
vc_info(dev, “gdev->num_flash:%d \r\n”, gdev->num_flash);
//dev_err(dev,“1111111111111\n”);
//获取rgb的管脚信息
gdev->rgb_gpios = devm_gpiod_get_array(dev, “rgb”, GPIOD_OUT_LOW);
if (IS_ERR(gdev->rgb_gpios))
{
vc_err(dev, “gdev->rgb_gpios get error \r\n”);
return PTR_ERR(gdev->rgb_gpios);
}
gdev->num_rgb = gdev->rgb_gpios->ndescs;
vc_info(dev, “gdev->num_rgb:%d \r\n”, gdev->num_rgb);
//dev_err(dev,“1111111111111\n”);
//申请一个rgb闪烁的消息队列
gdev->wq_rgb = devm_kzalloc(dev, sizeof(WORK_STRUCT), GFP_KERNEL);
if (!gdev->wq_rgb)
return -ENOMEM;
init_waitqueue_head(&gdev->wq_rgb->waitQueue);
snprintf(thread_name, sizeof(thread_name), “rgb_0”);
gdev->wq_rgb->res_value = 0;
gdev->wq_rgb->thread = kthread_run(my_rgb_flash_fn, gdev->wq_rgb, thread_name);
//dev_err(dev,“1111111111111\n”);
//申请一个2D曝光模式的消息队列
gdev->wq_2D = devm_kzalloc(dev, sizeof(WORK_STRUCT), GFP_KERNEL);
if (!gdev->wq_2D)
return -ENOMEM;
init_waitqueue_head(&gdev->wq_2D->waitQueue);
snprintf(thread_name, sizeof(thread_name), “2D_expo”);
gdev->wq_2D->res_value = 0;
gdev->wq_2D->thread = kthread_run(my_2d_exposure_fn, gdev->wq_2D, thread_name);
//dev_err(dev,“1111111111111\n”);
//申请led闪烁消息队列
gdev->wq_flash = devm_kzalloc(dev, sizeof(WORK_STRUCT) * gdev->num_flash, GFP_KERNEL);
if (!gdev->wq_flash)
return -ENOMEM;
for (i = 0; i < gdev->num_flash; i++) { //对常驻内核线程的声明
init_waitqueue_head(&gdev->wq_flash[i].waitQueue);
snprintf(thread_name, sizeof(thread_name), “flash_%d”, i);
gdev->wq_flash[i].res_value = i;
gdev->wq_flash[i].thread = kthread_run(my_led_flash_fn, &gdev->wq_flash[i], thread_name);
}
//dev_err(dev,“1111111111111\n”);
//申请输出配置消息队列
gdev->wq = devm_kzalloc(dev, sizeof(WORK_STRUCT) * gdev->num_outputs, GFP_KERNEL);
if (!gdev->wq)
return -ENOMEM;
for (i = 0; i < gdev->num_outputs; i++) { //对常驻内核线程的声明
init_waitqueue_head(&gdev->wq[i].waitQueue);
snprintf(thread_name, sizeof(thread_name), “td_%d”, i);
gdev->wq[i].res_value = i;
gdev->wq[i].thread = kthread_run(my_thread_fn, &gdev->wq[i], thread_name);
}
//dev_err(dev,“1111111111111\n”);
// 申请中断
gdev->irq_nums = devm_kzalloc(dev, sizeof(int) * gdev->num_inputs, GFP_KERNEL);
if (!gdev->irq_nums)
return -ENOMEM;
for (i = 0; i < gdev->num_inputs; i++)
{
gdev->irq_nums[i] = gpiod_to_irq(gdev->input_gpios->desc[i]);
vc_info(dev, “gdev->irq_nums[%d]:%d\n”, i, gdev->irq_nums[i]);
if (gdev->irq_nums[i] < 0)
{
dev_err(dev, “Failed to get IRQ for gdev->irq_nums[%d]:%d \n”, i, gdev->irq_nums[i]);
return gdev->irq_nums[i];
}
if (i < 2)
{
ret = devm_request_irq(dev, gdev->irq_nums[i], gpio_irq_handler,
IRQF_ONESHOT | IRQF_TRIGGER_RISING, IRQ_NAME, gdev);
}
else if( i < (gdev->num_inputs - 3))
{
ret = devm_request_irq(dev, gdev->irq_nums[i], gpio_irq_handler, \
IRQF_ONESHOT|IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, IRQ_NAME, gdev);
}
else
{
ret = devm_request_irq(dev, gdev->irq_nums[i], gpio_irq_handler, \
IRQF_ONESHOT|IRQF_TRIGGER_RISING, IRQ_NAME, gdev);
}
if (ret)
{
dev_err(dev, “Failed to request IRQ for input[%d]\n”, i);
return ret;
}
}
// dev_err(dev,“1111111111111\n”);
gdev->major = register_chrdev(0,DEVICE_NAME,&iomanager_fops);
//dev_err(dev,“1111111111111\n”);
gdev->gpio_manager_class = class_create(THIS_MODULE, DEVICE_NAME);
//dev_err(dev,“1111111111111\n”);
gdev->gpio_manager_dev = device_create(gdev->gpio_manager_class, NULL, MKDEV(gdev->major, 0), NULL, DEVICE_NAME);
//dev_err(dev,“1111111111111\n”);
platform_set_drvdata(pdev, gdev);
//dev_err(dev,“1111111111111\n”);
vc_info(dev, “probe success\n”);
dev_err(dev,“1111111111111\n”);
return 0;
}
static int iomanager_remove(struct platform_device *pdev)
{
struct gpio_inout_dev *mdev = platform_get_drvdata(pdev);
unregister_chrdev(mdev->major,DEVICE_NAME);
device_unregister(mdev->gpio_manager_dev);
class_destroy(mdev->gpio_manager_class);
//dev_err(mdev->dev, “1111111111111\n”);
return 0;
}
static struct platform_driver of_gpio_manager_driver = {
.probe = iomanager_probe,
.remove = iomanager_remove,
.driver = {
.name = DEVICE_NAME,
.of_match_table = of_gpio_manager_match,
},
};
module_platform_driver(of_gpio_manager_driver);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Bopixel,yz”);
MODULE_DESCRIPTION(DRIVER_DESC);
This is my driver. Is there any problem?