aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Arlott <simon@fire.lp0.eu>2009-11-21 10:14:01 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 17:53:01 -0500
commit4ac37208e9b30b36b615ed22a79b4ee787fdc9b5 (patch)
tree792b78405d06b00a0d0a5fa3a342ef359f1f5383
parent885582c48e5fbf47ccc4273aaa5f2f56ad513253 (diff)
USB: cxacru: add write-only sysfs attribute for modem configuration
The modem can be configured using CM_REQUEST_CARD_DATA_SET, although CM_REQUEST_CARD_DATA_GET does not return any data. Tested by setting the modulation (0x0a) option. There is a list of parameters in the following archive, but the meaning of many of them is not well documented: http://sourceforge.net/project/shownotes.php?release_id=301825 This source also indicates that the highest parameter set is 0x4a but this varies by model so an arbitrary limit of 0x7f has been used (the index is a 32-bit integer). Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/networking/cxacru.txt9
-rw-r--r--drivers/usb/atm/cxacru.c76
2 files changed, 84 insertions, 1 deletions
diff --git a/Documentation/networking/cxacru.txt b/Documentation/networking/cxacru.txt
index 3532ceecd2c3..f4fbf4cd592c 100644
--- a/Documentation/networking/cxacru.txt
+++ b/Documentation/networking/cxacru.txt
@@ -15,6 +15,15 @@ several sysfs attribute files for retrieving device statistics:
15* adsl_headend_environment 15* adsl_headend_environment
16 Information about the remote headend. 16 Information about the remote headend.
17 17
18* adsl_config
19 Configuration writing interface.
20 Write parameters in hexadecimal format <index>=<value>,
21 separated by whitespace, e.g.:
22 "1=0 a=5"
23 Up to 7 parameters at a time will be sent and the modem will restart
24 the ADSL connection when any value is set. These are logged for future
25 reference.
26
18* downstream_attenuation (dB) 27* downstream_attenuation (dB)
19* downstream_bits_per_frame 28* downstream_bits_per_frame
20* downstream_rate (kbps) 29* downstream_rate (kbps)
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 5e3d7b9a78a7..c2163d0826e3 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -52,6 +52,7 @@ static const char cxacru_driver_name[] = "cxacru";
52#define CXACRU_EP_DATA 0x02 /* Bulk in/out */ 52#define CXACRU_EP_DATA 0x02 /* Bulk in/out */
53 53
54#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */ 54#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */
55#define CMD_MAX_CONFIG ((CMD_PACKET_SIZE / 4 - 1) / 2)
55 56
56/* Addresses */ 57/* Addresses */
57#define PLLFCLK_ADDR 0x00350068 58#define PLLFCLK_ADDR 0x00350068
@@ -216,6 +217,10 @@ static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
216static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \ 217static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
217 cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name) 218 cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
218 219
220#define CXACRU_SET_INIT(_name) \
221static DEVICE_ATTR(_name, S_IWUSR, \
222 NULL, cxacru_sysfs_store_##_name)
223
219#define CXACRU_ATTR_INIT(_value, _type, _name) \ 224#define CXACRU_ATTR_INIT(_value, _type, _name) \
220static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \ 225static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
221 struct device_attribute *attr, char *buf) \ 226 struct device_attribute *attr, char *buf) \
@@ -232,10 +237,12 @@ CXACRU__ATTR_INIT(_name)
232 237
233#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name) 238#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
234#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) 239#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
240#define CXACRU_SET_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
235#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) 241#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
236 242
237#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name) 243#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
238#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) 244#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
245#define CXACRU_SET_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
239#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) 246#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
240 247
241static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf) 248static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
@@ -438,6 +445,72 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
438 return ret; 445 return ret;
439} 446}
440 447
448/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */
449
450static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
451 struct device_attribute *attr, const char *buf, size_t count)
452{
453 struct cxacru_data *instance = to_usbatm_driver_data(
454 to_usb_interface(dev));
455 int len = strlen(buf);
456 int ret, pos, num;
457 __le32 data[CMD_PACKET_SIZE / 4];
458
459 if (!capable(CAP_NET_ADMIN))
460 return -EACCES;
461
462 if (instance == NULL)
463 return -ENODEV;
464
465 pos = 0;
466 num = 0;
467 while (pos < len) {
468 int tmp;
469 u32 index;
470 u32 value;
471
472 ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
473 if (ret < 2)
474 return -EINVAL;
475 if (index < 0 || index > 0x7f)
476 return -EINVAL;
477 pos += tmp;
478
479 /* skip trailing newline */
480 if (buf[pos] == '\n' && pos == len-1)
481 pos++;
482
483 data[num * 2 + 1] = cpu_to_le32(index);
484 data[num * 2 + 2] = cpu_to_le32(value);
485 num++;
486
487 /* send config values when data buffer is full
488 * or no more data
489 */
490 if (pos >= len || num >= CMD_MAX_CONFIG) {
491 char log[CMD_MAX_CONFIG * 12 + 1]; /* %02x=%08x */
492
493 data[0] = cpu_to_le32(num);
494 ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
495 (u8 *) data, 4 + num * 8, NULL, 0);
496 if (ret < 0) {
497 atm_err(instance->usbatm,
498 "set card data returned %d\n", ret);
499 return -EIO;
500 }
501
502 for (tmp = 0; tmp < num; tmp++)
503 snprintf(log + tmp*12, 13, " %02x=%08x",
504 le32_to_cpu(data[tmp * 2 + 1]),
505 le32_to_cpu(data[tmp * 2 + 2]));
506 atm_info(instance->usbatm, "config%s\n", log);
507 num = 0;
508 }
509 }
510
511 return len;
512}
513
441/* 514/*
442 * All device attributes are included in CXACRU_ALL_FILES 515 * All device attributes are included in CXACRU_ALL_FILES
443 * so that the same list can be used multiple times: 516 * so that the same list can be used multiple times:
@@ -473,7 +546,8 @@ CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
473CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \ 546CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
474CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \ 547CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
475CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \ 548CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \
476CXACRU_CMD_##_action( adsl_state); 549CXACRU_CMD_##_action( adsl_state); \
550CXACRU_SET_##_action( adsl_config);
477 551
478CXACRU_ALL_FILES(INIT); 552CXACRU_ALL_FILES(INIT);
479 553