這年頭情侶一多,黃瓜就不好賣了. –- 北大門口賣水果的小販回憶2005
開源社群的家夥大概都是光棍,因為他們展現給我們的不是情侶多,而是變态的資料結構多.尤其我們這一節裡要經曆的變态資料結構更是多,基本上這些變态的資料結構都聚集到了這一節,所謂物以類聚吧.這麼一堆變态的資料結構,要是寫部落格的是譚浩強,估計你看了就崩潰了,也虧了是我在寫.平心而論,經曆了畢業這兩年來的種種挫折之後,尤其是兩次求職的那冷暖自知的種種辛酸之後,有些東西我也算是看得比較透了,寫代碼的這群混蛋們就是唯恐天下不亂,每寫一個子產品就給我們引進一堆複雜的資料結構,仿佛他們的理念就是,男人,就是要對别人狠一點.沒辦法,哥們兒也是因為沒錢,迫于生計才學Linux,有錢了我才不會來看這無聊的代碼呢,如果我要中500萬,除了爹媽不換,剩下全換!
usb_create_hcd的第一個參數struct hc_driver,這個結構體掀開了我們對usb host controller driver的認識,它來自drivers/usb/core/hcd.h:
149 struct hc_driver {
150 const char *description;
151 const char *product_desc;
152 size_t hcd_priv_size;
153
154
155 irqreturn_t (*irq) (struct usb_hcd *hcd);
156
157 int flags;
158 #define HCD_MEMORY 0x0001
159 #define HCD_USB11 0x0010
160 #define HCD_USB2 0x0020
161
162
163 int (*reset) (struct usb_hcd *hcd);
164 int (*start) (struct usb_hcd *hcd);
165
166
169
170 int (*suspend) (struct usb_hcd *hcd, pm_message_t message);
171
172
173 int (*resume) (struct usb_hcd *hcd);
174
175
176 void (*stop) (struct usb_hcd *hcd);
177
178
179 void (*shutdown) (struct usb_hcd *hcd);
180
181
182 int (*get_frame_number) (struct usb_hcd *hcd);
183
184
185 int (*urb_enqueue) (struct usb_hcd *hcd,
186 struct usb_host_endpoint *ep,
187 struct urb *urb,
188 gfp_t mem_flags);
189 int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
190
191
192 void (*endpoint_disable)(struct usb_hcd *hcd,
193 struct usb_host_endpoint *ep);
194
195
196 int (*hub_status_data) (struct usb_hcd *hcd, char *buf);
197 int (*hub_control) (struct usb_hcd *hcd,
198 u16 typeReq, u16 wValue, u16 wIndex,
199 char *buf, u16 wLength);
200 int (*bus_suspend)(struct usb_hcd *);
201 int (*bus_resume)(struct usb_hcd *);
202 int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
203 void (*hub_irq_enable)(struct usb_hcd *);
204
205 };
說句良心話,你說這麼長的一個結構體你要我怎麼看?現在制藥的都知道要制良心藥,你們這些寫代碼的就不能寫良心代碼?算了,先不看這個結構體的細節了,反正吧,每個hcd都得對應這麼一個結構體變量.比如咱們的uhci,在drivers/usb/host/uhci-hcd中就有這麼一段:
862 static const char hcd_name[] = "uhci_hcd";
863
864 static const struct hc_driver uhci_driver = {
865 .description = hcd_name,
866 .product_desc = "UHCI Host Controller",
867 .hcd_priv_size = sizeof(struct uhci_hcd),
868
869
870 .irq = uhci_irq,
871 .flags = HCD_USB11,
872
873
874 .reset = uhci_init,
875 .start = uhci_start,
876 #ifdef CONFIG_PM
877 .suspend = uhci_suspend,
878 .resume = uhci_resume,
879 .bus_suspend = uhci_rh_suspend,
880 .bus_resume = uhci_rh_resume,
881 #endif
882 .stop = uhci_stop,
883
884 .urb_enqueue = uhci_urb_enqueue,
885 .urb_dequeue = uhci_urb_dequeue,
886
887 .endpoint_disable = uhci_hcd_endpoint_disable,
888 .get_frame_number = uhci_hcd_get_frame_number,
889
890 .hub_status_data = uhci_hub_status_data,
891 .hub_control = uhci_hub_control,
892 };
其實就是一堆亂七八糟的指針,也沒什麼了不起.不過我得提醒你了,在咱們整個故事中也就隻有一個struct hc_driver變量,就是這一個uhci_driver,以後凡是提到hc_driver,指的就是uhci_driver.不過你說這個probe函數咋知道的?probe函數是pci那邊的接口,而hc_driver是usb這邊的接口,這兩概念咋扯到一塊去了呢?呵呵, usb_hcd_pci_probe函數67行,看見沒有,driver在這裡被指派了,而等号右邊那個id->driver_data又是什麼?繼續回去看,在uhci_pci_ids這張表裡寫得很清楚,driver_data就是被指派為&uhci_driver,是以說一切都是有因才有果的,不會無緣無故的出現一個變量.說到因果,就好比你問我”沒房沒老婆”是什麼關系,我就隻能告訴你三十歲以前是并列關系,三十歲以後是因果關系.
繼續看,1496行,一個變态的資料結構還不夠,還得來一個更變态的.struct usb_hcd,這意思很明确,有一個hcd就得有這麼一個結構體,也是來自drivers/usb/core/hcd.h:
47
48
49
55
56
57
58 struct usb_hcd {
59
60
63 struct usb_bus self;
64 struct kref kref;
65
66 const char *product_desc;
67 char irq_descr[24];
68
69 struct timer_list rh_timer;
70 struct urb *status_urb;
71 #ifdef CONFIG_PM
72 struct work_struct wakeup_work;
73 #endif
74
75
78 const struct hc_driver *driver;
79
80
81 unsigned long flags;
82 #define HCD_FLAG_HW_ACCESSIBLE 0x00000001
83 #define HCD_FLAG_SAW_IRQ 0x00000002
84
85 unsigned rh_registered:1;
86
87
89 unsigned uses_new_polling:1;
90 unsigned poll_rh:1;
91 unsigned poll_pending:1;
92 unsigned wireless:1;
93
94 int irq;
95 void __iomem *regs;
96 u64 rsrc_start;
97 u64 rsrc_len;
98 unsigned power_budget;
99
100 #define HCD_BUFFER_POOLS 4
101 struct dma_pool *pool [HCD_BUFFER_POOLS];
102
103 int state;
104 # define __ACTIVE 0x01
105 # define __SUSPEND 0x04
106 # define __TRANSIENT 0x80
107
108 # define HC_STATE_HALT 0
109 # define HC_STATE_RUNNING (__ACTIVE)
110 # define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
111 # define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
112 # define HC_STATE_SUSPENDED (__SUSPEND)
113
114 #define HC_IS_RUNNING(state) ((state) & __ACTIVE)
115 #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)
116
117
122
123
126 unsigned long hcd_priv[0]
127 __attribute__ ((aligned (sizeof(unsigned long))));
128 };
是以usb_create_hcd這個函數就是為struct usb_hcd申請記憶體空間,并且初始化.我們來看它具體如何初始化的.
1498行是申請記憶體,并且初值為0.
接下來你得注意了,usb_create_hcd中的dev可是struct device結構體指針,而剛才的usb_hcd_pci_probe中的dev是struct pci_dev結構體指針,struct pci_dev雖然我們沒說,但也該知道,表示的就是一個pci裝置,它有一個成員struct device dev,是以實際上我們看到我們在調用usb_create_hcd的時候第二個參數是&dev->dev.而這裡1503行這個dev_set_drvdata就是一簡單的内聯函數,來自include/linux/device.h:
491 static inline void
492 dev_set_drvdata (struct device *dev, void *data)
493 {
494 dev->driver_data = data;
495 }
struct device這個結構體中有一個成員void *driver_data,是以在我們這裡,其效果就是令dev->driver_data等于咱們這裡申請好的hcd.
而1504行就是初始化一個引用計數,struct usb_hcd也不是白貼出來了,至少我們可以看到它有一個成員struct kref kref,這玩藝說白了就是一個引用計數的變量.
1506行,我不知道該說什麼了,反正我也貼出來了,你也看到了,struct usb_hcd中有一個成員struct usb_bus self,我們說了一個主機控制器就意味着一條總線,是以這裡又出來另一個結構體,struct usb_bus,
273
276 struct usb_bus {
277 struct device *controller;
278 int busnum;
279 char *bus_name;
280 u8 uses_dma;
281 u8 otg_port;
282 unsigned is_b_host:1;
283 unsigned b_hnp_enable:1;
284
285 int devnum_next;
287
288 struct usb_devmap devmap;
289 struct usb_device *root_hub;
290 struct list_head bus_list;
291
292 int bandwidth_allocated;
299 int bandwidth_int_reqs;
300 int bandwidth_isoc_reqs;
301
302 #ifdef CONFIG_USB_DEVICEFS
303 struct dentry *usbfs_dentry;
304 #endif
305 struct class_device *class_dev;
306
307 #if defined(CONFIG_USB_MON)
308 struct mon_bus *mon_bus;
309 int monitored;
310 #endif
311 };
有時候我真的很困惑,難道定義的結構體越多說明寫代碼的人腕兒越大?真的,我算是看明白了,這些人的思路是,一定得選最變态的資料結構,行數至少也得30行,什麼int型呀,char型呀,unsinged型呀,能給它用的全給它用上,結構體前邊有說明,裡邊有嵌套的結構體,結構體内寫一堆注釋,跨行,特長的那種,一套道地的gcc文法,倍兒有面子,再用上ANSI C的struct結構體初始化形式,一個結構體光指針就得十來個,再添加一些宏定義,編譯開關,就是一個字兒--帥!寫個子產品就得定義十個八個的結構體,你要是隻定義兩三個啊,你都不好意思在開源社群裡跟人家打招呼,你說這樣的代碼,一個子產品得賣多少錢?我覺得怎麼着也得兩千美金吧,兩千美金?!那是人力成本,四千美金起,你别嫌貴,還不打折,你得研究使用者的購買心理,願意掏兩千美金買源程式的使用者,根本不在乎再多掏兩千,什麼叫成功人士你知道嗎?成功人士就是,買什麼都買最複雜的,不買最好的,是以我們寫代碼的口号就是,不求最好,但求最複雜.