diff options
-rw-r--r-- | drivers/atm/solos-pci.c | 93 |
1 files changed, 92 insertions, 1 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index b0c4676296ba..4c87dfb01566 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -82,6 +82,7 @@ struct pkt_hdr { | |||
82 | #define PKT_COMMAND 1 | 82 | #define PKT_COMMAND 1 |
83 | #define PKT_POPEN 3 | 83 | #define PKT_POPEN 3 |
84 | #define PKT_PCLOSE 4 | 84 | #define PKT_PCLOSE 4 |
85 | #define PKT_STATUS 5 | ||
85 | 86 | ||
86 | struct solos_card { | 87 | struct solos_card { |
87 | void __iomem *config_regs; | 88 | void __iomem *config_regs; |
@@ -275,6 +276,72 @@ static ssize_t solos_param_store(struct device *dev, struct device_attribute *at | |||
275 | return ret; | 276 | return ret; |
276 | } | 277 | } |
277 | 278 | ||
279 | static char *next_string(struct sk_buff *skb) | ||
280 | { | ||
281 | int i = 0; | ||
282 | char *this = skb->data; | ||
283 | |||
284 | while (i < skb->len) { | ||
285 | if (this[i] == '\n') { | ||
286 | this[i] = 0; | ||
287 | skb_pull(skb, i); | ||
288 | return this; | ||
289 | } | ||
290 | } | ||
291 | return NULL; | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Status packet has fields separated by \n, starting with a version number | ||
296 | * for the information therein. Fields are.... | ||
297 | * | ||
298 | * packet version | ||
299 | * TxBitRate (version >= 1) | ||
300 | * RxBitRate (version >= 1) | ||
301 | * State (version >= 1) | ||
302 | */ | ||
303 | static int process_status(struct solos_card *card, int port, struct sk_buff *skb) | ||
304 | { | ||
305 | char *str, *end; | ||
306 | int ver, rate_up, rate_down, state; | ||
307 | |||
308 | if (!card->atmdev[port]) | ||
309 | return -ENODEV; | ||
310 | |||
311 | str = next_string(skb); | ||
312 | if (!str) | ||
313 | return -EIO; | ||
314 | |||
315 | ver = simple_strtol(str, NULL, 10); | ||
316 | if (ver < 1) { | ||
317 | dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n", | ||
318 | ver); | ||
319 | return -EIO; | ||
320 | } | ||
321 | |||
322 | str = next_string(skb); | ||
323 | rate_up = simple_strtol(str, &end, 10); | ||
324 | if (*end) | ||
325 | return -EIO; | ||
326 | |||
327 | str = next_string(skb); | ||
328 | rate_down = simple_strtol(str, &end, 10); | ||
329 | if (*end) | ||
330 | return -EIO; | ||
331 | |||
332 | str = next_string(skb); | ||
333 | if (!strcmp(str, "Showtime")) | ||
334 | state = ATM_PHY_SIG_FOUND; | ||
335 | else state = ATM_PHY_SIG_LOST; | ||
336 | |||
337 | card->atmdev[port]->link_rate = rate_down; | ||
338 | card->atmdev[port]->signal = state; | ||
339 | |||
340 | dev_info(&card->dev->dev, "ATM state: '%s', %d/%d kb/s up/down.\n", | ||
341 | str, rate_up/1000, rate_down/1000); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
278 | static int process_command(struct solos_card *card, int port, struct sk_buff *skb) | 345 | static int process_command(struct solos_card *card, int port, struct sk_buff *skb) |
279 | { | 346 | { |
280 | struct solos_param *prm; | 347 | struct solos_param *prm; |
@@ -512,7 +579,7 @@ void solos_bh(unsigned long card_arg) | |||
512 | 579 | ||
513 | size = le16_to_cpu(header.size); | 580 | size = le16_to_cpu(header.size); |
514 | 581 | ||
515 | skb = alloc_skb(size, GFP_ATOMIC); | 582 | skb = alloc_skb(size + 1, GFP_ATOMIC); |
516 | if (!skb) { | 583 | if (!skb) { |
517 | if (net_ratelimit()) | 584 | if (net_ratelimit()) |
518 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); | 585 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); |
@@ -547,6 +614,11 @@ void solos_bh(unsigned long card_arg) | |||
547 | atomic_inc(&vcc->stats->rx); | 614 | atomic_inc(&vcc->stats->rx); |
548 | break; | 615 | break; |
549 | 616 | ||
617 | case PKT_STATUS: | ||
618 | process_status(card, port, skb); | ||
619 | dev_kfree_skb(skb); | ||
620 | break; | ||
621 | |||
550 | case PKT_COMMAND: | 622 | case PKT_COMMAND: |
551 | default: /* FIXME: Not really, surely? */ | 623 | default: /* FIXME: Not really, surely? */ |
552 | if (process_command(card, port, skb)) | 624 | if (process_command(card, port, skb)) |
@@ -996,6 +1068,9 @@ static int atm_init(struct solos_card *card) | |||
996 | int i; | 1068 | int i; |
997 | 1069 | ||
998 | for (i = 0; i < card->nr_ports; i++) { | 1070 | for (i = 0; i < card->nr_ports; i++) { |
1071 | struct sk_buff *skb; | ||
1072 | struct pkt_hdr *header; | ||
1073 | |||
999 | skb_queue_head_init(&card->tx_queue[i]); | 1074 | skb_queue_head_init(&card->tx_queue[i]); |
1000 | skb_queue_head_init(&card->cli_queue[i]); | 1075 | skb_queue_head_init(&card->cli_queue[i]); |
1001 | 1076 | ||
@@ -1016,6 +1091,22 @@ static int atm_init(struct solos_card *card) | |||
1016 | card->atmdev[i]->ci_range.vci_bits = 16; | 1091 | card->atmdev[i]->ci_range.vci_bits = 16; |
1017 | card->atmdev[i]->dev_data = card; | 1092 | card->atmdev[i]->dev_data = card; |
1018 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; | 1093 | card->atmdev[i]->phy_data = (void *)(unsigned long)i; |
1094 | card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN; | ||
1095 | |||
1096 | skb = alloc_skb(sizeof(*header), GFP_ATOMIC); | ||
1097 | if (!skb) { | ||
1098 | dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n"); | ||
1099 | continue; | ||
1100 | } | ||
1101 | |||
1102 | header = (void *)skb_put(skb, sizeof(*header)); | ||
1103 | |||
1104 | header->size = cpu_to_le16(0); | ||
1105 | header->vpi = cpu_to_le16(0); | ||
1106 | header->vci = cpu_to_le16(0); | ||
1107 | header->type = cpu_to_le16(PKT_STATUS); | ||
1108 | |||
1109 | fpga_queue(card, i, skb, NULL); | ||
1019 | } | 1110 | } |
1020 | return 0; | 1111 | return 0; |
1021 | } | 1112 | } |