aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm/cxacru.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/atm/cxacru.c')
-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;