mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
arcnet: com20020-pci: add led trigger support
The EAE PLX-PCI card has special leds on the the main io pci resource bar. This patch adds support to trigger the conflict and data leds with the packages. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
This commit is contained in:
parent
5ef216c1f8
commit
8890624a4e
@ -237,6 +237,8 @@ struct Outgoing {
|
|||||||
numsegs; /* number of segments */
|
numsegs; /* number of segments */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ARCNET_LED_NAME_SZ (IFNAMSIZ + 6)
|
||||||
|
|
||||||
struct arcnet_local {
|
struct arcnet_local {
|
||||||
uint8_t config, /* current value of CONFIG register */
|
uint8_t config, /* current value of CONFIG register */
|
||||||
timeout, /* Extended timeout for COM20020 */
|
timeout, /* Extended timeout for COM20020 */
|
||||||
@ -260,6 +262,11 @@ struct arcnet_local {
|
|||||||
/* On preemtive and SMB a lock is needed */
|
/* On preemtive and SMB a lock is needed */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
|
struct led_trigger *tx_led_trig;
|
||||||
|
char tx_led_trig_name[ARCNET_LED_NAME_SZ];
|
||||||
|
struct led_trigger *recon_led_trig;
|
||||||
|
char recon_led_trig_name[ARCNET_LED_NAME_SZ];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
|
* Buffer management: an ARCnet card has 4 x 512-byte buffers, each of
|
||||||
* which can be used for either sending or receiving. The new dynamic
|
* which can be used for either sending or receiving. The new dynamic
|
||||||
@ -309,6 +316,8 @@ struct arcnet_local {
|
|||||||
int (*reset)(struct net_device *dev, int really_reset);
|
int (*reset)(struct net_device *dev, int really_reset);
|
||||||
void (*open)(struct net_device *dev);
|
void (*open)(struct net_device *dev);
|
||||||
void (*close)(struct net_device *dev);
|
void (*close)(struct net_device *dev);
|
||||||
|
void (*datatrigger) (struct net_device * dev, int enable);
|
||||||
|
void (*recontrigger) (struct net_device * dev, int enable);
|
||||||
|
|
||||||
void (*copy_to_card)(struct net_device *dev, int bufnum,
|
void (*copy_to_card)(struct net_device *dev, int bufnum,
|
||||||
int offset, void *buf, int count);
|
int offset, void *buf, int count);
|
||||||
@ -319,6 +328,16 @@ struct arcnet_local {
|
|||||||
void __iomem *mem_start; /* pointer to ioremap'ed MMIO */
|
void __iomem *mem_start; /* pointer to ioremap'ed MMIO */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum arcnet_led_event {
|
||||||
|
ARCNET_LED_EVENT_RECON,
|
||||||
|
ARCNET_LED_EVENT_OPEN,
|
||||||
|
ARCNET_LED_EVENT_STOP,
|
||||||
|
ARCNET_LED_EVENT_TX,
|
||||||
|
};
|
||||||
|
|
||||||
|
void arcnet_led_event(struct net_device *netdev, enum arcnet_led_event event);
|
||||||
|
void devm_arcnet_led_init(struct net_device *netdev, int index, int subid);
|
||||||
|
|
||||||
#if ARCNET_DEBUG_MAX & D_SKB
|
#if ARCNET_DEBUG_MAX & D_SKB
|
||||||
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
|
void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
|
||||||
#else
|
#else
|
||||||
|
@ -52,6 +52,8 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
|
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
#include "arcdevice.h"
|
#include "arcdevice.h"
|
||||||
#include "com9026.h"
|
#include "com9026.h"
|
||||||
|
|
||||||
@ -189,6 +191,71 @@ static void arcnet_dump_packet(struct net_device *dev, int bufnum,
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Trigger a LED event in response to a ARCNET device event */
|
||||||
|
void arcnet_led_event(struct net_device *dev, enum arcnet_led_event event)
|
||||||
|
{
|
||||||
|
struct arcnet_local *lp = netdev_priv(dev);
|
||||||
|
unsigned long led_delay = 350;
|
||||||
|
unsigned long tx_delay = 50;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case ARCNET_LED_EVENT_RECON:
|
||||||
|
led_trigger_blink_oneshot(lp->recon_led_trig,
|
||||||
|
&led_delay, &led_delay, 0);
|
||||||
|
break;
|
||||||
|
case ARCNET_LED_EVENT_OPEN:
|
||||||
|
led_trigger_event(lp->tx_led_trig, LED_OFF);
|
||||||
|
led_trigger_event(lp->recon_led_trig, LED_OFF);
|
||||||
|
break;
|
||||||
|
case ARCNET_LED_EVENT_STOP:
|
||||||
|
led_trigger_event(lp->tx_led_trig, LED_OFF);
|
||||||
|
led_trigger_event(lp->recon_led_trig, LED_OFF);
|
||||||
|
break;
|
||||||
|
case ARCNET_LED_EVENT_TX:
|
||||||
|
led_trigger_blink_oneshot(lp->tx_led_trig,
|
||||||
|
&tx_delay, &tx_delay, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(arcnet_led_event);
|
||||||
|
|
||||||
|
static void arcnet_led_release(struct device *gendev, void *res)
|
||||||
|
{
|
||||||
|
struct arcnet_local *lp = netdev_priv(to_net_dev(gendev));
|
||||||
|
|
||||||
|
led_trigger_unregister_simple(lp->tx_led_trig);
|
||||||
|
led_trigger_unregister_simple(lp->recon_led_trig);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register ARCNET LED triggers for a arcnet device
|
||||||
|
*
|
||||||
|
* This is normally called from a driver's probe function
|
||||||
|
*/
|
||||||
|
void devm_arcnet_led_init(struct net_device *netdev, int index, int subid)
|
||||||
|
{
|
||||||
|
struct arcnet_local *lp = netdev_priv(netdev);
|
||||||
|
void *res;
|
||||||
|
|
||||||
|
res = devres_alloc(arcnet_led_release, 0, GFP_KERNEL);
|
||||||
|
if (!res) {
|
||||||
|
netdev_err(netdev, "cannot register LED triggers\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(lp->tx_led_trig_name, sizeof(lp->tx_led_trig_name),
|
||||||
|
"arc%d-%d-tx", index, subid);
|
||||||
|
snprintf(lp->recon_led_trig_name, sizeof(lp->recon_led_trig_name),
|
||||||
|
"arc%d-%d-recon", index, subid);
|
||||||
|
|
||||||
|
led_trigger_register_simple(lp->tx_led_trig_name,
|
||||||
|
&lp->tx_led_trig);
|
||||||
|
led_trigger_register_simple(lp->recon_led_trig_name,
|
||||||
|
&lp->recon_led_trig);
|
||||||
|
|
||||||
|
devres_add(&netdev->dev, res);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(devm_arcnet_led_init);
|
||||||
|
|
||||||
/* Unregister a protocol driver from the arc_proto_map. Protocol drivers
|
/* Unregister a protocol driver from the arc_proto_map. Protocol drivers
|
||||||
* are responsible for registering themselves, but the unregister routine
|
* are responsible for registering themselves, but the unregister routine
|
||||||
* is pretty generic so we'll do it here.
|
* is pretty generic so we'll do it here.
|
||||||
@ -425,6 +492,7 @@ int arcnet_open(struct net_device *dev)
|
|||||||
|
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
||||||
|
arcnet_led_event(dev, ARCNET_LED_EVENT_OPEN);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_module_put:
|
out_module_put:
|
||||||
@ -438,6 +506,7 @@ int arcnet_close(struct net_device *dev)
|
|||||||
{
|
{
|
||||||
struct arcnet_local *lp = netdev_priv(dev);
|
struct arcnet_local *lp = netdev_priv(dev);
|
||||||
|
|
||||||
|
arcnet_led_event(dev, ARCNET_LED_EVENT_STOP);
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
|
|
||||||
/* flush TX and disable RX */
|
/* flush TX and disable RX */
|
||||||
@ -585,6 +654,8 @@ netdev_tx_t arcnet_send_packet(struct sk_buff *skb,
|
|||||||
arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n",
|
arc_printk(D_DEBUG, dev, "%s: %d: %s, status: %x\n",
|
||||||
__FILE__, __LINE__, __func__, lp->hw.status(dev));
|
__FILE__, __LINE__, __func__, lp->hw.status(dev));
|
||||||
|
|
||||||
|
arcnet_led_event(dev, ARCNET_LED_EVENT_TX);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
return retval; /* no need to try again */
|
return retval; /* no need to try again */
|
||||||
}
|
}
|
||||||
@ -837,6 +908,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
|
|||||||
|
|
||||||
arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n",
|
arc_printk(D_RECON, dev, "Network reconfiguration detected (status=%Xh)\n",
|
||||||
status);
|
status);
|
||||||
|
arcnet_led_event(dev, ARCNET_LED_EVENT_RECON);
|
||||||
/* MYRECON bit is at bit 7 of diagstatus */
|
/* MYRECON bit is at bit 7 of diagstatus */
|
||||||
if (diagstatus & 0x80)
|
if (diagstatus & 0x80)
|
||||||
arc_printk(D_RECON, dev, "Put out that recon myself\n");
|
arc_printk(D_RECON, dev, "Put out that recon myself\n");
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
#include "arcdevice.h"
|
#include "arcdevice.h"
|
||||||
#include "com20020.h"
|
#include "com20020.h"
|
||||||
@ -62,6 +63,36 @@ module_param(clockp, int, 0);
|
|||||||
module_param(clockm, int, 0);
|
module_param(clockm, int, 0);
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
static void led_tx_set(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
struct com20020_dev *card;
|
||||||
|
struct com20020_priv *priv;
|
||||||
|
struct com20020_pci_card_info *ci;
|
||||||
|
|
||||||
|
card = container_of(led_cdev, struct com20020_dev, tx_led);
|
||||||
|
|
||||||
|
priv = card->pci_priv;
|
||||||
|
ci = priv->ci;
|
||||||
|
|
||||||
|
outb(!!value, priv->misc + ci->leds[card->index].green);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void led_recon_set(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
struct com20020_dev *card;
|
||||||
|
struct com20020_priv *priv;
|
||||||
|
struct com20020_pci_card_info *ci;
|
||||||
|
|
||||||
|
card = container_of(led_cdev, struct com20020_dev, recon_led);
|
||||||
|
|
||||||
|
priv = card->pci_priv;
|
||||||
|
ci = priv->ci;
|
||||||
|
|
||||||
|
outb(!!value, priv->misc + ci->leds[card->index].red);
|
||||||
|
}
|
||||||
|
|
||||||
static void com20020pci_remove(struct pci_dev *pdev);
|
static void com20020pci_remove(struct pci_dev *pdev);
|
||||||
|
|
||||||
static int com20020pci_probe(struct pci_dev *pdev,
|
static int com20020pci_probe(struct pci_dev *pdev,
|
||||||
@ -170,14 +201,41 @@ static int com20020pci_probe(struct pci_dev *pdev,
|
|||||||
|
|
||||||
card->index = i;
|
card->index = i;
|
||||||
card->pci_priv = priv;
|
card->pci_priv = priv;
|
||||||
|
card->tx_led.brightness_set = led_tx_set;
|
||||||
|
card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
|
||||||
|
GFP_KERNEL, "arc%d-%d-tx",
|
||||||
|
dev->dev_id, i);
|
||||||
|
card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||||
|
"pci:green:tx:%d-%d",
|
||||||
|
dev->dev_id, i);
|
||||||
|
|
||||||
|
card->tx_led.dev = &dev->dev;
|
||||||
|
card->recon_led.brightness_set = led_recon_set;
|
||||||
|
card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
|
||||||
|
GFP_KERNEL, "arc%d-%d-recon",
|
||||||
|
dev->dev_id, i);
|
||||||
|
card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||||
|
"pci:red:recon:%d-%d",
|
||||||
|
dev->dev_id, i);
|
||||||
|
card->recon_led.dev = &dev->dev;
|
||||||
card->dev = dev;
|
card->dev = dev;
|
||||||
|
|
||||||
|
ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
|
||||||
|
if (ret)
|
||||||
|
goto out_port;
|
||||||
|
|
||||||
|
ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
|
||||||
|
if (ret)
|
||||||
|
goto out_port;
|
||||||
|
|
||||||
dev_set_drvdata(&dev->dev, card);
|
dev_set_drvdata(&dev->dev, card);
|
||||||
|
|
||||||
ret = com20020_found(dev, IRQF_SHARED);
|
ret = com20020_found(dev, IRQF_SHARED);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_port;
|
goto out_port;
|
||||||
|
|
||||||
|
devm_arcnet_led_init(dev, dev->dev_id, i);
|
||||||
|
|
||||||
list_add(&card->list, &priv->list_dev);
|
list_add(&card->list, &priv->list_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,6 +319,12 @@ static struct com20020_pci_card_info card_info_eae_arc1 = {
|
|||||||
.offset = 0x10,
|
.offset = 0x10,
|
||||||
.size = 0x04,
|
.size = 0x04,
|
||||||
},
|
},
|
||||||
|
.leds = {
|
||||||
|
{
|
||||||
|
.green = 0x0,
|
||||||
|
.red = 0x1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.rotary = 0x0,
|
.rotary = 0x0,
|
||||||
.flags = ARC_CAN_10MBIT,
|
.flags = ARC_CAN_10MBIT,
|
||||||
};
|
};
|
||||||
@ -284,6 +348,15 @@ static struct com20020_pci_card_info card_info_eae_ma1 = {
|
|||||||
.offset = 0x10,
|
.offset = 0x10,
|
||||||
.size = 0x04,
|
.size = 0x04,
|
||||||
},
|
},
|
||||||
|
.leds = {
|
||||||
|
{
|
||||||
|
.green = 0x0,
|
||||||
|
.red = 0x1,
|
||||||
|
}, {
|
||||||
|
.green = 0x2,
|
||||||
|
.red = 0x3,
|
||||||
|
},
|
||||||
|
},
|
||||||
.rotary = 0x0,
|
.rotary = 0x0,
|
||||||
.flags = ARC_CAN_10MBIT,
|
.flags = ARC_CAN_10MBIT,
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifndef __COM20020_H
|
#ifndef __COM20020_H
|
||||||
#define __COM20020_H
|
#define __COM20020_H
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
int com20020_check(struct net_device *dev);
|
int com20020_check(struct net_device *dev);
|
||||||
int com20020_found(struct net_device *dev, int shared);
|
int com20020_found(struct net_device *dev, int shared);
|
||||||
@ -36,6 +37,11 @@ extern const struct net_device_ops com20020_netdev_ops;
|
|||||||
|
|
||||||
#define PLX_PCI_MAX_CARDS 2
|
#define PLX_PCI_MAX_CARDS 2
|
||||||
|
|
||||||
|
struct ledoffsets {
|
||||||
|
int green;
|
||||||
|
int red;
|
||||||
|
};
|
||||||
|
|
||||||
struct com20020_pci_channel_map {
|
struct com20020_pci_channel_map {
|
||||||
u32 bar;
|
u32 bar;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@ -49,6 +55,7 @@ struct com20020_pci_card_info {
|
|||||||
struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS];
|
struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS];
|
||||||
struct com20020_pci_channel_map misc_map;
|
struct com20020_pci_channel_map misc_map;
|
||||||
|
|
||||||
|
struct ledoffsets leds[PLX_PCI_MAX_CARDS];
|
||||||
int rotary;
|
int rotary;
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
@ -64,6 +71,9 @@ struct com20020_dev {
|
|||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
|
||||||
|
struct led_classdev tx_led;
|
||||||
|
struct led_classdev recon_led;
|
||||||
|
|
||||||
struct com20020_priv *pci_priv;
|
struct com20020_priv *pci_priv;
|
||||||
int index;
|
int index;
|
||||||
};
|
};
|
||||||
|
@ -283,6 +283,13 @@ static inline void led_trigger_register_simple(const char *name,
|
|||||||
static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
|
static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {}
|
||||||
static inline void led_trigger_event(struct led_trigger *trigger,
|
static inline void led_trigger_event(struct led_trigger *trigger,
|
||||||
enum led_brightness event) {}
|
enum led_brightness event) {}
|
||||||
|
static inline void led_trigger_blink(struct led_trigger *trigger,
|
||||||
|
unsigned long *delay_on,
|
||||||
|
unsigned long *delay_off) {}
|
||||||
|
static inline void led_trigger_blink_oneshot(struct led_trigger *trigger,
|
||||||
|
unsigned long *delay_on,
|
||||||
|
unsigned long *delay_off,
|
||||||
|
int invert) {}
|
||||||
static inline void led_trigger_set_default(struct led_classdev *led_cdev) {}
|
static inline void led_trigger_set_default(struct led_classdev *led_cdev) {}
|
||||||
static inline void led_trigger_set(struct led_classdev *led_cdev,
|
static inline void led_trigger_set(struct led_classdev *led_cdev,
|
||||||
struct led_trigger *trigger) {}
|
struct led_trigger *trigger) {}
|
||||||
|
Loading…
Reference in New Issue
Block a user