开发者

alternative to container_of()

开发者 https://www.devze.com 2023-02-20 16:15 出处:网络
I am a newbie trying to code a serial driver(PCI based ) and I don\'t want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module

I am a newbie trying to code a serial driver(PCI based ) and I don't want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module would be < 2.6.x so I want to make it compatible with most of the old and new versions.

i want to access the structure member(s) of a serial card driver.the structure is a custom one containing the atomic variable for example - use_count and the related operation on it-- atomic_inc(&serial_card->use_count).I dont want to access them by using the container_of() function which will give me the containing structure Is there any alternate to container_of() function.If I am not wrong the text LINux device drivers by Allesandro Roubini describes a way on page no 174 | Chapter 6: Advanced Char Driver Operations. But I am still fixed about how to assign something like struct scull_dev *dev = &scull_s_device. if the structure itself contains a variable of type struct pc_device *dev,the above statement populates a similar variable and that is assigned to dev,

in my case i have declared a structure and related function as below

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;
}

the complete description on page 174 - 175 is as follows

Single-Open Devices

The brute-force way to provide access control is to permit a device to be opened by only one process at a time (single openness). This technique is best avoided be开发者_如何学编程cause it inhibits user ingenuity. A user might want to run different processes on the same device, one reading status information while the other is writing data. In some cases, users can get a lot done by running a few simple programs through a shell script, as long as they can access the device concurrently. In other words, implementing a singleopen behavior amounts to creating policy, which may get in the way of what your users want to do. Allowing only a single process to open a device has undesirable properties, but it is also the easiest access control to implement for a device driver, so it’s shown here. The source code is extracted from a device called scullsingle.

The scullsingle device maintains an atomic_t variable called scull_s_available; that variable is initialized to a value of one, indicating that the device is indeed available. The open call decrements and tests scull_s_available and refuses access if somebody else already has the device open:

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 */
  }

The release call, on the other hand, marks the device as no longer busy:

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

Normally, we recommend that you put the open flag scull_s_available within the device structure (Scull_Dev here) because, conceptually, it belongs to the device. The scull driver, however, uses standalone variables to hold the flag so it can use the same device structure and methods as the bare scull device and minimize code duplication.

Please let me know any alternative for this

thanks and regards


perhaps I am missing the point, but "cotainer_of" is not a function, but a macro. If you have porting concerns, you can safely define it by yourserlf if the system headers don't implement it. Here a basic implementation:

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

#endif

Or here's the implementation - more accurate - from recent linux headers:

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


In that code the containerof is used to store and retrieve the correct dev structure easily. The correct structure can be retrieved inside the read and write functions also without accessing to the private_data. I do not know why you do not want to use private->data and containerof, but you can always retrieve your minor number from the struct file pointer.

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

then accessing to your multiple devices vector using something like

struct scull_dev* dev = &scull_devices[minor]:

and using it.


You will need to use filp->privatedata to store "per-open" information that you also use in read/write. You will need to decide what to store to ensure that the right information is available.

Probably you want two structures. One "device structure" and one "open structure". The open structure can get dynamically allocated in "open" and stored at private_data. In release, it gets freed. It should have the members such that you can use them in read/write to get access to the data you need.

The device structure is going to be per "card". In your driver init, you probably want to loop on the number of cards and create a new device structure (serial_card) for each. You can make them a static array, or dynamically allocate, it doesn't matter. I would store the minor number in the structure as well. The minor number is chosen by you, so start with 1 and go through #cards. You can reserve "0" for a system level interface, if you want, or just start at 0 for the cards.

In open, you will get the minor number that the user opened. Go through your serial_card list looking for a match. If you don't find it, error out of open. Otherwise, you have your info and can use it to allocate a "open structure", populate it, and store it in filp->private_data.


@Giuseppe Guerrini Some compiler just cannot recognize the linux implementation of container_of. The basic define is fine, but I wonder if there is any safety or compatibility risk at this implementation:

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

#endif
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号