【问题标题】:How can a callback function be executed within a driver on linux?如何在 linux 的驱动程序中执行回调函数?
【发布时间】:2022-01-14 11:57:14
【问题描述】:

我必须修改在 linux 上运行的驱动程序以添加从外部应用程序调用的回调函数。我已经实现了代码,但是当它在计算机启动时执行时,系统出错并被阻止。

这是我在驱动端的新代码:

typedef void (*callbackFunctionNoParams) ();

typedef struct T_EXI_CONFIGURE_BUS_
{
    T_mode mode;
    unsigned short NumeroRT;
    T_SA_Enable SA_Enable;
    unsigned short MINOR_CYCLE;
    callbackFunctionNoParams callback;

} T_EXI_CONFIGURE_BUS;

typedef struct PciExiDev_
{
   /**
    * It represents a char device to read/write
    */
   struct cdev charDevice;
   /**
    * IRQ assigned
    */
   unsigned int irq;

   /**
    * Callback function to be invoked
    */

   callbackFunctionNoParams callback;

   /**
    * Device control block
    */
   EXI_DCB theDCB;
} PciExiDev;

驱动端执行代码:

static long exi_ioctl( struct file * filep, unsigned int cmd, unsigned long arg )
{
   PciExiDev * aPciExiDev = (PciExiDev *) filep->private_data;

   int result = SUCCESS;
   int i, j;
   long ret = 0;
   //printk("Ioctl received %d.\n",cmd);
   switch( cmd )
   {
      case FIO_EXI_CONFIGURE_BUS:
      {
         T_EXI_CONFIGURE_BUS config;
        T_LISTA_TRANS *auxTrans1, *auxTrans2;
        T_TRANSACTION_DCB *transDCB1;
         T_OPI opi;
         T_EXIS exis;
         unsigned short dato;
         unsigned short datolong[2];
         unsigned short ControlBlock[12];
//       printk("Exi configure bus initiated.\n");
         printk("TNB. Exi ioctl CONFIGURE BUS.\n");

         copy_from_user( &config, (T_EXI_CONFIGURE_BUS *) arg, sizeof(T_EXI_CONFIGURE_BUS) );

         LeerDatos( &aPciExiDev->theDCB, OPI_ADDRESS, 1, (unsigned short *) &opi, 1 );

         aPciExiDev->callback = config.callback;
         aPciExiDev->theDCB.modo = config.mode;
         aPciExiDev->theDCB.CicloMenor = config.MINOR_CYCLE;
         
         (*aPciExiDev->callback)();

...

客户端的新代码:

   if( theHWConfiguration.existExi() )
   {
      T_EXI_CONFIGURE_BUS bus_config;

      // Configura la tarjega exi en modo Bus Controller.
      bus_config.mode = BC;
      bus_config.NumeroRT = 28;
      bus_config.MINOR_CYCLE = 20;
      bus_config.callback = &bcInterruptHandler2;
      status = ioctl( A_fd_exi, FIO_EXI_CONFIGURE_BUS, reinterpret_cast<long>( &bus_config ) );
   }
   return status;
}

void C_EXI::bcInterruptHandler2()
{
   std::cout<< "bcInterruptHandler2" << endl;
}

这是执行代码的结果:

Crash Image

如果有人可以帮助我或提出另一种方法,我将不胜感激。

【问题讨论】:

  • 您是否尝试从内核空间调用用户空间函数?
  • 能否请您提供其中一个 cmets 的翻译?
  • 是的@GauravPathak,为了更好地描述场景;我们有一个与驱动程序通信的应用程序,目前仅在那个方向上进行通信,但是由于新的要求,现在,当驱动程序端发生某些事件时,它必须通知应用程序;我曾认为回调函数会是解决方案,但它会使操作系统崩溃。你能想出另一种从驱动程序到应用程序的通信方式吗?

标签: c linux callback kernel driver


【解决方案1】:

您的callback 必须在内核空间运行,然后您将其写入std::cout。在浏览您的代码时,它表明内核模式地址空间和用户侧进程地址空间之间存在冲突。这意味着如果callback函数是在用户端声明的,而是在内核空间中调用,就会出现错误。

【讨论】:

  • 好的,BKN,我明白你说的问题了;无论如何,最终代码不会有 std::cout,这只是一个测试,但我看到测试是错误的。感谢您的回答,我将更改代码并重试
【解决方案2】:

崩溃图像表明在您的代码中某处您尝试访问的指针无效。恐怕我无法用提供的小上下文调试你的代码,但我可以给你一些建议:

  • 在绝对必要之前尽量避免强制转换。
  • 当您转换为指针时,请仔细检查这是否正是您需要做的。
  • 在错误消息中还有调用堆栈:查看它以确定错误在哪里。
  • 您只需在代码中添加一些 printk("%p", pointer) 即可调试变量的内容。

【讨论】:

  • 感谢您的回答米格尔;我已经看到测试错误了,我将审查代码并重试。问候。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-28
  • 2021-07-23
  • 2018-03-19
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多