Insmod iomanager.ko

bp@tegra-ubuntu:~$ sudo insmod iomanager.ko
[ 1634.576137] iomanager gpio-iomanager: 1111111111111
bp@tegra-ubuntu:~$ [ 1634.579370] tegra194-vi5 13e00000.host1x:vi0@15c00000: syncpt fops register failed, defer probe
[ 1634.579944] tegra194-vi5 13e00000.host1x:vi1@14c00000: syncpt fops register failed, defer probe

When I implant the iomanager.ko driver into the system of the Orin nx 16GB development board, these lines of errors appeared, where did my problem occur, and how should I solve it?

hello HoweWW,

you may check the kernel version, please make sure you’re using the same kernel version.
please check the kernel version by running the command uname -r .
BTW, please refer to developer guide, Building the NVIDIA Out-of-Tree Modules.

I found that when I initially compiled the module, I had configured the real-time kernel.

export IGNORE_PREEMPT_RT_PRESENCE=1

export CROSS_COMPILE=/home/howe/l4t-gcc/aarch64–glibc–stable-2022.08-1/bin/aarch64-buildroot-linux-gnu-

export KERNEL_HEADERS=$PWD/kernel/kernel-jammy-src

make modules

Later, I revised it to look like this

export IGNORE_PREEMPT_RT_PRESENCE=0

Then I recompiled the kernel, modules, device tree, finally flashed the machine, and copied the .ko driver directly to the /Linux_for_Tegra/rootfs/home/bp/ directory, and it still displayed this after flashing again

[sudo] password for bp:
[ 176.180517] iomanager gpio-iomanager: 1111111111111
[ 176.185656] tegra194-vi5 13e00000.host1x:vi0@15c00000: syncpt fops register failed, defer probe
[ 176.186059] tegra194-vi5 13e00000.host1x:vi1@14c00000: syncpt fops register failed, defer probe

What should I do ?Please help me ,thank you.

hello HoweWW,

may I know what exactly is this driver? are you trying to operate with the VI/CSI drivers?

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?

hello HoweWW,

please see-also developer guide, Using the Pins in GPIO Mode.
you may check with gpiod for pin controls.