container_of()的替代品

时间:2011-03-29 07:32:34

标签: c linux linux-device-driver

我是一个新手试图编写一个串行驱动程序(基于PCI),我不想使用container_of()缺乏向下兼容性。内核版本我可能编译模块 将是< 2.6.x所以我想让它与大多数旧版本和新版本兼容。

我想访问串行卡驱动程序的结构成员。该结构是一个包含原子变量的自定义结构 - 例如use_count及其相关操作 - atomic_inc(&serial_card->use_count)。我不想要使用container_of()函数访问它们,这将给我包含结构 是否有任何替代container_of()函数。如果我没错,Allesandro Roubini的文本LINux设备驱动程序描述了第174页的方法。第6章:高级字符驱动程序操作。 但我仍然知道如何分配像struct scull_dev *dev = &scull_s_device这样的东西。 如果结构本身包含类型为struct pc_device *dev的变量,则上述语句将填充一个类似的变量并分配给dev,

在我的情况下,我已经声明了一个结构和相关的功能,如下所示

struct serial_card
{
  unsigned int      id;     // to identify the each card
  //atomic_t        use_count;      //  variable used to check whether the device is already opened or not  
  wait_queue_head_t rx_queue[64];   // queue in which the process are stored
  unsigned int      data_ready[64]; //  queue in which  the process is ready 
  unsigned int      rx_chan;    // used by interrupt handler 
  unsigned int      base, len; // holds physical base address , holds the total area ( for each card )
  unsigned int      *base;      // holds virtual address 
  /*struct cdev     cdev;           //  kernel uses this structure to represent the EACH char device 
 not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/

  struct pci_dev        *device;    // pci_dev structure for EACH device.
  //struct semaphore    sem;        //Semaphore needed to handle the co-ordination of processes,use incase need arises
};

static struct serial_card *serial_cards;    // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file


static int serialcard_open(struct inode *inode,struct file *filep)
{

  //getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev

  //struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);

  // read the current value of use_count

  static int Device_Open = 0;
  if ( Device_Open )            //Device_Open is static varibale used here for checking the no of times a device is opened
  {
    printk("cPCIserial: Open attempt rejected\n");
    return -EBUSY;
  }
  Device_Open++;


  // using the card so increment use_count
  //atomic_inc(&serial_cards->use_count);
  //filep->private_data = serial_cards;

  return 0;
}

第174-175页的完整说明如下

  

单开设备

     

提供访问控制的强力方法是允许设备打开   一次只有一个过程(单一开放)。这种技术最好避免因为它   抑制用户的聪明才智。用户可能希望在同一个上运行不同的进程   设备,一个读取状态信息,另一个是写入数据。在某些情况下,   用户可以通过shell脚本运行一些简单的程序来完成很多工作   只要他们可以同时访问设备。换句话说,实现单一开放   行为相当于创建策略,这可能会阻碍你的行为   用户想要做的。仅允许单个进程打开设备具有不良属性,但它也是实现设备驱动程序的最简单的访问控制,因此在此处显示。   源代码是从名为scullsingle的设备中提取的。

scullsingle设备维护一个名为scull_s_available的atomic_t变量;那 变量初始化为值1,表示设备确实可用。 open调用减少并测试scull_s_available并拒绝访问(如果有人) 否则已打开设备:

static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
  struct scull_dev *dev = &scull_s_device; /* device information */
  if (! atomic_dec_and_test (&scull_s_available)) {
    atomic_inc(&scull_s_available);
    return -EBUSY; /* already open */
  }

  /* then, everything else is copied from the bare scull device */
  if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
    scull_trim(dev);
    filp->private_data = dev;
    return 0; /* success */
  }

另一方面,释放呼叫标志着设备不再忙碌:

static int scull_s_release(struct inode *inode, struct file *filp)
{
  atomic_inc(&scull_s_available); /* release the device */
  return 0;
}

通常,我们建议您将开放标志scull_s_available放在 device structure (Scull_Dev here)因为从概念上讲,它属于设备。该 但是,scull驱动程序使用独立变量来保存标志,以便它可以使用相同的标记 设备结构和方法作为裸sc设备并最小化代码重复。

请告诉我任何替代方案

感谢和问候

4 个答案:

答案 0 :(得分:3)

也许我错过了这一点,但“cotainer_of”不是一个函数,而是一个宏。如果您有移植问题,如果系统头没有实现,您可以安全地定义它。这是一个基本的实现:

#ifndef container_of
#define container_of(ptr, type, member) \
 ((type *)                              \
   (  ((char *)(ptr))                   \
    - ((char *)(&((type*)0)->member)) ))

#endif

或者这里的实现 - 更准确 - 来自最近的linux标题:

#define container_of(ptr, type, member) ({ \
                const typeof( ((type *)0)->member ) *__mptr = (ptr); 
                (type *)( (char *)__mptr - offsetof(type,member) );})

答案 1 :(得分:2)

在该代码中,containerof用于轻松存储和检索正确的dev结构。在读取和写入函数内部也可以检索正确的结构,而无需访问private_data。 我不知道为什么你不想使用private-> data和containerof,但是你总是可以从struct文件指针中检索你的次要号码。

int minor=MINOR(filp->f_dentry_d_inode->i__rdev);

然后使用类似

的内容访问您的多个设备矢量
struct scull_dev* dev = &scull_devices[minor]:

并使用它。

答案 2 :(得分:0)

您需要使用filp-> privatedata来存储您在读/写中也使用的“每次打开”信息。您需要确定要存储的内容以确保提供正确的信息。

可能你想要两个结构。一个“设备结构”和一个“开放结构”。开放结构可以“打开”动态分配并存储在private_data中。在发布中,它被释放。它应该有成员,以便您可以在读/写中使用它们来访问您需要的数据。

设备结构将按照“卡”进行。在你的驱动程序init中,你可能想要循环卡的数量并为每个卡创建一个新的设备结构(serial_card)。你可以使它们成为静态数组,或者动态分配,这没关系。我也会将次要号码存储在结构中。次要号码由您选择,因此从1开始并通过#cards。如果需要,可以为系统级接口保留“0”,或者从卡片的0开始。

在打开时,您将获得用户打开的次要号码。浏览您的serial_card列表以查找匹配项。如果您没有找到它,则错误打开。否则,您有自己的信息,可以使用它来分配“开放结构”,填充它,并将其存储在filp-> private_data中。

答案 3 :(得分:0)

@Giuseppe Guerrini有些编译器无法识别container_of的linux实现。 基本定义很好,但我想知道在这个实现中是否存在任何安全性或兼容性风险:

 #ifndef container_of
#define container_of(ptr, type, member) \
 ((type *)                              \
   (  ((char *)(ptr))                   \
    - ((char *)(&((type*)0)->member)) ))

#endif