Commit a95d1abe authored by Gilles Chanteperdrix's avatar Gilles Chanteperdrix Committed by Philippe Gerum
Browse files

rtnet: reduce the compat cruft

parent 43fda38d
......@@ -32,15 +32,6 @@
#include <rtnet_chrdev.h>
#include <rtnet_port.h> /* for netdev_priv() */
#ifdef CONFIG_RTOS_STARTSTOP_TIMER
static int start_timer = 0;
module_param(start_timer, int, 0444);
MODULE_PARM_DESC(start_timer, "set to non-zero if RTAI timer was not yet "
"started");
#endif
MODULE_LICENSE("GPL");
static unsigned int rtcap_rtskbs = 128;
......@@ -165,7 +156,6 @@ void rtcap_kfree_rtskb(struct rtskb *rtskb)
static void convert_timestamp(nanosecs_abs_t timestamp, struct sk_buff *skb)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
# ifdef CONFIG_KTIME_SCALAR
skb->tstamp.tv64 = timestamp;
# else /* !CONFIG_KTIME_SCALAR */
......@@ -174,21 +164,6 @@ static void convert_timestamp(nanosecs_abs_t timestamp, struct sk_buff *skb)
rem = do_div(timestamp, NSEC_PER_SEC);
skb->tstamp = ktime_set((long)timestamp, rem);
# endif /* !CONFIG_KTIME_SCALAR */
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
struct timeval tv;
tv.tv_usec = do_div(timestamp, NSEC_PER_SEC);
tv.tv_sec = (long)timestamp;
tv.tv_usec /= 1000;
skb_set_timestamp(skb, &tv);
#else /* KERNEL_VERSION < 2.6.14 */
# ifndef NSEC_PER_SEC
# define NSEC_PER_SEC (1000000000L)
# endif
skb->stamp.tv_usec = do_div(timestamp, NSEC_PER_SEC);
skb->stamp.tv_sec = (long)timestamp;
skb->stamp.tv_usec /= 1000;
#endif
}
......@@ -331,7 +306,6 @@ static int tap_dev_change_mtu(struct net_device *dev, int new_mtu)
#ifdef HAVE_NET_DEVICE_OPS
static const struct net_device_ops tap_netdev_ops = {
.ndo_open = tap_dev_open,
.ndo_stop = tap_dev_stop,
......@@ -339,24 +313,12 @@ static const struct net_device_ops tap_netdev_ops = {
.ndo_get_stats = tap_dev_get_stats,
.ndo_change_mtu = tap_dev_change_mtu,
};
#endif /* HAVE_NET_DEVICE_OPS */
static void tap_dev_setup(struct net_device *dev)
{
ether_setup(dev);
#ifdef HAVE_NET_DEVICE_OPS
dev->netdev_ops = &tap_netdev_ops;
#else /* !HAVE_NET_DEVICE_OPS */
dev->open = tap_dev_open;
dev->hard_start_xmit = tap_dev_xmit;
dev->get_stats = tap_dev_get_stats;
dev->change_mtu = tap_dev_change_mtu;
dev->set_mac_address = NULL;
#ifdef HAVE_VALIDATE_ADDR
dev->validate_addr = NULL;
#endif
#endif /* !HAVE_NET_DEVICE_OPS */
dev->mtu = 1500;
dev->flags &= ~IFF_MULTICAST;
}
......@@ -407,11 +369,6 @@ int __init rtcap_init(void)
printk("RTcap: real-time capturing interface\n");
#ifdef CONFIG_RTOS_STARTSTOP_TIMER
if (start_timer)
rtos_timer_start();
#endif
rtskb_queue_init(&cap_queue);
rtdm_nrtsig_init(&cap_signal, rtcap_signal_handler, NULL);
......@@ -535,11 +492,6 @@ void rtcap_cleanup(void)
rtdm_lockctx_t context;
#ifdef CONFIG_RTOS_STARTSTOP_TIMER
if (start_timer)
rtos_timer_stop();
#endif
rtdm_nrtsig_destroy(&cap_signal);
/* unregister capturing handlers
......
......@@ -54,7 +54,7 @@
#include <rtdev.h>
#include <rtskb.h>
#include <rtnet_sys.h>
#include <rtdm/driver.h>
#include <ipv4/ip_input.h>
#include <ipv4/route.h>
#include <rtnet_port.h>
......@@ -140,9 +140,7 @@ static int rtnetproxy_xmit(struct sk_buff *skb, struct net_device *dev)
break;
default:
drop1:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
dev->stats.tx_dropped++;
#endif
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
......@@ -172,9 +170,7 @@ drop1:
if (rt_ip_route_output(&rt, daddr, INADDR_ANY) < 0) {
drop2:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
dev->stats.tx_dropped++;
#endif
kfree_rtskb(rtskb);
return NETDEV_TX_OK;
}
......@@ -190,10 +186,8 @@ drop2:
rtskb->rtdev = rt.rtdev;
#endif /* CONFIG_XENO_DRIVERS_NET_ADDON_PROXY_ARP */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
dev->stats.tx_packets++;
dev->stats.tx_bytes += len;
#endif
rtskb_queue_tail(&tx_queue, rtskb);
rtdm_event_signal(&rtnetproxy_tx_event);
......@@ -219,9 +213,7 @@ static void rtnetproxy_recv(struct rtskb *rtskb)
{
/* Acquire rtskb (JK) */
if (rtskb_acquire(rtskb, &rtskb_pool) != 0) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
dev_rtnetproxy->stats.rx_dropped++;
#endif
rtdm_printk("rtnetproxy_recv: No free rtskb in pool\n");
kfree_rtskb(rtskb);
return;
......@@ -259,17 +251,11 @@ static inline void rtnetproxy_kernel_recv(struct rtskb *rtskb)
skb->pkt_type = PACKET_HOST; /* Extremely important! Why?!? */
/* the rtskb stamp is useless (different clock), get new one */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
__net_timestamp(skb);
#else
do_gettimeofday(&skb->stamp);
#endif
dev->last_rx = jiffies;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
dev->stats.rx_bytes+=skb->len;
dev->stats.rx_packets++;
#endif
netif_rx(skb); /* pass it to the received stuff */
......@@ -307,7 +293,6 @@ static int rtnetproxy_accept_fastpath(struct net_device *dev, struct dst_entry *
}
#endif
#ifdef HAVE_NET_DEVICE_OPS
static int rtnetproxy_open(struct net_device *dev)
{
int err = try_module_get(THIS_MODULE);
......@@ -327,13 +312,8 @@ static const struct net_device_ops rtnetproxy_netdev_ops = {
.ndo_open = rtnetproxy_open,
.ndo_stop = rtnetproxy_stop,
.ndo_start_xmit = rtnetproxy_xmit,
#ifdef HAVE_SET_RX_MODE
.ndo_set_rx_mode = fake_multicast_support,
#else
.ndo_set_multicast_list = fake_multicast_support,
#endif
};
#endif /* HAVE_NET_DEVICE_OPS */
/* ************************************************************************
* device init
......@@ -351,15 +331,7 @@ static void __init rtnetproxy_init(struct net_device *dev)
#endif
dev->flags &= ~IFF_MULTICAST;
#ifdef HAVE_NET_DEVICE_OPS
dev->netdev_ops = &rtnetproxy_netdev_ops;
#else /* !HAVE_NET_DEVICE_OPS */
dev->hard_start_xmit = rtnetproxy_xmit;
dev->set_multicast_list = fake_multicast_support;
#ifdef CONFIG_NET_FASTROUTE
dev->accept_fastpath = rtnetproxy_accept_fastpath;
#endif
#endif /* !HAVE_NET_DEVICE_OPS */
}
/* ************************************************************************
......
......@@ -59,18 +59,13 @@
static int cards[MAX_UNITS] = { [0 ... (MAX_UNITS-1)] = 1 };
static int media[MAX_UNITS] = { [0 ... (MAX_UNITS-1)] = -1 };
static unsigned int rx_pool_size = DEFAULT_RX_POOL_SIZE;
compat_module_int_param_array(cards, MAX_UNITS);
compat_module_int_param_array(media, MAX_UNITS);
module_param_array(cards, int, NULL, 0444);
module_param_array(media, int, NULL, 0444);
module_param(rx_pool_size, uint, 0444);
MODULE_PARM_DESC(cards, "array of cards to be supported (e.g. 1,0,1)");
MODULE_PARM_DESC(media, "8139too: Bits 4+9: force full duplex, bit 5: 100Mbps");
MODULE_PARM_DESC(rx_pool_size, "number of receive buffers");
#if 0 /* FIXME: before we can use this option, a wrapper for duplex_lock vs. force_media has to be created */
static int full_duplex[MAX_UNITS] = { [0 ... (MAX_UNITS-1)] = -1 };
compat_module_int_param_array(full_duplex, MAX_UNITS);
MODULE_PARM_DESC (full_duplex, "8139too: Force full duplex for board(s) (1)");
#endif
/* *** RTnet *** */
......@@ -847,29 +842,6 @@ static int rtl8139_init_one (struct pci_dev *pdev,
pci_set_drvdata (pdev, rtdev);
#if 0
/* Find the connected MII xcvrs.
Doing this in open() would allow detecting external xcvrs later, but
takes too much time. */
#ifdef CONFIG_8139TOO_8129
if (tp->drv_flags & HAS_MII_XCVR) {
int phy, phy_idx = 0;
for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
int mii_status = mdio_read(rtdev, phy, 1);
if (mii_status != 0xffff && mii_status != 0x0000) {
u16 advertising = mdio_read(rtdev, phy, 4);
tp->phys[phy_idx++] = phy;
rtdm_printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x advertising %4.4x.\n",
rtdev->name, phy, mii_status, advertising);
}
}
if (phy_idx == 0) {
rtdm_printk(KERN_INFO "%s: No MII transceivers found! Assuming SYM transceiver.\n", rtdev->name);
tp->phys[0] = 32;
}
} else
#endif
#endif
tp->phys[0] = 32;
/* The lower four bits are the media type. */
......@@ -880,15 +852,6 @@ static int rtl8139_init_one (struct pci_dev *pdev,
if (tp->default_port)
tp->medialock = 1;
}
#if 0 /* FIXME: create wrapper for duplex_lock vs. force_media in newer kernels */
if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0)
tp->mii.full_duplex = full_duplex[board_idx];
if (tp->mii.full_duplex) {
rtdm_printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", rtdev->name);
/* Changing the MII-advertised media because might prevent re-connection. */
tp->mii.duplex_lock = 1;
}
#endif
if (tp->default_port) {
rtdm_printk(KERN_INFO " Forcing %dMbps %s-duplex operation.\n",
(option & 0x20 ? 100 : 10),
......@@ -1437,77 +1400,6 @@ static void rtl8139_rx_err
/* RTnet-TODO: We really need an error manager to handle such issues... */
rtdm_printk("%s: FATAL - Ethernet frame had errors, status %8.8x.\n",
rtdev->name, rx_status);
#if 0
tp->stats.rx_errors++;
if (!(rx_status & RxStatusOK)) {
if (rx_status & RxTooLong) {
printk ("%s: Oversized Ethernet frame, status %4.4x!\n",
rtdev->name, rx_status);
/* A.C.: The chip hangs here. */
}
if (rx_status & (RxBadSymbol | RxBadAlign))
tp->stats.rx_frame_errors++;
if (rx_status & (RxRunt | RxTooLong))
tp->stats.rx_length_errors++;
if (rx_status & RxCRCErr)
tp->stats.rx_crc_errors++;
} else {
tp->xstats.rx_lost_in_ring++;
}
#ifdef CONFIG_8139_NEW_RX_RESET
tmp8 = RTL_R8 (ChipCmd);
RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);
RTL_W8 (ChipCmd, tmp8);
RTL_W32 (RxConfig, tp->rx_config);
tp->cur_rx = 0;
#else
/* Reset the receiver, based on RealTek recommendation. (Bug?) */
/* disable receive */
RTL_W8_F (ChipCmd, CmdTxEnb);
tmp_work = 200;
while (--tmp_work > 0) {
udelay(1);
tmp8 = RTL_R8 (ChipCmd);
if (!(tmp8 & CmdRxEnb))
break;
}
if (tmp_work <= 0)
printk (KERN_WARNING PFX "rx stop wait too long\n");
/* restart receive */
tmp_work = 200;
while (--tmp_work > 0) {
RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);
udelay(1);
tmp8 = RTL_R8 (ChipCmd);
if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))
break;
}
if (tmp_work <= 0)
printk (KERN_WARNING PFX "tx/rx enable wait too long\n");
/* and reinitialize all rx related registers */
RTL_W8_F (Cfg9346, Cfg9346_Unlock);
/* Must enable Tx/Rx before setting transfer thresholds! */
RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);
tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
RTL_W32 (RxConfig, tp->rx_config);
tp->cur_rx = 0;
printk("init buffer addresses\n");
/* Lock Config[01234] and BMCR register writes */
RTL_W8 (Cfg9346, Cfg9346_Lock);
/* init Rx ring buffer DMA address */
RTL_W32_F (RxBuf, tp->rx_ring_dma);
/* A.C.: Reset the multicast list. */
__set_rx_mode (rtdev);
#endif
#endif
}
......@@ -1608,19 +1500,6 @@ static void rtl8139_weird_interrupt (struct rtnet_device *rtdev,
if ((status & RxUnderrun) && link_changed && (tp->drv_flags & HAS_LNK_CHNG)) {
/* Really link-change on new chips. */
#if 0 /* FIXME: create wrapper for duplex_lock vs. force_media */
int lpar = RTL_R16 (NWayLPAR);
int duplex = (lpar & LPA_100FULL) || (lpar & 0x01C0) == 0x0040;
|| tp->mii.duplex_lock;
if (tp->mii.full_duplex != duplex) {
tp->mii.full_duplex = duplex;
#if 0
RTL_W8 (Cfg9346, Cfg9346_Unlock);
RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);
RTL_W8 (Cfg9346, Cfg9346_Lock);
#endif
}
#endif
status &= ~RxUnderrun;
}
......@@ -1827,7 +1706,7 @@ static int __init rtl8139_init_module (void)
printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
#endif
return compat_pci_register_driver (&rtl8139_pci_driver);
return pci_register_driver (&rtl8139_pci_driver);
}
......
......@@ -460,24 +460,6 @@ static void update_mac_address(struct rtnet_device *dev)
/*
* Store the new hardware address in dev->dev_addr, and update the MAC.
*/
#if 0
static int set_mac_address(struct rtnet_device *dev, void* addr)
{
struct sockaddr *address = addr;
if (!is_valid_ether_addr(address->sa_data))
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
update_mac_address(dev);
printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
return 0;
}
#endif
static int inline hash_bit_value(int bitnr, __u8 *addr)
{
......@@ -517,177 +499,18 @@ static int inline hash_bit_value(int bitnr, __u8 *addr)
/*
* Return the hash index value for the specified address.
*/
#if 0
static int hash_get_index(__u8 *addr)
{
int i, j, bitval;
int hash_index = 0;
for (j = 0; j < 6; j++) {
for (i = 0, bitval = 0; i < 8; i++)
bitval ^= hash_bit_value(i*6 + j, addr);
hash_index |= (bitval << j);
}
return hash_index;
}
#endif
/*
* Add multicast addresses to the internal multicast-hash table.
*/
#if 0
static void at91ether_sethashtable(struct rtnet_device *dev)
{
struct dev_mc_list *curr;
unsigned long mc_filter[2];
unsigned int i, bitnr;
mc_filter[0] = mc_filter[1] = 0;
curr = dev->mc_list;
for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
if (!curr) break; /* unexpected end of list */
bitnr = hash_get_index(curr->dmi_addr);
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}
at91_emac_write(AT91_EMAC_HSH, mc_filter[0]);
at91_emac_write(AT91_EMAC_HSL, mc_filter[1]);
}
#endif
/*
* Enable/Disable promiscuous and multicast modes.
*/
#if 0
static void at91ether_set_rx_mode(struct rtnet_device *dev)
{
unsigned long cfg;
cfg = at91_emac_read(AT91_EMAC_CFG);
if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */
cfg |= AT91_EMAC_CAF;
else if (dev->flags & (~IFF_PROMISC)) /* Disable promiscuous mode */
cfg &= ~AT91_EMAC_CAF;
if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */
at91_emac_write(AT91_EMAC_HSH, -1);
at91_emac_write(AT91_EMAC_HSL, -1);
cfg |= AT91_EMAC_MTI;
} else if (dev->mc_count > 0) { /* Enable specific multicasts */
at91ether_sethashtable(dev);
cfg |= AT91_EMAC_MTI;
} else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */
at91_emac_write(AT91_EMAC_HSH, 0);
at91_emac_write(AT91_EMAC_HSL, 0);
cfg &= ~AT91_EMAC_MTI;
}
at91_emac_write(AT91_EMAC_CFG, cfg);
}
#endif
/* ......................... ETHTOOL SUPPORT ........................... */
#if 0
static int at91ether_get_settings(struct rtnet_device *dev, struct ethtool_cmd *cmd)
{
struct at91_private *lp = dev->priv;
int ret;
rtdm_lockctx_t context;
rtdm_lock_get_irqsave(&lp->lock, context);
enable_mdi();
ret = mii_ethtool_gset(&lp->mii, cmd);
disable_mdi();
rtdm_lock_put_irqrestore(&lp->lock, context);
if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */
cmd->supported = SUPPORTED_FIBRE;
cmd->port = PORT_FIBRE;
}
return ret;
}
static int at91ether_set_settings(struct rtnet_device *dev, struct ethtool_cmd *cmd)
{
struct at91_private *lp = dev->priv;
int ret;
rtdm_lockctx_t context;
rtdm_lock_get_irqsave(&lp->lock, context);
enable_mdi();
ret = mii_ethtool_sset(&lp->mii, cmd);
disable_mdi();
rtdm_lock_put_irqrestore(&lp->lock, context);
return ret;
}
static int at91ether_nwayreset(struct rtnet_device *dev)
{
struct at91_private *lp = dev->priv;
int ret;
rtdm_lockctx_t context;
rtdm_lock_get_irqsave(&lp->lock, context);
enable_mdi();
ret = mii_nway_restart(&lp->mii);
disable_mdi();
rtdm_lock_put_irqrestore(&lp->lock, context);
return ret;
}
static void at91ether_get_drvinfo(struct rtnet_device *dev, struct ethtool_drvinfo *info)
{
strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
/*strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));*/
}
static const struct ethtool_ops at91ether_ethtool_ops = {
.get_settings = at91ether_get_settings,
.set_settings = at91ether_set_settings,
.get_drvinfo = at91ether_get_drvinfo,
.nway_reset = at91ether_nwayreset,
.get_link = ethtool_op_get_link,
};
#endif
#if 0
static int at91ether_ioctl_rt(struct rtnet_device *dev, struct ifreq *rq, int cmd)
{
struct at91_private *lp = dev->priv;
int res;
rtdm_lockctx_t context;
if (!rtnetif_running(dev))
return -EINVAL;
rtdm_lock_get_irqsave(&lp->lock, context);
enable_mdi();
res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
disable_mdi();
rtdm_lock_put_irqrestore(&lp->lock, context);
return res;
}
#endif
/* ................................ MAC ................................ */
/*
......@@ -766,39 +589,6 @@ static int at91ether_tx(struct rtskb *skb, struct rtnet_device *dev)
/*
* Update the current statistics from the internal statistics registers.
*/
#if 0
static struct rtnet_device_stats *at91ether_stats(struct rtnet_device *dev)
{
struct at91_private *lp = dev->priv;
int ale, lenerr, seqe, lcol, ecol;
if (rtnetif_running(dev)) {
lp->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */
ale = at91_emac_read(AT91_EMAC_ALE);
lp->stats.rx_frame_errors += ale; /* Alignment errors */
lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF);
lp->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */
seqe = at91_emac_read(AT91_EMAC_SEQE);
lp->stats.rx_crc_errors += seqe; /* CRC error */
lp->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */
lp->stats.rx_errors += (ale + lenerr + seqe
+ at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB));
lp->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */
lp->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */
lp->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */
lp->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */
lcol = at91_emac_read(AT91_EMAC_LCOL);
ecol = at91_emac_read(AT91_EMAC_ECOL);
lp->stats.tx_window_errors += lcol; /* Late collisions */
lp->stats.tx_aborted_errors += ecol; /* 16 collisions */
lp->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol);
}
return &lp->stats;
}
#endif
/*
* Extract received frame from buffer descriptors and sent to upper layers.
* (Called from interrupt context)
......
......@@ -4,7 +4,6 @@ ccflags-y := -Iarch/$(SRCARCH)/xenomai/include -Iinclude/xenomai \
obj-$(CONFIG_XENO_DRIVERS_NET_DRV_E1000) += rt_e1000.o
rt_e1000-y := \
kcompat.o \
e1000_hw.o \
e1000_main.o \
e1000_param.o
......@@ -251,7 +251,7 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
#define MAX_UNITS 8
static int cards[MAX_UNITS] = { [0 ... (MAX_UNITS-1)] = 1 };
compat_module_int_param_array(cards, MAX_UNITS);
module_param_array(cards, int, NULL, 0444);
MODULE_PARM_DESC(cards, "array of cards to be supported (eg. 1,0,1)");