歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux字符設備驅動之register_chrdev_region()系列

Linux字符設備驅動之register_chrdev_region()系列

日期:2017/3/1 10:20:50   编辑:Linux編程

1.內核中所有已分配的字符設備編號都記錄在一個名為 chrdevs 散列表裡。該散列表中的每一個元素是一個 char_device_struct 結構,它的定義如下:

static struct char_device_struct {

struct char_device_struct *next; // 指向散列沖突鏈表中的下一個元素的指針

unsigned int major; // 主設備號

unsigned int baseminor; // 起始次設備號

int minorct; // 設備編號的范圍大小

char name[64]; // 處理該設備編號范圍內的設備驅動的名稱

struct file_operations *fops;

struct cdev *cdev; // 指向字符設備驅動程序描述符的指針

} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

1>內核並不是為每一個字符設備編號定義一個 char_device_struct 結構,而是為一組對應同一個字符設備驅動的設備編號范圍定義一個 char_device_struct 結構。chrdevs 散列表的大小是 255,散列算法是把每組字符設備編號范圍的主設備號以 255 取模插入相應的散列桶中。同一個散列桶中的字符設備編號范圍是按起始次設備號遞增排序的。

2.注冊

內核提供了三個函數來注冊一組字符設備編號,這三個函數分別是 register_chrdev_region()、alloc_chrdev_region() 和

register_chrdev()。這三個函數都會調用一個共用的

__register_chrdev_region() 函數來注冊一組設備編號范圍(即一個 char_device_struct 結構)。

1>int register_chrdev_region(dev_t from, unsigned count, const char *name)

from :要分配的設備編號范圍的初始值(次設備號常設為0);

Count:連續編號范圍.

name:編號相關聯的設備名稱. (/proc/devices);

2>動態分配:

int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

firstminor是請求的最小的次編號;

count是請求的連續設備編號的總數;

name為設備名,返回值小於0表示分配失敗。

然後通過major=MMOR(dev)獲取主設備號

3>釋放:

Void unregist_chrdev_region(dev_t first,unsigned int count);

調用Documentation/devices.txt中能夠找到已分配的設備號.

3.__register_chrdev_region() 函數的實現代碼

/*

84 * Register a single major with a specified minor range.

85 *

86 * If major == 0 this functions will dynamically allocate a major and return

87 * its number.

88 *

89 * If major > 0 this function will attempt to reserve the passed range of

90 * minors and will return zero on success.

91 *

92 * Returns a -ve errno on failure.

93 */

94static struct char_device_struct *

95__register_chrdev_region(unsigned int major, unsigned int baseminor,

96 int minorct, const char *name)

97{

98 struct char_device_struct *cd, **cp;

99 int ret = 0;

100 int i;

101

102 cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);

103 if (cd == NULL)

104 return ERR_PTR(-ENOMEM);

105

106 mutex_lock(&chrdevs_lock);

107

108 /* temporary */

109 if (major == 0) {

110 for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {

111 if (chrdevs[i] == NULL)

112 break;

113 }

114

115 if (i == 0) {

116 ret = -EBUSY;

117 goto out;

118 }

119 major = i;

120 ret = major;

121 }

122

123 cd->major = major;

124 cd->baseminor = baseminor;

125 cd->minorct = minorct;

126 strlcpy(cd->name, name, sizeof(cd->name));

127

128 i = major_to_index(major);

129

130 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)

131 if ((*cp)->major > major ||

132 ((*cp)->major == major &&

133 (((*cp)->baseminor >= baseminor) ||

134 ((*cp)->baseminor + (*cp)->minorct > baseminor))))

135 break;

136

137 /* Check for overlapping minor ranges. */

138 if (*cp && (*cp)->major == major) {

139 int old_min = (*cp)->baseminor;

140 int old_max = (*cp)->baseminor + (*cp)->minorct - 1;

141 int new_min = baseminor;

142 int new_max = baseminor + minorct - 1;

143

144 /* New driver overlaps from the left. */

145 if (new_max >= old_min && new_max <= old_max) {

146 ret = -EBUSY;

147 goto out;

148 }

149

150 /* New driver overlaps from the right. */

151 if (new_min <= old_max && new_min >= old_min) {

152 ret = -EBUSY;

153 goto out;

154 }

155 }

156

157 cd->next = *cp;

158 *cp = cd;

159 mutex_unlock(&chrdevs_lock);

160 return cd;

161out:

162 mutex_unlock(&chrdevs_lock);

163 kfree(cd);

164 return ERR_PTR(ret);

165}

Copyright © Linux教程網 All Rights Reserved