1 |
Author: hwoarang |
2 |
Date: 2009-06-23 19:55:11 +0000 (Tue, 23 Jun 2009) |
3 |
New Revision: 1579 |
4 |
|
5 |
Added: |
6 |
genpatches-2.6/trunk/2.6.29/2900_bluetooth-fix-sysfs.patch |
7 |
Modified: |
8 |
genpatches-2.6/trunk/2.6.29/0000_README |
9 |
Log: |
10 |
Fix hard lock with bluetooth connections |
11 |
|
12 |
|
13 |
Modified: genpatches-2.6/trunk/2.6.29/0000_README |
14 |
=================================================================== |
15 |
--- genpatches-2.6/trunk/2.6.29/0000_README 2009-06-22 19:27:41 UTC (rev 1578) |
16 |
+++ genpatches-2.6/trunk/2.6.29/0000_README 2009-06-23 19:55:11 UTC (rev 1579) |
17 |
@@ -83,6 +83,10 @@ |
18 |
From: http://bugs.gentoo.org/show_bug.cgi?id=251237 |
19 |
Desc: usblp: continuously poll for status |
20 |
|
21 |
+Patch: 2900_bluetooth-fix-sysfs.patch |
22 |
+From: http://bugs.gentoo.org/show_bug.cgi?id=274007 |
23 |
+Desc: Fix hard lock with bluetooth connections |
24 |
+ |
25 |
Patch: 4100_dm-bbr.patch |
26 |
From: EVMS 2.5.2 |
27 |
Desc: Bad block relocation support for LiveCD users |
28 |
|
29 |
Added: genpatches-2.6/trunk/2.6.29/2900_bluetooth-fix-sysfs.patch |
30 |
=================================================================== |
31 |
--- genpatches-2.6/trunk/2.6.29/2900_bluetooth-fix-sysfs.patch (rev 0) |
32 |
+++ genpatches-2.6/trunk/2.6.29/2900_bluetooth-fix-sysfs.patch 2009-06-23 19:55:11 UTC (rev 1579) |
33 |
@@ -0,0 +1,454 @@ |
34 |
+From: Cornelia Huck <cornelia.huck@××××××.com> |
35 |
+Date: Wed, 4 Mar 2009 11:44:00 +0000 (+0100) |
36 |
+Subject: Driver core: Fix device_move() vs. dpm list ordering, v2 |
37 |
+X-Git-Tag: v2.6.30-rc1~671^2~7 |
38 |
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fstable%2Flinux-2.6.30.y.git;a=commitdiff_plain;h=ffa6a7054d172a2f57248dff2de600ca795c5656;hp=60530afe1ee8a5532cb09d0ab5bc3f1a6495b780 |
39 |
+ |
40 |
+Driver core: Fix device_move() vs. dpm list ordering, v2 |
41 |
+ |
42 |
+dpm_list currently relies on the fact that child devices will |
43 |
+be registered after their parents to get a correct suspend |
44 |
+order. Using device_move() however destroys this assumption, as |
45 |
+an already registered device may be moved under a newly registered |
46 |
+one. |
47 |
+ |
48 |
+This patch adds a new argument to device_move(), allowing callers |
49 |
+to specify how dpm_list should be adapted. |
50 |
+ |
51 |
+Signed-off-by: Cornelia Huck <cornelia.huck@××××××.com> |
52 |
+Acked-by: Alan Stern <stern@×××××××××××××××.edu> |
53 |
+Signed-off-by: Greg Kroah-Hartman <gregkh@××××.de> |
54 |
+--- |
55 |
+ |
56 |
+Index: linux-2.6.29.2/drivers/base/core.c |
57 |
+=================================================================== |
58 |
+--- linux-2.6.29.2.orig/drivers/base/core.c |
59 |
++++ linux-2.6.29.2/drivers/base/core.c |
60 |
+@@ -1545,8 +1545,10 @@ out: |
61 |
+ * device_move - moves a device to a new parent |
62 |
+ * @dev: the pointer to the struct device to be moved |
63 |
+ * @new_parent: the new parent of the device (can by NULL) |
64 |
++ * @dpm_order: how to reorder the dpm_list |
65 |
+ */ |
66 |
+-int device_move(struct device *dev, struct device *new_parent) |
67 |
++int device_move(struct device *dev, struct device *new_parent, |
68 |
++ enum dpm_order dpm_order) |
69 |
+ { |
70 |
+ int error; |
71 |
+ struct device *old_parent; |
72 |
+@@ -1556,6 +1558,7 @@ int device_move(struct device *dev, stru |
73 |
+ if (!dev) |
74 |
+ return -EINVAL; |
75 |
+ |
76 |
++ device_pm_lock(); |
77 |
+ new_parent = get_device(new_parent); |
78 |
+ new_parent_kobj = get_device_parent(dev, new_parent); |
79 |
+ |
80 |
+@@ -1596,9 +1599,23 @@ int device_move(struct device *dev, stru |
81 |
+ put_device(new_parent); |
82 |
+ goto out; |
83 |
+ } |
84 |
++ switch (dpm_order) { |
85 |
++ case DPM_ORDER_NONE: |
86 |
++ break; |
87 |
++ case DPM_ORDER_DEV_AFTER_PARENT: |
88 |
++ device_pm_move_after(dev, new_parent); |
89 |
++ break; |
90 |
++ case DPM_ORDER_PARENT_BEFORE_DEV: |
91 |
++ device_pm_move_before(new_parent, dev); |
92 |
++ break; |
93 |
++ case DPM_ORDER_DEV_LAST: |
94 |
++ device_pm_move_last(dev); |
95 |
++ break; |
96 |
++ } |
97 |
+ out_put: |
98 |
+ put_device(old_parent); |
99 |
+ out: |
100 |
++ device_pm_unlock(); |
101 |
+ put_device(dev); |
102 |
+ return error; |
103 |
+ } |
104 |
+Index: linux-2.6.29.2/drivers/base/power/main.c |
105 |
+=================================================================== |
106 |
+--- linux-2.6.29.2.orig/drivers/base/power/main.c |
107 |
++++ linux-2.6.29.2/drivers/base/power/main.c |
108 |
+@@ -107,6 +107,50 @@ void device_pm_remove(struct device *dev |
109 |
+ } |
110 |
+ |
111 |
+ /** |
112 |
++ * device_pm_move_before - move device in dpm_list |
113 |
++ * @deva: Device to move in dpm_list |
114 |
++ * @devb: Device @deva should come before |
115 |
++ */ |
116 |
++void device_pm_move_before(struct device *deva, struct device *devb) |
117 |
++{ |
118 |
++ pr_debug("PM: Moving %s:%s before %s:%s\n", |
119 |
++ deva->bus ? deva->bus->name : "No Bus", |
120 |
++ kobject_name(&deva->kobj), |
121 |
++ devb->bus ? devb->bus->name : "No Bus", |
122 |
++ kobject_name(&devb->kobj)); |
123 |
++ /* Delete deva from dpm_list and reinsert before devb. */ |
124 |
++ list_move_tail(&deva->power.entry, &devb->power.entry); |
125 |
++} |
126 |
++ |
127 |
++/** |
128 |
++ * device_pm_move_after - move device in dpm_list |
129 |
++ * @deva: Device to move in dpm_list |
130 |
++ * @devb: Device @deva should come after |
131 |
++ */ |
132 |
++void device_pm_move_after(struct device *deva, struct device *devb) |
133 |
++{ |
134 |
++ pr_debug("PM: Moving %s:%s after %s:%s\n", |
135 |
++ deva->bus ? deva->bus->name : "No Bus", |
136 |
++ kobject_name(&deva->kobj), |
137 |
++ devb->bus ? devb->bus->name : "No Bus", |
138 |
++ kobject_name(&devb->kobj)); |
139 |
++ /* Delete deva from dpm_list and reinsert after devb. */ |
140 |
++ list_move(&deva->power.entry, &devb->power.entry); |
141 |
++} |
142 |
++ |
143 |
++/** |
144 |
++ * device_pm_move_last - move device to end of dpm_list |
145 |
++ * @dev: Device to move in dpm_list |
146 |
++ */ |
147 |
++void device_pm_move_last(struct device *dev) |
148 |
++{ |
149 |
++ pr_debug("PM: Moving %s:%s to end of list\n", |
150 |
++ dev->bus ? dev->bus->name : "No Bus", |
151 |
++ kobject_name(&dev->kobj)); |
152 |
++ list_move_tail(&dev->power.entry, &dpm_list); |
153 |
++} |
154 |
++ |
155 |
++/** |
156 |
+ * pm_op - execute the PM operation appropiate for given PM event |
157 |
+ * @dev: Device. |
158 |
+ * @ops: PM operations to choose from. |
159 |
+Index: linux-2.6.29.2/drivers/base/power/power.h |
160 |
+=================================================================== |
161 |
+--- linux-2.6.29.2.orig/drivers/base/power/power.h |
162 |
++++ linux-2.6.29.2/drivers/base/power/power.h |
163 |
+@@ -18,11 +18,19 @@ static inline struct device *to_device(s |
164 |
+ |
165 |
+ extern void device_pm_add(struct device *); |
166 |
+ extern void device_pm_remove(struct device *); |
167 |
++extern void device_pm_move_before(struct device *, struct device *); |
168 |
++extern void device_pm_move_after(struct device *, struct device *); |
169 |
++extern void device_pm_move_last(struct device *); |
170 |
+ |
171 |
+ #else /* CONFIG_PM_SLEEP */ |
172 |
+ |
173 |
+ static inline void device_pm_add(struct device *dev) {} |
174 |
+ static inline void device_pm_remove(struct device *dev) {} |
175 |
++static inline void device_pm_move_before(struct device *deva, |
176 |
++ struct device *devb) {} |
177 |
++static inline void device_pm_move_after(struct device *deva, |
178 |
++ struct device *devb) {} |
179 |
++static inline void device_pm_move_last(struct device *dev) {} |
180 |
+ |
181 |
+ #endif |
182 |
+ |
183 |
+Index: linux-2.6.29.2/drivers/s390/cio/device.c |
184 |
+=================================================================== |
185 |
+--- linux-2.6.29.2.orig/drivers/s390/cio/device.c |
186 |
++++ linux-2.6.29.2/drivers/s390/cio/device.c |
187 |
+@@ -799,7 +799,7 @@ static void sch_attach_disconnected_devi |
188 |
+ return; |
189 |
+ other_sch = to_subchannel(cdev->dev.parent); |
190 |
+ /* Note: device_move() changes cdev->dev.parent */ |
191 |
+- ret = device_move(&cdev->dev, &sch->dev); |
192 |
++ ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV); |
193 |
+ if (ret) { |
194 |
+ CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " |
195 |
+ "(ret=%d)!\n", cdev->private->dev_id.ssid, |
196 |
+@@ -830,7 +830,7 @@ static void sch_attach_orphaned_device(s |
197 |
+ * Try to move the ccw device to its new subchannel. |
198 |
+ * Note: device_move() changes cdev->dev.parent |
199 |
+ */ |
200 |
+- ret = device_move(&cdev->dev, &sch->dev); |
201 |
++ ret = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV); |
202 |
+ if (ret) { |
203 |
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " |
204 |
+ "failed (ret=%d)!\n", |
205 |
+@@ -897,7 +897,8 @@ void ccw_device_move_to_orphanage(struct |
206 |
+ * ccw device can take its place on the subchannel. |
207 |
+ * Note: device_move() changes cdev->dev.parent |
208 |
+ */ |
209 |
+- ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); |
210 |
++ ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev, |
211 |
++ DPM_ORDER_NONE); |
212 |
+ if (ret) { |
213 |
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " |
214 |
+ "(ret=%d)!\n", cdev->private->dev_id.ssid, |
215 |
+@@ -1129,7 +1130,7 @@ static void ccw_device_move_to_sch(struc |
216 |
+ * Try to move the ccw device to its new subchannel. |
217 |
+ * Note: device_move() changes cdev->dev.parent |
218 |
+ */ |
219 |
+- rc = device_move(&cdev->dev, &sch->dev); |
220 |
++ rc = device_move(&cdev->dev, &sch->dev, DPM_ORDER_PARENT_BEFORE_DEV); |
221 |
+ mutex_unlock(&sch->reg_mutex); |
222 |
+ if (rc) { |
223 |
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel " |
224 |
+Index: linux-2.6.29.2/include/linux/device.h |
225 |
+=================================================================== |
226 |
+--- linux-2.6.29.2.orig/include/linux/device.h |
227 |
++++ linux-2.6.29.2/include/linux/device.h |
228 |
+@@ -483,7 +483,8 @@ extern int device_for_each_child(struct |
229 |
+ extern struct device *device_find_child(struct device *dev, void *data, |
230 |
+ int (*match)(struct device *dev, void *data)); |
231 |
+ extern int device_rename(struct device *dev, char *new_name); |
232 |
+-extern int device_move(struct device *dev, struct device *new_parent); |
233 |
++extern int device_move(struct device *dev, struct device *new_parent, |
234 |
++ enum dpm_order dpm_order); |
235 |
+ |
236 |
+ /* |
237 |
+ * Root device objects for grouping under /sys/devices |
238 |
+Index: linux-2.6.29.2/include/linux/pm.h |
239 |
+=================================================================== |
240 |
+--- linux-2.6.29.2.orig/include/linux/pm.h |
241 |
++++ linux-2.6.29.2/include/linux/pm.h |
242 |
+@@ -400,6 +400,9 @@ extern void __suspend_report_result(cons |
243 |
+ |
244 |
+ #else /* !CONFIG_PM_SLEEP */ |
245 |
+ |
246 |
++#define device_pm_lock() do {} while (0) |
247 |
++#define device_pm_unlock() do {} while (0) |
248 |
++ |
249 |
+ static inline int device_suspend(pm_message_t state) |
250 |
+ { |
251 |
+ return 0; |
252 |
+@@ -409,6 +412,14 @@ static inline int device_suspend(pm_mess |
253 |
+ |
254 |
+ #endif /* !CONFIG_PM_SLEEP */ |
255 |
+ |
256 |
++/* How to reorder dpm_list after device_move() */ |
257 |
++enum dpm_order { |
258 |
++ DPM_ORDER_NONE, |
259 |
++ DPM_ORDER_DEV_AFTER_PARENT, |
260 |
++ DPM_ORDER_PARENT_BEFORE_DEV, |
261 |
++ DPM_ORDER_DEV_LAST, |
262 |
++}; |
263 |
++ |
264 |
+ /* |
265 |
+ * Global Power Management flags |
266 |
+ * Used to keep APM and ACPI from both being active |
267 |
+Index: linux-2.6.29.2/net/bluetooth/hci_sysfs.c |
268 |
+=================================================================== |
269 |
+--- linux-2.6.29.2.orig/net/bluetooth/hci_sysfs.c |
270 |
++++ linux-2.6.29.2/net/bluetooth/hci_sysfs.c |
271 |
+@@ -9,8 +9,7 @@ |
272 |
+ struct class *bt_class = NULL; |
273 |
+ EXPORT_SYMBOL_GPL(bt_class); |
274 |
+ |
275 |
+-static struct workqueue_struct *btaddconn; |
276 |
+-static struct workqueue_struct *btdelconn; |
277 |
++static struct workqueue_struct *bt_workq; |
278 |
+ |
279 |
+ static inline char *link_typetostr(int type) |
280 |
+ { |
281 |
+@@ -88,35 +87,17 @@ static struct device_type bt_link = { |
282 |
+ |
283 |
+ static void add_conn(struct work_struct *work) |
284 |
+ { |
285 |
+- struct hci_conn *conn = container_of(work, struct hci_conn, work); |
286 |
++ struct hci_conn *conn = container_of(work, struct hci_conn, work_add); |
287 |
++ struct hci_dev *hdev = conn->hdev; |
288 |
+ |
289 |
+- flush_workqueue(btdelconn); |
290 |
++ dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); |
291 |
+ |
292 |
+ if (device_add(&conn->dev) < 0) { |
293 |
+ BT_ERR("Failed to register connection device"); |
294 |
+ return; |
295 |
+ } |
296 |
+-} |
297 |
+- |
298 |
+-void hci_conn_add_sysfs(struct hci_conn *conn) |
299 |
+-{ |
300 |
+- struct hci_dev *hdev = conn->hdev; |
301 |
+- |
302 |
+- BT_DBG("conn %p", conn); |
303 |
+- |
304 |
+- conn->dev.type = &bt_link; |
305 |
+- conn->dev.class = bt_class; |
306 |
+- conn->dev.parent = &hdev->dev; |
307 |
+ |
308 |
+- dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); |
309 |
+- |
310 |
+- dev_set_drvdata(&conn->dev, conn); |
311 |
+- |
312 |
+- device_initialize(&conn->dev); |
313 |
+- |
314 |
+- INIT_WORK(&conn->work, add_conn); |
315 |
+- |
316 |
+- queue_work(btaddconn, &conn->work); |
317 |
++ hci_dev_hold(hdev); |
318 |
+ } |
319 |
+ |
320 |
+ /* |
321 |
+@@ -131,34 +112,58 @@ static int __match_tty(struct device *de |
322 |
+ |
323 |
+ static void del_conn(struct work_struct *work) |
324 |
+ { |
325 |
+- struct hci_conn *conn = container_of(work, struct hci_conn, work); |
326 |
++ struct hci_conn *conn = container_of(work, struct hci_conn, work_del); |
327 |
+ struct hci_dev *hdev = conn->hdev; |
328 |
+ |
329 |
++ if (!device_is_registered(&conn->dev)) |
330 |
++ return; |
331 |
++ |
332 |
+ while (1) { |
333 |
+ struct device *dev; |
334 |
+ |
335 |
+ dev = device_find_child(&conn->dev, NULL, __match_tty); |
336 |
+ if (!dev) |
337 |
+ break; |
338 |
+- device_move(dev, NULL); |
339 |
++ device_move(dev, NULL, DPM_ORDER_DEV_LAST); |
340 |
+ put_device(dev); |
341 |
+ } |
342 |
+ |
343 |
+ device_del(&conn->dev); |
344 |
+ put_device(&conn->dev); |
345 |
++ |
346 |
+ hci_dev_put(hdev); |
347 |
+ } |
348 |
+ |
349 |
+-void hci_conn_del_sysfs(struct hci_conn *conn) |
350 |
++void hci_conn_init_sysfs(struct hci_conn *conn) |
351 |
+ { |
352 |
++ struct hci_dev *hdev = conn->hdev; |
353 |
++ |
354 |
+ BT_DBG("conn %p", conn); |
355 |
+ |
356 |
+- if (!device_is_registered(&conn->dev)) |
357 |
+- return; |
358 |
++ conn->dev.type = &bt_link; |
359 |
++ conn->dev.class = bt_class; |
360 |
++ conn->dev.parent = &hdev->dev; |
361 |
+ |
362 |
+- INIT_WORK(&conn->work, del_conn); |
363 |
++ dev_set_drvdata(&conn->dev, conn); |
364 |
++ |
365 |
++ device_initialize(&conn->dev); |
366 |
+ |
367 |
+- queue_work(btdelconn, &conn->work); |
368 |
++ INIT_WORK(&conn->work_add, add_conn); |
369 |
++ INIT_WORK(&conn->work_del, del_conn); |
370 |
++} |
371 |
++ |
372 |
++void hci_conn_add_sysfs(struct hci_conn *conn) |
373 |
++{ |
374 |
++ BT_DBG("conn %p", conn); |
375 |
++ |
376 |
++ queue_work(bt_workq, &conn->work_add); |
377 |
++} |
378 |
++ |
379 |
++void hci_conn_del_sysfs(struct hci_conn *conn) |
380 |
++{ |
381 |
++ BT_DBG("conn %p", conn); |
382 |
++ |
383 |
++ queue_work(bt_workq, &conn->work_del); |
384 |
+ } |
385 |
+ |
386 |
+ static inline char *host_typetostr(int type) |
387 |
+@@ -435,20 +440,13 @@ void hci_unregister_sysfs(struct hci_dev |
388 |
+ |
389 |
+ int __init bt_sysfs_init(void) |
390 |
+ { |
391 |
+- btaddconn = create_singlethread_workqueue("btaddconn"); |
392 |
+- if (!btaddconn) |
393 |
++ bt_workq = create_singlethread_workqueue("bluetooth"); |
394 |
++ if (!bt_workq) |
395 |
+ return -ENOMEM; |
396 |
+ |
397 |
+- btdelconn = create_singlethread_workqueue("btdelconn"); |
398 |
+- if (!btdelconn) { |
399 |
+- destroy_workqueue(btaddconn); |
400 |
+- return -ENOMEM; |
401 |
+- } |
402 |
+- |
403 |
+ bt_class = class_create(THIS_MODULE, "bluetooth"); |
404 |
+ if (IS_ERR(bt_class)) { |
405 |
+- destroy_workqueue(btdelconn); |
406 |
+- destroy_workqueue(btaddconn); |
407 |
++ destroy_workqueue(bt_workq); |
408 |
+ return PTR_ERR(bt_class); |
409 |
+ } |
410 |
+ |
411 |
+@@ -457,8 +455,7 @@ int __init bt_sysfs_init(void) |
412 |
+ |
413 |
+ void bt_sysfs_cleanup(void) |
414 |
+ { |
415 |
+- destroy_workqueue(btaddconn); |
416 |
+- destroy_workqueue(btdelconn); |
417 |
++ destroy_workqueue(bt_workq); |
418 |
+ |
419 |
+ class_destroy(bt_class); |
420 |
+ } |
421 |
+Index: linux-2.6.29.2/net/bluetooth/rfcomm/tty.c |
422 |
+=================================================================== |
423 |
+--- linux-2.6.29.2.orig/net/bluetooth/rfcomm/tty.c |
424 |
++++ linux-2.6.29.2/net/bluetooth/rfcomm/tty.c |
425 |
+@@ -731,7 +731,8 @@ static int rfcomm_tty_open(struct tty_st |
426 |
+ remove_wait_queue(&dev->wait, &wait); |
427 |
+ |
428 |
+ if (err == 0) |
429 |
+- device_move(dev->tty_dev, rfcomm_get_device(dev)); |
430 |
++ device_move(dev->tty_dev, rfcomm_get_device(dev), |
431 |
++ DPM_ORDER_DEV_AFTER_PARENT); |
432 |
+ |
433 |
+ rfcomm_tty_copy_pending(dev); |
434 |
+ |
435 |
+@@ -751,7 +752,7 @@ static void rfcomm_tty_close(struct tty_ |
436 |
+ |
437 |
+ if (atomic_dec_and_test(&dev->opened)) { |
438 |
+ if (dev->tty_dev->parent) |
439 |
+- device_move(dev->tty_dev, NULL); |
440 |
++ device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST); |
441 |
+ |
442 |
+ /* Close DLC and dettach TTY */ |
443 |
+ rfcomm_dlc_close(dev->dlc, 0); |
444 |
+Index: linux-2.6.29.2/include/net/bluetooth/hci_core.h |
445 |
+=================================================================== |
446 |
+--- linux-2.6.29.2.orig/include/net/bluetooth/hci_core.h |
447 |
++++ linux-2.6.29.2/include/net/bluetooth/hci_core.h |
448 |
+@@ -179,7 +179,8 @@ struct hci_conn { |
449 |
+ struct timer_list disc_timer; |
450 |
+ struct timer_list idle_timer; |
451 |
+ |
452 |
+- struct work_struct work; |
453 |
++ struct work_struct work_add; |
454 |
++ struct work_struct work_del; |
455 |
+ |
456 |
+ struct device dev; |
457 |
+ |
458 |
+@@ -455,6 +456,7 @@ int hci_recv_fragment(struct hci_dev *hd |
459 |
+ |
460 |
+ int hci_register_sysfs(struct hci_dev *hdev); |
461 |
+ void hci_unregister_sysfs(struct hci_dev *hdev); |
462 |
++void hci_conn_init_sysfs(struct hci_conn *conn); |
463 |
+ void hci_conn_add_sysfs(struct hci_conn *conn); |
464 |
+ void hci_conn_del_sysfs(struct hci_conn *conn); |
465 |
+ |
466 |
+Index: linux-2.6.29.2/net/bluetooth/hci_conn.c |
467 |
+=================================================================== |
468 |
+--- linux-2.6.29.2.orig/net/bluetooth/hci_conn.c |
469 |
++++ linux-2.6.29.2/net/bluetooth/hci_conn.c |
470 |
+@@ -240,6 +240,8 @@ struct hci_conn *hci_conn_add(struct hci |
471 |
+ if (hdev->notify) |
472 |
+ hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); |
473 |
+ |
474 |
++ hci_conn_init_sysfs(conn); |
475 |
++ |
476 |
+ tasklet_enable(&hdev->tx_task); |
477 |
+ |
478 |
+ return conn; |
479 |
+@@ -280,6 +282,8 @@ int hci_conn_del(struct hci_conn *conn) |
480 |
+ |
481 |
+ skb_queue_purge(&conn->data_q); |
482 |
+ |
483 |
++ hci_dev_put(hdev); |
484 |
++ |
485 |
+ return 0; |
486 |
+ } |
487 |
+ |