aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSimon Arlott <simon@arlott.org>2007-03-06 05:47:45 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 16:28:34 -0400
commitfa70fe44aba95ce373d7bcd27df4a594b53dcbdc (patch)
tree9aa3ae5dca5189ca3fb727c0b0ab2d412a7d1a32 /drivers/usb
parente9b8daf31b459acb440647a651b1bda3b30e6188 (diff)
USB: cxacru: export detailed device info through sysfs
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. Signed-off-by: Simon Arlott <simon@fire.lp0.eu> Cc: Duncan Sands <duncan.sands@free.fr> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/atm/cxacru.c181
1 files changed, 176 insertions, 5 deletions
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 3dfa3e40e148..cdcdfed9449d 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -34,14 +34,14 @@
34#include <linux/errno.h> 34#include <linux/errno.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/init.h> 36#include <linux/init.h>
37#include <linux/device.h> /* FIXME: linux/firmware.h should include it itself */ 37#include <linux/device.h>
38#include <linux/firmware.h> 38#include <linux/firmware.h>
39#include <linux/mutex.h> 39#include <linux/mutex.h>
40 40
41#include "usbatm.h" 41#include "usbatm.h"
42 42
43#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands" 43#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
44#define DRIVER_VERSION "0.2" 44#define DRIVER_VERSION "0.3"
45#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver" 45#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
46 46
47static const char cxacru_driver_name[] = "cxacru"; 47static const char cxacru_driver_name[] = "cxacru";
@@ -64,7 +64,7 @@ static const char cxacru_driver_name[] = "cxacru";
64#define SDRAM_ENA 0x1 64#define SDRAM_ENA 0x1
65 65
66#define CMD_TIMEOUT 2000 /* msecs */ 66#define CMD_TIMEOUT 2000 /* msecs */
67#define POLL_INTERVAL 5000 /* msecs */ 67#define POLL_INTERVAL 1 /* secs */
68 68
69/* commands for interaction with the modem through the control channel before 69/* commands for interaction with the modem through the control channel before
70 * firmware is loaded */ 70 * firmware is loaded */
@@ -159,6 +159,7 @@ struct cxacru_data {
159 159
160 int line_status; 160 int line_status;
161 struct delayed_work poll_work; 161 struct delayed_work poll_work;
162 u32 card_info[CXINF_MAX];
162 163
163 /* contol handles */ 164 /* contol handles */
164 struct mutex cm_serialize; 165 struct mutex cm_serialize;
@@ -170,6 +171,151 @@ struct cxacru_data {
170 struct completion snd_done; 171 struct completion snd_done;
171}; 172};
172 173
174/* Card info exported through sysfs */
175#define CXACRU__ATTR_INIT(_name) \
176static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
177
178#define CXACRU_ATTR_INIT(_value, _type, _name) \
179static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
180 struct device_attribute *attr, char *buf) \
181{ \
182 struct usb_interface *intf = to_usb_interface(dev); \
183 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
184 struct cxacru_data *instance = usbatm_instance->driver_data; \
185 return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
186} \
187CXACRU__ATTR_INIT(_name)
188
189#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
190#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
191
192#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
193#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
194
195static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
196{
197 return snprintf(buf, PAGE_SIZE, "%u\n", value);
198}
199
200static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
201{
202 return snprintf(buf, PAGE_SIZE, "%d\n", value);
203}
204
205static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
206{
207 if (unlikely(value < 0)) {
208 return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
209 value / 100, -value % 100);
210 } else {
211 return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
212 value / 100, value % 100);
213 }
214}
215
216static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
217{
218 switch (value) {
219 case 0: return snprintf(buf, PAGE_SIZE, "no\n");
220 case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
221 default: return 0;
222 }
223}
224
225static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
226{
227 switch (value) {
228 case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
229 case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
230 case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
231 default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
232 }
233}
234
235static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
236{
237 switch (value) {
238 case 0: return snprintf(buf, PAGE_SIZE, "down\n");
239 case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
240 case 2: return snprintf(buf, PAGE_SIZE, "training\n");
241 case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
242 case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
243 case 5: return snprintf(buf, PAGE_SIZE, "up\n");
244 case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
245 case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
246 default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
247 }
248}
249
250static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
251{
252 switch (value) {
253 case 0: return 0;
254 case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
255 case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
256 case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
257 default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
258 }
259}
260
261/*
262 * This could use MAC_ADDRESS_HIGH and MAC_ADDRESS_LOW, but since
263 * this data is already in atm_dev there's no point.
264 *
265 * MAC_ADDRESS_HIGH = 0x????5544
266 * MAC_ADDRESS_LOW = 0x33221100
267 * Where 00-55 are bytes 0-5 of the MAC.
268 */
269static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
270 struct device_attribute *attr, char *buf)
271{
272 struct usb_interface *intf = to_usb_interface(dev);
273 struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
274 struct atm_dev *atm_dev = usbatm_instance->atm_dev;
275
276 return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n",
277 atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2],
278 atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]);
279}
280
281/*
282 * All device attributes are included in CXACRU_ALL_FILES
283 * so that the same list can be used multiple times:
284 * INIT (define the device attributes)
285 * CREATE (create all the device files)
286 * REMOVE (remove all the device files)
287 *
288 * With the last two being defined as needed in the functions
289 * they are used in before calling CXACRU_ALL_FILES()
290 */
291#define CXACRU_ALL_FILES(_action) \
292CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_RATE, u32, downstream_rate); \
293CXACRU_ATTR_##_action(CXINF_UPSTREAM_RATE, u32, upstream_rate); \
294CXACRU_ATTR_##_action(CXINF_LINK_STATUS, LINK, link_status); \
295CXACRU_ATTR_##_action(CXINF_LINE_STATUS, LINE, line_status); \
296CXACRU__ATTR_##_action( mac_address); \
297CXACRU_ATTR_##_action(CXINF_UPSTREAM_SNR_MARGIN, dB, upstream_snr_margin); \
298CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_SNR_MARGIN, dB, downstream_snr_margin); \
299CXACRU_ATTR_##_action(CXINF_UPSTREAM_ATTENUATION, dB, upstream_attenuation); \
300CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_ATTENUATION, dB, downstream_attenuation); \
301CXACRU_ATTR_##_action(CXINF_TRANSMITTER_POWER, s8, transmitter_power); \
302CXACRU_ATTR_##_action(CXINF_UPSTREAM_BITS_PER_FRAME, u32, upstream_bits_per_frame); \
303CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_BITS_PER_FRAME, u32, downstream_bits_per_frame); \
304CXACRU_ATTR_##_action(CXINF_STARTUP_ATTEMPTS, u32, startup_attempts); \
305CXACRU_ATTR_##_action(CXINF_UPSTREAM_CRC_ERRORS, u32, upstream_crc_errors); \
306CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_CRC_ERRORS, u32, downstream_crc_errors); \
307CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC_ERRORS, u32, upstream_fec_errors); \
308CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS, u32, downstream_fec_errors); \
309CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS, u32, upstream_hec_errors); \
310CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS, u32, downstream_hec_errors); \
311CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE, bool, line_startable); \
312CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
313CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
314CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
315CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version);
316
317CXACRU_ALL_FILES(INIT);
318
173/* the following three functions are stolen from drivers/usb/core/message.c */ 319/* the following three functions are stolen from drivers/usb/core/message.c */
174static void cxacru_blocking_completion(struct urb *urb) 320static void cxacru_blocking_completion(struct urb *urb)
175{ 321{
@@ -395,6 +541,8 @@ static void cxacru_poll_status(struct work_struct *work)
395 goto reschedule; 541 goto reschedule;
396 } 542 }
397 543
544 memcpy(instance->card_info, buf, sizeof(instance->card_info));
545
398 if (instance->line_status == buf[CXINF_LINE_STATUS]) 546 if (instance->line_status == buf[CXINF_LINE_STATUS])
399 goto reschedule; 547 goto reschedule;
400 548
@@ -449,7 +597,8 @@ static void cxacru_poll_status(struct work_struct *work)
449 break; 597 break;
450 } 598 }
451reschedule: 599reschedule:
452 schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL)); 600 schedule_delayed_work(&instance->poll_work,
601 round_jiffies_relative(msecs_to_jiffies(POLL_INTERVAL*1000)));
453} 602}
454 603
455static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, 604static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
@@ -684,6 +833,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
684 833
685 instance->usbatm = usbatm_instance; 834 instance->usbatm = usbatm_instance;
686 instance->modem_type = (struct cxacru_modem_type *) id->driver_info; 835 instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
836 memset(instance->card_info, 0, sizeof(instance->card_info));
687 837
688 instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); 838 instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
689 if (!instance->rcv_buf) { 839 if (!instance->rcv_buf) {
@@ -710,6 +860,13 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
710 goto fail; 860 goto fail;
711 } 861 }
712 862
863 #define CXACRU_DEVICE_CREATE_FILE(_name) \
864 ret = device_create_file(&intf->dev, &dev_attr_##_name); \
865 if (unlikely(ret)) \
866 goto fail_sysfs;
867 CXACRU_ALL_FILES(CREATE);
868 #undef CXACRU_DEVICE_CREATE_FILE
869
713 usb_fill_int_urb(instance->rcv_urb, 870 usb_fill_int_urb(instance->rcv_urb,
714 usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), 871 usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
715 instance->rcv_buf, PAGE_SIZE, 872 instance->rcv_buf, PAGE_SIZE,
@@ -730,6 +887,14 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
730 887
731 return 0; 888 return 0;
732 889
890 fail_sysfs:
891 dbg("cxacru_bind: device_create_file failed (%d)\n", ret);
892
893 #define CXACRU_DEVICE_REMOVE_FILE(_name) \
894 device_remove_file(&intf->dev, &dev_attr_##_name);
895 CXACRU_ALL_FILES(REMOVE);
896 #undef CXACRU_DEVICE_REVOVE_FILE
897
733 fail: 898 fail:
734 free_page((unsigned long) instance->snd_buf); 899 free_page((unsigned long) instance->snd_buf);
735 free_page((unsigned long) instance->rcv_buf); 900 free_page((unsigned long) instance->rcv_buf);
@@ -762,6 +927,12 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
762 927
763 free_page((unsigned long) instance->snd_buf); 928 free_page((unsigned long) instance->snd_buf);
764 free_page((unsigned long) instance->rcv_buf); 929 free_page((unsigned long) instance->rcv_buf);
930
931 #define CXACRU_DEVICE_REMOVE_FILE(_name) \
932 device_remove_file(&intf->dev, &dev_attr_##_name);
933 CXACRU_ALL_FILES(REMOVE);
934 #undef CXACRU_DEVICE_REVOVE_FILE
935
765 kfree(instance); 936 kfree(instance);
766 937
767 usbatm_instance->driver_data = NULL; 938 usbatm_instance->driver_data = NULL;