Re: [PATCH] cxacru: Export detailed device info through sysfs.

Simon Arlott
2007-02-23T22:42:21Z

[-- Attachment #1: Type: text/plain, Size: 5700 bytes --]

On 23/02/07 22:29, Simon Arlott wrote:
> When the device is polled for status there is a lot of useful status
> information available that is ignored. This patch stores the device
> info array when the status is polled and adds sysfs files to the usb
> device to allow userspace to query it. Since the device updates its
> status internally once a second the poll time is changed to this, and
> round_jiffies_relative is used to avoid waking the cpu unnecessarily.

I also have a patch that can call the ADSL start/stop function on the
device via sysfs, but it's inherently unstable because requests to start
when running or stop when stopped will blocking until the state is changed.

redrum 3-2:1.0 # echo no >adsl_running
Feb 23 22:35:28 redrum [ 8574.166565] ATM dev 0: ADSL line: down

redrum 3-2:1.0 # echo yes >adsl_running
Feb 23 22:35:34 redrum [ 8580.169400] ATM dev 0: ADSL line: initializing
---

diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index c8b69bf..33d6a7e 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -171,6 +171,9 @@ struct cxacru_data {
struct completion snd_done;
};

+static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
+ u8 *wdata, int wsize, u8 *rdata, int rsize);
+
/* Card info exported through sysfs */
#define CXACRU__ATTR_INIT(_name) \
static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
@@ -186,10 +189,16 @@ static ssize_t cxacru_sysfs_show_##_name
} \
CXACRU__ATTR_INIT(_name)

+#define CXACRU_CMD_INIT(_name) \
+static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
+ cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
+
#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
+#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)

#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
+#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)

static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
@@ -213,6 +222,7 @@ static ssize_t cxacru_sysfs_showattr_dB(
}
}

+/*
static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
{
switch (value) {
@@ -221,6 +231,7 @@ static ssize_t cxacru_sysfs_showattr_boo
default: return 0;
}
}
+*/

static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
{
@@ -278,6 +289,66 @@ static ssize_t cxacru_sysfs_show_mac_add
atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
}

+
+static ssize_t cxacru_sysfs_show_adsl_running(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
+ struct cxacru_data *instance = usbatm_instance->driver_data;
+
+ switch (instance->card_info[CXINF_LINE_STARTABLE]) {
+ case 0: return snprintf(buf, PAGE_SIZE, "yes\n");
+ case 1: return snprintf(buf, PAGE_SIZE, "no\n");
+ default: return 0;
+ }
+}
+
+static ssize_t cxacru_sysfs_store_adsl_running(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
+ struct cxacru_data *instance = usbatm_instance->driver_data;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EACCES;
+
+ switch (instance->card_info[CXINF_LINE_STARTABLE]) {
+ case 0: /* ADSL running */
+ if (count != 3
+ || strncmp(buf, "no", strlen("no"))
+ || strncmp(buf, "no\n", strlen("no\n")))
+ return 0;
+
+ ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ atm_err(usbatm_instance, "cxacru_sysfs_store_atm_running:"
+ " CHIP_ADSL_LINE_STOP returned %d\n", ret);
+ return ret;
+ }
+ // TODO: poll twice more then stop
+ return strlen(buf);
+ case 1: /* ADSL not running */
+ if (count != 4
+ || strncmp(buf, "yes", strlen("yes"))
+ || strncmp(buf, "yes\n", strlen("yes\n")))
+ return 0;
+
+ ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ atm_err(usbatm_instance, "cxacru_sysfs_store_atm_running:"
+ " CHIP_ADSL_LINE_START returned %d\n", ret);
+ return ret;
+ }
+ // TODO: resume polling
+ return strlen(buf);
+ default:
+ return -EINVAL;
+ }
+}
+
/*
* All device attributes are included in CXACRU_ALL_FILES
* so that the same list can be used multiple times:
@@ -308,11 +379,11 @@ CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS, u32, downstream_fec_errors); \
CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS, u32, upstream_hec_errors); \
CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS, u32, downstream_hec_errors); \
-CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE, bool, line_startable); \
CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
-CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version);
+CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \
+CXACRU_CMD_##_action( adsl_running);

CXACRU_ALL_FILES(INIT);