From: Henk - Added a rwsemaphore to yealink.c Hopefully this does sysfs write serialisation & fixes potential unload races - Fixed a small typo in drinvers/usb/input/Kconfig Cc: Dmitry Torokhov Cc: Greg KH Cc: Vojtech Pavlik Signed-off-by: Henk Signed-off-by: Andrew Morton --- drivers/usb/input/Kconfig | 2 - drivers/usb/input/yealink.c | 72 ++++++++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 20 deletions(-) diff -puN drivers/usb/input/Kconfig~yealink-updates-0701 drivers/usb/input/Kconfig --- devel/drivers/usb/input/Kconfig~yealink-updates-0701 2005-07-06 01:19:50.000000000 -0700 +++ devel-akpm/drivers/usb/input/Kconfig 2005-07-06 01:19:50.000000000 -0700 @@ -234,7 +234,7 @@ config USB_YEALINK tristate "Yealink usb-p1k voip phone" depends on USB && INPUT && EXPERIMENTAL ---help--- - Say Y here if you want to enable keyboard and LDC functions of the + Say Y here if you want to enable keyboard and LCD functions of the Yealink usb-p1k usb phones. The audio part is enabled by the generic usb sound driver, so you might want to enable that as well. diff -puN drivers/usb/input/yealink.c~yealink-updates-0701 drivers/usb/input/yealink.c --- devel/drivers/usb/input/yealink.c~yealink-updates-0701 2005-07-06 01:19:50.000000000 -0700 +++ devel-akpm/drivers/usb/input/yealink.c 2005-07-06 01:19:50.000000000 -0700 @@ -44,6 +44,7 @@ * 20050531 henk Added led, LCD, dialtone and sysfs interface. * 20050610 henk Cleanups, make it ready for public consumption. * 20050630 henk Cleanups, fixes in response to comments. + * 20050701 henk sysfs write serialisation, fix potential unload races */ #include @@ -52,12 +53,12 @@ #include #include #include -#include +#include #include #include "map_to_7segment.h" -#define DRIVER_VERSION "yld-20050630" +#define DRIVER_VERSION "yld-20050701" #define DRIVER_AUTHOR "Henk Vergonet" #define DRIVER_DESC "Yealink phone driver" @@ -502,6 +503,8 @@ static void input_close(struct input_dev * sysfs interface ******************************************************************************/ +static DECLARE_RWSEM(sysfs_rwsema); + /* Interface to the 7-segments translation table aka. char set. */ static ssize_t show_map(struct device *dev, struct device_attribute *attr, @@ -530,9 +533,16 @@ static ssize_t store_map(struct device * */ static ssize_t show_line(struct device *dev, char *buf, int a, int b) { - struct yealink_dev *yld = dev_get_drvdata(dev); + struct yealink_dev *yld; int i = 0; + down_read(&sysfs_rwsema); + yld = dev_get_drvdata(dev); + if (yld == NULL) { + up_read(&sysfs_rwsema); + return 0; + } + for (i = a; i < b; i++) *buf++ = lcdMap[i].type; *buf++ = '\n'; @@ -540,6 +550,8 @@ static ssize_t show_line(struct device * *buf++ = yld->lcdMap[i]; *buf++ = '\n'; *buf = 0; + + up_read(&sysfs_rwsema); return 3 + ((b - a) << 1); } @@ -571,13 +583,19 @@ static ssize_t show_line3(struct device static ssize_t store_line(struct device *dev, const char *buf, size_t count, int el, size_t len) { - struct yealink_dev *yld = dev_get_drvdata(dev); + struct yealink_dev *yld; int i; - if (len > count) - len = count; - for (i = 0; i < len; i++) - setChar(yld, el++, buf[i]); + down_write(&sysfs_rwsema); + yld = dev_get_drvdata(dev); + if (yld) { + if (len > count) + len = count; + for (i = 0; i < len; i++) + setChar(yld, el++, buf[i]); + } + + up_write(&sysfs_rwsema); return count; } @@ -607,8 +625,16 @@ static ssize_t store_line3(struct device static ssize_t get_icons(struct device *dev, struct device_attribute *attr, char *buf) { - struct yealink_dev *yld = dev_get_drvdata(dev); + struct yealink_dev *yld; int i, ret = 1; + + down_read(&sysfs_rwsema); + yld = dev_get_drvdata(dev); + if (!yld) { + up_read(&sysfs_rwsema); + return 0; + } + for (i = 0; i < ARRAY_SIZE(lcdMap); i++) { if (lcdMap[i].type != '.') continue; @@ -616,6 +642,7 @@ static ssize_t get_icons(struct device * yld->lcdMap[i] == ' ' ? " " : "on", lcdMap[i].u.p.name); } + up_read(&sysfs_rwsema); return ret; } @@ -623,19 +650,22 @@ static ssize_t get_icons(struct device * static ssize_t set_icon(struct device *dev, const char *buf, size_t count, int chr) { - struct yealink_dev *yld = dev_get_drvdata(dev); + struct yealink_dev *yld; int i; - if (yld == NULL) - return count; - for (i = 0; i < ARRAY_SIZE(lcdMap); i++) { - if (lcdMap[i].type != '.') - continue; - if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) { - setChar(yld, i, chr); - break; + down_write(&sysfs_rwsema); + yld = dev_get_drvdata(dev); + if (yld) { + for (i = 0; i < ARRAY_SIZE(lcdMap); i++) { + if (lcdMap[i].type != '.') + continue; + if (strncmp(buf, lcdMap[i].u.p.name, count) == 0) { + setChar(yld, i, chr); + break; + } } } + up_write(&sysfs_rwsema); return count; } @@ -735,10 +765,14 @@ static int usb_cleanup(struct yealink_de static void usb_disconnect(struct usb_interface *intf) { - struct yealink_dev *yld = usb_get_intfdata(intf); + struct yealink_dev *yld; + down_write(&sysfs_rwsema); + yld = usb_get_intfdata(intf); sysfs_remove_group(&intf->dev.kobj, &yld_attr_group); usb_set_intfdata(intf, NULL); + up_write(&sysfs_rwsema); + usb_cleanup(yld, 0); } _