diff options
author | David S. Miller <davem@davemloft.net> | 2015-10-27 01:16:02 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-27 01:16:02 -0400 |
commit | 61b9da925a5e985afc268eb8184f1af3ef542422 (patch) | |
tree | f236a21ec42a998dfebd167b91bd1c610cbc7dc1 | |
parent | 4b3418fba0fe819197e3359d5ddbef84ba2c59de (diff) | |
parent | 59fbcbc61e1f0fd9acdf3efb09faca0320049718 (diff) |
Merge tag 'arcnet-for-4.4-rc1' of git://git.pengutronix.de/git/mgr/linux
Michael Grzeschik says:
====================
This series includes code simplifaction. The main changes are the correct
xceiver handling (enable/disable) of the com20020 cards. The driver now handles
link status change detection. The EAE PCI-ARCNET cards now make use of the
rotary encoded subdevice indexing and got support for led triggers on transmit
and reconnection events.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/arcnet/arcdevice.h | 21 | ||||
-rw-r--r-- | drivers/net/arcnet/arcnet.c | 107 | ||||
-rw-r--r-- | drivers/net/arcnet/com20020-pci.c | 107 | ||||
-rw-r--r-- | drivers/net/arcnet/com20020.c | 39 | ||||
-rw-r--r-- | drivers/net/arcnet/com20020.h | 14 | ||||
-rw-r--r-- | include/linux/leds.h | 7 |
6 files changed, 277 insertions, 18 deletions
diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h index d7fdea11e694..20bfb9ba83ea 100644 --- a/drivers/net/arcnet/arcdevice.h +++ b/drivers/net/arcnet/arcdevice.h | |||
@@ -237,6 +237,8 @@ struct Outgoing { | |||
237 | numsegs; /* number of segments */ | 237 | numsegs; /* number of segments */ |
238 | }; | 238 | }; |
239 | 239 | ||
240 | #define ARCNET_LED_NAME_SZ (IFNAMSIZ + 6) | ||
241 | |||
240 | struct arcnet_local { | 242 | struct arcnet_local { |
241 | uint8_t config, /* current value of CONFIG register */ | 243 | uint8_t config, /* current value of CONFIG register */ |
242 | timeout, /* Extended timeout for COM20020 */ | 244 | timeout, /* Extended timeout for COM20020 */ |
@@ -260,6 +262,13 @@ struct arcnet_local { | |||
260 | /* On preemtive and SMB a lock is needed */ | 262 | /* On preemtive and SMB a lock is needed */ |
261 | spinlock_t lock; | 263 | spinlock_t lock; |
262 | 264 | ||
265 | struct led_trigger *tx_led_trig; | ||
266 | char tx_led_trig_name[ARCNET_LED_NAME_SZ]; | ||
267 | struct led_trigger *recon_led_trig; | ||
268 | char recon_led_trig_name[ARCNET_LED_NAME_SZ]; | ||
269 | |||
270 | struct timer_list timer; | ||
271 | |||
263 | /* | 272 | /* |
264 | * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of | 273 | * Buffer management: an ARCnet card has 4 x 512-byte buffers, each of |
265 | * which can be used for either sending or receiving. The new dynamic | 274 | * which can be used for either sending or receiving. The new dynamic |
@@ -309,6 +318,8 @@ struct arcnet_local { | |||
309 | int (*reset)(struct net_device *dev, int really_reset); | 318 | int (*reset)(struct net_device *dev, int really_reset); |
310 | void (*open)(struct net_device *dev); | 319 | void (*open)(struct net_device *dev); |
311 | void (*close)(struct net_device *dev); | 320 | void (*close)(struct net_device *dev); |
321 | void (*datatrigger) (struct net_device * dev, int enable); | ||
322 | void (*recontrigger) (struct net_device * dev, int enable); | ||
312 | 323 | ||
313 | void (*copy_to_card)(struct net_device *dev, int bufnum, | 324 | void (*copy_to_card)(struct net_device *dev, int bufnum, |
314 | int offset, void *buf, int count); | 325 | int offset, void *buf, int count); |
@@ -319,6 +330,16 @@ struct arcnet_local { | |||
319 | void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ | 330 | void __iomem *mem_start; /* pointer to ioremap'ed MMIO */ |
320 | }; | 331 | }; |
321 | 332 | ||
333 | enum arcnet_led_event { | ||
334 | ARCNET_LED_EVENT_RECON, | ||
335 | ARCNET_LED_EVENT_OPEN, | ||
336 | ARCNET_LED_EVENT_STOP, | ||
337 | ARCNET_LED_EVENT_TX, | ||
338 | }; | ||
339 | |||
340 | void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event); | ||
341 | void devm_arcnet_led_init(struct net_device *netdev, int index, int subid); | ||
342 | |||
322 | #if ARCNET_DEBUG_MAX & D_SKB | 343 | #if ARCNET_DEBUG_MAX & D_SKB |
323 | void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); | 344 | void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc); |
324 | #else | 345 | #else |
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index e41dd36fe832..6ea963e3b89a 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c | |||
@@ -52,6 +52,8 @@ | |||
52 | #include <linux/init.h> | 52 | #include <linux/init.h> |
53 | #include <linux/jiffies.h> | 53 | #include <linux/jiffies.h> |
54 | 54 | ||
55 | #include <linux/leds.h> | ||
56 | |||
55 | #include "arcdevice.h" | 57 | #include "arcdevice.h" |
56 | #include "com9026.h" | 58 | #include "com9026.h" |
57 | 59 | ||
@@ -189,6 +191,71 @@ static void arcnet_dump_packet(struct net_device *dev, int bufnum, | |||
189 | 191 | ||
190 | #endif | 192 | #endif |
191 | 193 | ||
194 | /* Trigger a LED event in response to a ARCNET device event */ | ||
195 | void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event) | ||
196 | { | ||
197 | struct arcnet_local *lp = netdev_priv(dev); | ||
198 | unsigned long led_delay = 350; | ||
199 | unsigned long tx_delay = 50; | ||
200 | |||
201 | switch (event) { | ||
202 | case ARCNET_LED_EVENT_RECON: | ||
203 | led_trigger_blink_oneshot(lp->recon_led_trig, | ||
204 | &led_delay, &led_delay, 0); | ||
205 | break; | ||
206 | case ARCNET_LED_EVENT_OPEN: | ||
207 | led_trigger_event(lp->tx_led_trig, LED_OFF); | ||
208 | led_trigger_event(lp->recon_led_trig, LED_OFF); | ||
209 | break; | ||
210 | case ARCNET_LED_EVENT_STOP: | ||
211 | led_trigger_event(lp->tx_led_trig, LED_OFF); | ||
212 | led_trigger_event(lp->recon_led_trig, LED_OFF); | ||
213 | break; | ||
214 | case ARCNET_LED_EVENT_TX: | ||
215 | led_trigger_blink_oneshot(lp->tx_led_trig, | ||
216 | &tx_delay, &tx_delay, 0); | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(arcnet_led_event); | ||
221 | |||
222 | static void arcnet_led_release(struct device *gendev, void *res) | ||
223 | { | ||
224 | struct arcnet_local *lp = netdev_priv(to_net_dev(gendev)); | ||
225 | |||
226 | led_trigger_unregister_simple(lp->tx_led_trig); | ||
227 | led_trigger_unregister_simple(lp->recon_led_trig); | ||
228 | } | ||
229 | |||
230 | /* Register ARCNET LED triggers for a arcnet device | ||
231 | * | ||
232 | * This is normally called from a driver's probe function | ||
233 | */ | ||
234 | void devm_arcnet_led_init(struct net_device *netdev, int index, int subid) | ||
235 | { | ||
236 | struct arcnet_local *lp = netdev_priv(netdev); | ||
237 | void *res; | ||
238 | |||
239 | res = devres_alloc(arcnet_led_release, 0, GFP_KERNEL); | ||
240 | if (!res) { | ||
241 | netdev_err(netdev, "cannot register LED triggers\n"); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | snprintf(lp->tx_led_trig_name, sizeof(lp->tx_led_trig_name), | ||
246 | "arc%d-%d-tx", index, subid); | ||
247 | snprintf(lp->recon_led_trig_name, sizeof(lp->recon_led_trig_name), | ||
248 | "arc%d-%d-recon", index, subid); | ||
249 | |||
250 | led_trigger_register_simple(lp->tx_led_trig_name, | ||
251 | &lp->tx_led_trig); | ||
252 | led_trigger_register_simple(lp->recon_led_trig_name, | ||
253 | &lp->recon_led_trig); | ||
254 | |||
255 | devres_add(&netdev->dev, res); | ||
256 | } | ||
257 | EXPORT_SYMBOL_GPL(devm_arcnet_led_init); | ||
258 | |||
192 | /* Unregister a protocol driver from the arc_proto_map. Protocol drivers | 259 | /* Unregister a protocol driver from the arc_proto_map. Protocol drivers |
193 | * are responsible for registering themselves, but the unregister routine | 260 | * are responsible for registering themselves, but the unregister routine |
194 | * is pretty generic so we'll do it here. | 261 | * is pretty generic so we'll do it here. |
@@ -314,6 +381,16 @@ static void arcdev_setup(struct net_device *dev) | |||
314 | dev->flags = IFF_BROADCAST; | 381 | dev->flags = IFF_BROADCAST; |
315 | } | 382 | } |
316 | 383 | ||
384 | static void arcnet_timer(unsigned long data) | ||
385 | { | ||
386 | struct net_device *dev = (struct net_device *)data; | ||
387 | |||
388 | if (!netif_carrier_ok(dev)) { | ||
389 | netif_carrier_on(dev); | ||
390 | netdev_info(dev, "link up\n"); | ||
391 | } | ||
392 | } | ||
393 | |||
317 | struct net_device *alloc_arcdev(const char *name) | 394 | struct net_device *alloc_arcdev(const char *name) |
318 | { | 395 | { |
319 | struct net_device *dev; | 396 | struct net_device *dev; |
@@ -325,6 +402,9 @@ struct net_device *alloc_arcdev(const char *name) | |||
325 | struct arcnet_local *lp = netdev_priv(dev); | 402 | struct arcnet_local *lp = netdev_priv(dev); |
326 | 403 | ||
327 | spin_lock_init(&lp->lock); | 404 | spin_lock_init(&lp->lock); |
405 | init_timer(&lp->timer); | ||
406 | lp->timer.data = (unsigned long) dev; | ||
407 | lp->timer.function = arcnet_timer; | ||
328 | } | 408 | } |
329 | 409 | ||
330 | return dev; | 410 | return dev; |
@@ -423,8 +503,11 @@ int arcnet_open(struct net_device *dev) | |||
423 | lp->hw.intmask(dev, lp->intmask); | 503 | lp->hw.intmask(dev, lp->intmask); |
424 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); | 504 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); |
425 | 505 | ||
506 | netif_carrier_off(dev); | ||
426 | netif_start_queue(dev); | 507 | netif_start_queue(dev); |
508 | mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000)); | ||
427 | 509 | ||
510 | arcnet_led_event(dev, ARCNET_LED_EVENT_OPEN); | ||
428 | return 0; | 511 | return 0; |
429 | 512 | ||
430 | out_module_put: | 513 | out_module_put: |
@@ -438,7 +521,11 @@ int arcnet_close(struct net_device *dev) | |||
438 | { | 521 | { |
439 | struct arcnet_local *lp = netdev_priv(dev); | 522 | struct arcnet_local *lp = netdev_priv(dev); |
440 | 523 | ||
524 | arcnet_led_event(dev, ARCNET_LED_EVENT_STOP); | ||
525 | del_timer_sync(&lp->timer); | ||
526 | |||
441 | netif_stop_queue(dev); | 527 | netif_stop_queue(dev); |
528 | netif_carrier_off(dev); | ||
442 | 529 | ||
443 | /* flush TX and disable RX */ | 530 | /* flush TX and disable RX */ |
444 | lp->hw.intmask(dev, 0); | 531 | lp->hw.intmask(dev, 0); |
@@ -515,7 +602,7 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, | |||
515 | struct ArcProto *proto; | 602 | struct ArcProto *proto; |
516 | int txbuf; | 603 | int txbuf; |
517 | unsigned long flags; | 604 | unsigned long flags; |
518 | int freeskb, retval; | 605 | int retval; |
519 | 606 | ||
520 | arc_printk(D_DURING, dev, | 607 | arc_printk(D_DURING, dev, |
521 | "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n", | 608 | "transmit requested (status=%Xh, txbufs=%d/%d, len=%d, protocol %x)\n", |
@@ -554,15 +641,13 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, | |||
554 | * the package later - forget about it now | 641 | * the package later - forget about it now |
555 | */ | 642 | */ |
556 | dev->stats.tx_bytes += skb->len; | 643 | dev->stats.tx_bytes += skb->len; |
557 | freeskb = 1; | 644 | dev_kfree_skb(skb); |
558 | } else { | 645 | } else { |
559 | /* do it the 'split' way */ | 646 | /* do it the 'split' way */ |
560 | lp->outgoing.proto = proto; | 647 | lp->outgoing.proto = proto; |
561 | lp->outgoing.skb = skb; | 648 | lp->outgoing.skb = skb; |
562 | lp->outgoing.pkt = pkt; | 649 | lp->outgoing.pkt = pkt; |
563 | 650 | ||
564 | freeskb = 0; | ||
565 | |||
566 | if (proto->continue_tx && | 651 | if (proto->continue_tx && |
567 | proto->continue_tx(dev, txbuf)) { | 652 | proto->continue_tx(dev, txbuf)) { |
568 | arc_printk(D_NORMAL, dev, | 653 | arc_printk(D_NORMAL, dev, |
@@ -574,7 +659,6 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, | |||
574 | lp->next_tx = txbuf; | 659 | lp->next_tx = txbuf; |
575 | } else { | 660 | } else { |
576 | retval = NETDEV_TX_BUSY; | 661 | retval = NETDEV_TX_BUSY; |
577 | freeskb = 0; | ||
578 | } | 662 | } |
579 | 663 | ||
580 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", | 664 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", |
@@ -588,10 +672,9 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb, | |||
588 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", | 672 | arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n", |
589 | __FILE__, __LINE__, __func__, lp->hw.status(dev)); | 673 | __FILE__, __LINE__, __func__, lp->hw.status(dev)); |
590 | 674 | ||
591 | spin_unlock_irqrestore(&lp->lock, flags); | 675 | arcnet_led_event(dev, ARCNET_LED_EVENT_TX); |
592 | if (freeskb) | ||
593 | dev_kfree_skb(skb); | ||
594 | 676 | ||
677 | spin_unlock_irqrestore(&lp->lock, flags); | ||
595 | return retval; /* no need to try again */ | 678 | return retval; /* no need to try again */ |
596 | } | 679 | } |
597 | EXPORT_SYMBOL(arcnet_send_packet); | 680 | EXPORT_SYMBOL(arcnet_send_packet); |
@@ -843,6 +926,13 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) | |||
843 | 926 | ||
844 | arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n", | 927 | arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n", |
845 | status); | 928 | status); |
929 | if (netif_carrier_ok(dev)) { | ||
930 | netif_carrier_off(dev); | ||
931 | netdev_info(dev, "link down\n"); | ||
932 | } | ||
933 | mod_timer(&lp->timer, jiffies + msecs_to_jiffies(1000)); | ||
934 | |||
935 | arcnet_led_event(dev, ARCNET_LED_EVENT_RECON); | ||
846 | /* MYRECON bit is at bit 7 of diagstatus */ | 936 | /* MYRECON bit is at bit 7 of diagstatus */ |
847 | if (diagstatus & 0x80) | 937 | if (diagstatus & 0x80) |
848 | arc_printk(D_RECON, dev, "Put out that recon myself\n"); | 938 | arc_printk(D_RECON, dev, "Put out that recon myself\n"); |
@@ -893,6 +983,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) | |||
893 | lp->num_recons = lp->network_down = 0; | 983 | lp->num_recons = lp->network_down = 0; |
894 | 984 | ||
895 | arc_printk(D_DURING, dev, "not recon: clearing counters anyway.\n"); | 985 | arc_printk(D_DURING, dev, "not recon: clearing counters anyway.\n"); |
986 | netif_carrier_on(dev); | ||
896 | } | 987 | } |
897 | 988 | ||
898 | if (didsomething) | 989 | if (didsomething) |
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index a12bf83be750..239de38fbd6a 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/pci.h> | 41 | #include <linux/pci.h> |
42 | #include <linux/list.h> | 42 | #include <linux/list.h> |
43 | #include <linux/io.h> | 43 | #include <linux/io.h> |
44 | #include <linux/leds.h> | ||
44 | 45 | ||
45 | #include "arcdevice.h" | 46 | #include "arcdevice.h" |
46 | #include "com20020.h" | 47 | #include "com20020.h" |
@@ -62,12 +63,43 @@ module_param(clockp, int, 0); | |||
62 | module_param(clockm, int, 0); | 63 | module_param(clockm, int, 0); |
63 | MODULE_LICENSE("GPL"); | 64 | MODULE_LICENSE("GPL"); |
64 | 65 | ||
66 | static void led_tx_set(struct led_classdev *led_cdev, | ||
67 | enum led_brightness value) | ||
68 | { | ||
69 | struct com20020_dev *card; | ||
70 | struct com20020_priv *priv; | ||
71 | struct com20020_pci_card_info *ci; | ||
72 | |||
73 | card = container_of(led_cdev, struct com20020_dev, tx_led); | ||
74 | |||
75 | priv = card->pci_priv; | ||
76 | ci = priv->ci; | ||
77 | |||
78 | outb(!!value, priv->misc + ci->leds[card->index].green); | ||
79 | } | ||
80 | |||
81 | static void led_recon_set(struct led_classdev *led_cdev, | ||
82 | enum led_brightness value) | ||
83 | { | ||
84 | struct com20020_dev *card; | ||
85 | struct com20020_priv *priv; | ||
86 | struct com20020_pci_card_info *ci; | ||
87 | |||
88 | card = container_of(led_cdev, struct com20020_dev, recon_led); | ||
89 | |||
90 | priv = card->pci_priv; | ||
91 | ci = priv->ci; | ||
92 | |||
93 | outb(!!value, priv->misc + ci->leds[card->index].red); | ||
94 | } | ||
95 | |||
65 | static void com20020pci_remove(struct pci_dev *pdev); | 96 | static void com20020pci_remove(struct pci_dev *pdev); |
66 | 97 | ||
67 | static int com20020pci_probe(struct pci_dev *pdev, | 98 | static int com20020pci_probe(struct pci_dev *pdev, |
68 | const struct pci_device_id *id) | 99 | const struct pci_device_id *id) |
69 | { | 100 | { |
70 | struct com20020_pci_card_info *ci; | 101 | struct com20020_pci_card_info *ci; |
102 | struct com20020_pci_channel_map *mm; | ||
71 | struct net_device *dev; | 103 | struct net_device *dev; |
72 | struct arcnet_local *lp; | 104 | struct arcnet_local *lp; |
73 | struct com20020_priv *priv; | 105 | struct com20020_priv *priv; |
@@ -84,9 +116,22 @@ static int com20020pci_probe(struct pci_dev *pdev, | |||
84 | 116 | ||
85 | ci = (struct com20020_pci_card_info *)id->driver_data; | 117 | ci = (struct com20020_pci_card_info *)id->driver_data; |
86 | priv->ci = ci; | 118 | priv->ci = ci; |
119 | mm = &ci->misc_map; | ||
87 | 120 | ||
88 | INIT_LIST_HEAD(&priv->list_dev); | 121 | INIT_LIST_HEAD(&priv->list_dev); |
89 | 122 | ||
123 | if (mm->size) { | ||
124 | ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset; | ||
125 | r = devm_request_region(&pdev->dev, ioaddr, mm->size, | ||
126 | "com20020-pci"); | ||
127 | if (!r) { | ||
128 | pr_err("IO region %xh-%xh already allocated.\n", | ||
129 | ioaddr, ioaddr + mm->size - 1); | ||
130 | return -EBUSY; | ||
131 | } | ||
132 | priv->misc = ioaddr; | ||
133 | } | ||
134 | |||
90 | for (i = 0; i < ci->devcount; i++) { | 135 | for (i = 0; i < ci->devcount; i++) { |
91 | struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; | 136 | struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; |
92 | struct com20020_dev *card; | 137 | struct com20020_dev *card; |
@@ -96,6 +141,7 @@ static int com20020pci_probe(struct pci_dev *pdev, | |||
96 | ret = -ENOMEM; | 141 | ret = -ENOMEM; |
97 | goto out_port; | 142 | goto out_port; |
98 | } | 143 | } |
144 | dev->dev_port = i; | ||
99 | 145 | ||
100 | dev->netdev_ops = &com20020_netdev_ops; | 146 | dev->netdev_ops = &com20020_netdev_ops; |
101 | 147 | ||
@@ -131,6 +177,13 @@ static int com20020pci_probe(struct pci_dev *pdev, | |||
131 | lp->timeout = timeout; | 177 | lp->timeout = timeout; |
132 | lp->hw.owner = THIS_MODULE; | 178 | lp->hw.owner = THIS_MODULE; |
133 | 179 | ||
180 | /* Get the dev_id from the PLX rotary coder */ | ||
181 | if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15)) | ||
182 | dev->dev_id = 0xc; | ||
183 | dev->dev_id ^= inb(priv->misc + ci->rotary) >> 4; | ||
184 | |||
185 | snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i); | ||
186 | |||
134 | if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) { | 187 | if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) { |
135 | pr_err("IO address %Xh is empty!\n", ioaddr); | 188 | pr_err("IO address %Xh is empty!\n", ioaddr); |
136 | ret = -EIO; | 189 | ret = -EIO; |
@@ -148,14 +201,41 @@ static int com20020pci_probe(struct pci_dev *pdev, | |||
148 | 201 | ||
149 | card->index = i; | 202 | card->index = i; |
150 | card->pci_priv = priv; | 203 | card->pci_priv = priv; |
204 | card->tx_led.brightness_set = led_tx_set; | ||
205 | card->tx_led.default_trigger = devm_kasprintf(&pdev->dev, | ||
206 | GFP_KERNEL, "arc%d-%d-tx", | ||
207 | dev->dev_id, i); | ||
208 | card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, | ||
209 | "pci:green:tx:%d-%d", | ||
210 | dev->dev_id, i); | ||
211 | |||
212 | card->tx_led.dev = &dev->dev; | ||
213 | card->recon_led.brightness_set = led_recon_set; | ||
214 | card->recon_led.default_trigger = devm_kasprintf(&pdev->dev, | ||
215 | GFP_KERNEL, "arc%d-%d-recon", | ||
216 | dev->dev_id, i); | ||
217 | card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, | ||
218 | "pci:red:recon:%d-%d", | ||
219 | dev->dev_id, i); | ||
220 | card->recon_led.dev = &dev->dev; | ||
151 | card->dev = dev; | 221 | card->dev = dev; |
152 | 222 | ||
223 | ret = devm_led_classdev_register(&pdev->dev, &card->tx_led); | ||
224 | if (ret) | ||
225 | goto out_port; | ||
226 | |||
227 | ret = devm_led_classdev_register(&pdev->dev, &card->recon_led); | ||
228 | if (ret) | ||
229 | goto out_port; | ||
230 | |||
153 | dev_set_drvdata(&dev->dev, card); | 231 | dev_set_drvdata(&dev->dev, card); |
154 | 232 | ||
155 | ret = com20020_found(dev, IRQF_SHARED); | 233 | ret = com20020_found(dev, IRQF_SHARED); |
156 | if (ret) | 234 | if (ret) |
157 | goto out_port; | 235 | goto out_port; |
158 | 236 | ||
237 | devm_arcnet_led_init(dev, dev->dev_id, i); | ||
238 | |||
159 | list_add(&card->list, &priv->list_dev); | 239 | list_add(&card->list, &priv->list_dev); |
160 | } | 240 | } |
161 | 241 | ||
@@ -234,6 +314,18 @@ static struct com20020_pci_card_info card_info_eae_arc1 = { | |||
234 | .size = 0x08, | 314 | .size = 0x08, |
235 | }, | 315 | }, |
236 | }, | 316 | }, |
317 | .misc_map = { | ||
318 | .bar = 2, | ||
319 | .offset = 0x10, | ||
320 | .size = 0x04, | ||
321 | }, | ||
322 | .leds = { | ||
323 | { | ||
324 | .green = 0x0, | ||
325 | .red = 0x1, | ||
326 | }, | ||
327 | }, | ||
328 | .rotary = 0x0, | ||
237 | .flags = ARC_CAN_10MBIT, | 329 | .flags = ARC_CAN_10MBIT, |
238 | }; | 330 | }; |
239 | 331 | ||
@@ -251,6 +343,21 @@ static struct com20020_pci_card_info card_info_eae_ma1 = { | |||
251 | .size = 0x08, | 343 | .size = 0x08, |
252 | } | 344 | } |
253 | }, | 345 | }, |
346 | .misc_map = { | ||
347 | .bar = 2, | ||
348 | .offset = 0x10, | ||
349 | .size = 0x04, | ||
350 | }, | ||
351 | .leds = { | ||
352 | { | ||
353 | .green = 0x0, | ||
354 | .red = 0x1, | ||
355 | }, { | ||
356 | .green = 0x2, | ||
357 | .red = 0x3, | ||
358 | }, | ||
359 | }, | ||
360 | .rotary = 0x0, | ||
254 | .flags = ARC_CAN_10MBIT, | 361 | .flags = ARC_CAN_10MBIT, |
255 | }; | 362 | }; |
256 | 363 | ||
diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index c82f323a8c2b..13d9ad4b3f5c 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c | |||
@@ -118,7 +118,7 @@ int com20020_check(struct net_device *dev) | |||
118 | arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND); | 118 | arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND); |
119 | } | 119 | } |
120 | 120 | ||
121 | lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE; | 121 | lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE; |
122 | /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */ | 122 | /* set node ID to 0x42 (but transmitter is disabled, so it's okay) */ |
123 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | 123 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); |
124 | arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG); | 124 | arcnet_outb(0x42, ioaddr, COM20020_REG_W_XREG); |
@@ -131,11 +131,6 @@ int com20020_check(struct net_device *dev) | |||
131 | } | 131 | } |
132 | arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status); | 132 | arc_printk(D_INIT_REASONS, dev, "status after reset: %X\n", status); |
133 | 133 | ||
134 | /* Enable TX */ | ||
135 | lp->config |= TXENcfg; | ||
136 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | ||
137 | arcnet_outb(arcnet_inb(ioaddr, 8), ioaddr, COM20020_REG_W_XREG); | ||
138 | |||
139 | arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, | 134 | arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, |
140 | ioaddr, COM20020_REG_W_COMMAND); | 135 | ioaddr, COM20020_REG_W_COMMAND); |
141 | status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS); | 136 | status = arcnet_inb(ioaddr, COM20020_REG_R_STATUS); |
@@ -169,9 +164,33 @@ static int com20020_set_hwaddr(struct net_device *dev, void *addr) | |||
169 | return 0; | 164 | return 0; |
170 | } | 165 | } |
171 | 166 | ||
167 | static int com20020_netdev_open(struct net_device *dev) | ||
168 | { | ||
169 | int ioaddr = dev->base_addr; | ||
170 | struct arcnet_local *lp = netdev_priv(dev); | ||
171 | |||
172 | lp->config |= TXENcfg; | ||
173 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | ||
174 | |||
175 | return arcnet_open(dev); | ||
176 | } | ||
177 | |||
178 | static int com20020_netdev_close(struct net_device *dev) | ||
179 | { | ||
180 | int ioaddr = dev->base_addr; | ||
181 | struct arcnet_local *lp = netdev_priv(dev); | ||
182 | |||
183 | arcnet_close(dev); | ||
184 | |||
185 | /* disable transmitter */ | ||
186 | lp->config &= ~TXENcfg; | ||
187 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
172 | const struct net_device_ops com20020_netdev_ops = { | 191 | const struct net_device_ops com20020_netdev_ops = { |
173 | .ndo_open = arcnet_open, | 192 | .ndo_open = com20020_netdev_open, |
174 | .ndo_stop = arcnet_close, | 193 | .ndo_stop = com20020_netdev_close, |
175 | .ndo_start_xmit = arcnet_send_packet, | 194 | .ndo_start_xmit = arcnet_send_packet, |
176 | .ndo_tx_timeout = arcnet_timeout, | 195 | .ndo_tx_timeout = arcnet_timeout, |
177 | .ndo_set_mac_address = com20020_set_hwaddr, | 196 | .ndo_set_mac_address = com20020_set_hwaddr, |
@@ -215,7 +234,7 @@ int com20020_found(struct net_device *dev, int shared) | |||
215 | arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND); | 234 | arcnet_outb(STARTIOcmd, ioaddr, COM20020_REG_W_COMMAND); |
216 | } | 235 | } |
217 | 236 | ||
218 | lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE; | 237 | lp->config = (lp->timeout << 3) | (lp->backplane << 2) | SUB_NODE; |
219 | /* Default 0x38 + register: Node ID */ | 238 | /* Default 0x38 + register: Node ID */ |
220 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | 239 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); |
221 | arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG); | 240 | arcnet_outb(dev->dev_addr[0], ioaddr, COM20020_REG_W_XREG); |
@@ -274,7 +293,7 @@ static int com20020_reset(struct net_device *dev, int really_reset) | |||
274 | dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS)); | 293 | dev->name, arcnet_inb(ioaddr, COM20020_REG_R_STATUS)); |
275 | 294 | ||
276 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); | 295 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); |
277 | lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2); | 296 | lp->config |= (lp->timeout << 3) | (lp->backplane << 2); |
278 | /* power-up defaults */ | 297 | /* power-up defaults */ |
279 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); | 298 | arcnet_outb(lp->config, ioaddr, COM20020_REG_W_CONFIG); |
280 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); | 299 | arc_printk(D_DEBUG, dev, "%s: %d: %s\n", __FILE__, __LINE__, __func__); |
diff --git a/drivers/net/arcnet/com20020.h b/drivers/net/arcnet/com20020.h index 22a460f39fb9..0bcc5d0a6903 100644 --- a/drivers/net/arcnet/com20020.h +++ b/drivers/net/arcnet/com20020.h | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | #ifndef __COM20020_H | 27 | #ifndef __COM20020_H |
28 | #define __COM20020_H | 28 | #define __COM20020_H |
29 | #include <linux/leds.h> | ||
29 | 30 | ||
30 | int com20020_check(struct net_device *dev); | 31 | int com20020_check(struct net_device *dev); |
31 | int com20020_found(struct net_device *dev, int shared); | 32 | int com20020_found(struct net_device *dev, int shared); |
@@ -36,6 +37,11 @@ extern const struct net_device_ops com20020_netdev_ops; | |||
36 | 37 | ||
37 | #define PLX_PCI_MAX_CARDS 2 | 38 | #define PLX_PCI_MAX_CARDS 2 |
38 | 39 | ||
40 | struct ledoffsets { | ||
41 | int green; | ||
42 | int red; | ||
43 | }; | ||
44 | |||
39 | struct com20020_pci_channel_map { | 45 | struct com20020_pci_channel_map { |
40 | u32 bar; | 46 | u32 bar; |
41 | u32 offset; | 47 | u32 offset; |
@@ -47,6 +53,10 @@ struct com20020_pci_card_info { | |||
47 | int devcount; | 53 | int devcount; |
48 | 54 | ||
49 | struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; | 55 | struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; |
56 | struct com20020_pci_channel_map misc_map; | ||
57 | |||
58 | struct ledoffsets leds[PLX_PCI_MAX_CARDS]; | ||
59 | int rotary; | ||
50 | 60 | ||
51 | unsigned int flags; | 61 | unsigned int flags; |
52 | }; | 62 | }; |
@@ -54,12 +64,16 @@ struct com20020_pci_card_info { | |||
54 | struct com20020_priv { | 64 | struct com20020_priv { |
55 | struct com20020_pci_card_info *ci; | 65 | struct com20020_pci_card_info *ci; |
56 | struct list_head list_dev; | 66 | struct list_head list_dev; |
67 | resource_size_t misc; | ||
57 | }; | 68 | }; |
58 | 69 | ||
59 | struct com20020_dev { | 70 | struct com20020_dev { |
60 | struct list_head list; | 71 | struct list_head list; |
61 | struct net_device *dev; | 72 | struct net_device *dev; |
62 | 73 | ||
74 | struct led_classdev tx_led; | ||
75 | struct led_classdev recon_led; | ||
76 | |||
63 | struct com20020_priv *pci_priv; | 77 | struct com20020_priv *pci_priv; |
64 | int index; | 78 | int index; |
65 | }; | 79 | }; |
diff --git a/include/linux/leds.h b/include/linux/leds.h index b122eeafb5dc..fa359c79c825 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h | |||
@@ -283,6 +283,13 @@ static inline void led_trigger_register_simple(const char *name, | |||
283 | static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} | 283 | static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} |
284 | static inline void led_trigger_event(struct led_trigger *trigger, | 284 | static inline void led_trigger_event(struct led_trigger *trigger, |
285 | enum led_brightness event) {} | 285 | enum led_brightness event) {} |
286 | static inline void led_trigger_blink(struct led_trigger *trigger, | ||
287 | unsigned long *delay_on, | ||
288 | unsigned long *delay_off) {} | ||
289 | static inline void led_trigger_blink_oneshot(struct led_trigger *trigger, | ||
290 | unsigned long *delay_on, | ||
291 | unsigned long *delay_off, | ||
292 | int invert) {} | ||
286 | static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} | 293 | static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} |
287 | static inline void led_trigger_set(struct led_classdev *led_cdev, | 294 | static inline void led_trigger_set(struct led_classdev *led_cdev, |
288 | struct led_trigger *trigger) {} | 295 | struct led_trigger *trigger) {} |