diff options
Diffstat (limited to 'drivers/staging/cxt1e1/linux.c')
-rw-r--r-- | drivers/staging/cxt1e1/linux.c | 1142 |
1 files changed, 0 insertions, 1142 deletions
diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c deleted file mode 100644 index 09f3d5ca75ac..000000000000 --- a/drivers/staging/cxt1e1/linux.c +++ /dev/null @@ -1,1142 +0,0 @@ -/* Copyright (C) 2007-2008 One Stop Systems - * Copyright (C) 2003-2006 SBE, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/types.h> -#include <linux/netdevice.h> -#include <linux/module.h> -#include <linux/hdlc.h> -#include <linux/if_arp.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <linux/rtnetlink.h> -#include <linux/skbuff.h> -#include "pmcc4_sysdep.h" -#include "sbecom_inline_linux.h" -#include "libsbew.h" -#include "pmcc4.h" -#include "pmcc4_ioctls.h" -#include "pmcc4_private.h" -#include "sbeproc.h" - -/******************************************************************************* - * Error out early if we have compiler trouble. - * - * (This section is included from the kernel's init/main.c as a friendly - * spiderman recommendation...) - * - * Versions of gcc older than that listed below may actually compile and link - * okay, but the end product can have subtle run time bugs. To avoid associated - * bogus bug reports, we flatly refuse to compile with a gcc that is known to be - * too old from the very beginning. - */ -#if (__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 2) -#error Sorry, your GCC is too old. It builds incorrect kernels. -#endif - -#if __GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ == 0 -#warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended. -#endif - -/*******************************************************************************/ - -#define CHANNAME "hdlc" - -/*******************************************************************/ -/* forward references */ -status_t c4_chan_work_init(mpi_t *, mch_t *); -void musycc_wq_chan_restart(void *); -status_t __init c4_init(ci_t *, u_char *, u_char *); -status_t __init c4_init2(ci_t *); -int __init c4hw_attach_all(void); -void __init hdw_sn_get(hdw_info_t *, int); - -#ifdef CONFIG_SBE_PMCC4_NCOMM -irqreturn_t c4_ebus_intr_th_handler(void *); - -#endif -int c4_frame_rw(ci_t *, struct sbecom_port_param *); -status_t c4_get_port(ci_t *, int); -int c4_loop_port(ci_t *, int, u_int8_t); -int c4_musycc_rw(ci_t *, struct c4_musycc_param *); -int c4_new_chan(ci_t *, int, int, void *); -status_t c4_set_port(ci_t *, int); -int c4_pld_rw(ci_t *, struct sbecom_port_param *); -void cleanup_devs(void); -void cleanup_ioremap(void); -status_t musycc_chan_down(ci_t *, int); -irqreturn_t musycc_intr_th_handler(void *); -int musycc_start_xmit(ci_t *, int, void *); - -extern ci_t *CI; -extern struct s_hdw_info hdw_info[]; - -int error_flag; /* module load error reporting */ -int cxt1e1_log_level = LOG_ERROR; -static int log_level_default = LOG_ERROR; -module_param(cxt1e1_log_level, int, 0444); - -int cxt1e1_max_mru = MUSYCC_MRU; -static int max_mru_default = MUSYCC_MRU; -module_param(cxt1e1_max_mru, int, 0444); - -int cxt1e1_max_mtu = MUSYCC_MTU; -int max_mtu_default = MUSYCC_MTU; -module_param(cxt1e1_max_mtu, int, 0444); - -int max_txdesc_used = MUSYCC_TXDESC_MIN; -int max_txdesc_default = MUSYCC_TXDESC_MIN; -module_param(max_txdesc_used, int, 0444); - -int max_rxdesc_used = MUSYCC_RXDESC_MIN; -int max_rxdesc_default = MUSYCC_RXDESC_MIN; -module_param(max_rxdesc_used, int, 0444); - -/****************************************************************************/ -/****************************************************************************/ -/****************************************************************************/ - -void * -getuserbychan(int channum) -{ - mch_t *ch; - - ch = c4_find_chan(channum); - return ch ? ch->user : NULL; -} - - -char * -get_hdlc_name(hdlc_device *hdlc) -{ - struct c4_priv *priv = hdlc->priv; - struct net_device *dev = getuserbychan(priv->channum); - - return dev->name; -} - -/***************************************************************************/ -#include <linux/workqueue.h> - -/*** - * One workqueue (wq) per port (since musycc allows simultaneous group - * commands), with individual data for each channel: - * - * mpi_t -> struct workqueue_struct *wq_port; (dynamically allocated using - * create_workqueue()) - * - * With work structure (work) statically allocated for each channel: - * - * mch_t -> struct work_struct ch_work; (statically allocated using ???) - * - ***/ - - -/* - * Called by the start transmit routine when a channel TX_ENABLE is to be - * issued. This queues the transmission start request among other channels - * within a port's group. - */ -void -c4_wk_chan_restart(mch_t *ch) -{ - mpi_t *pi = ch->up; - -#ifdef RLD_RESTART_DEBUG - pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", - __func__, pi->portnum, ch->channum, ch); -#endif - - /* create new entry w/in workqueue for this channel and let'er rip */ - - /** queue_work(struct workqueue_struct *queue, - ** struct work_struct *work); - **/ - queue_work(pi->wq_port, &ch->ch_work); -} - -status_t -c4_wk_chan_init(mpi_t *pi, mch_t *ch) -{ - /* - * this will be used to restart a stopped channel - */ - - /** INIT_WORK(struct work_struct *work, - ** void (*function)(void *), - ** void *data); - **/ - INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); - return 0; /* success */ -} - -status_t -c4_wq_port_init(mpi_t *pi) -{ - - char name[16]; /* NOTE: name of the queue limited by system - * to 10 characters */ - if (pi->wq_port) - return 0; /* already initialized */ - - /* IE pmcc4-01 */ - snprintf(name, sizeof(name), "%s%d", pi->up->devname, pi->portnum); - -#ifdef RLD_RESTART_DEBUG - pr_info(">> %s: creating workqueue <%s> for Port %d.\n", - __func__, name, pi->portnum); /* RLD DEBUG */ -#endif - pi->wq_port = create_singlethread_workqueue(name); - if (!pi->wq_port) - return -ENOMEM; - return 0; /* success */ -} - -void -c4_wq_port_cleanup(mpi_t *pi) -{ - /* - * PORT POINT: cannot call this if WQ is statically allocated w/in - * structure since it calls kfree(wq); - */ - if (pi->wq_port) { - destroy_workqueue(pi->wq_port); /* this also calls - * flush_workqueue() */ - pi->wq_port = NULL; - } -} - -/***************************************************************************/ - -static irqreturn_t -c4_linux_interrupt(int irq, void *dev_instance) -{ - struct net_device *ndev = dev_instance; - - return musycc_intr_th_handler(netdev_priv(ndev)); -} - - -#ifdef CONFIG_SBE_PMCC4_NCOMM -static irqreturn_t -c4_ebus_interrupt(int irq, void *dev_instance) -{ - struct net_device *ndev = dev_instance; - - return c4_ebus_intr_th_handler(netdev_priv(ndev)); -} -#endif - - -static int -void_open(struct net_device *ndev) -{ - pr_info("%s: trying to open master device !\n", ndev->name); - return -1; -} - - -static int -chan_open(struct net_device *ndev) -{ - hdlc_device *hdlc = dev_to_hdlc(ndev); - const struct c4_priv *priv = hdlc->priv; - int ret; - - ret = hdlc_open(ndev); - if (ret) { - pr_info("hdlc_open failure, err %d.\n", ret); - return ret; - } - - ret = c4_chan_up(priv->ci, priv->channum); - if (ret < 0) - return ret; - try_module_get(THIS_MODULE); - netif_start_queue(ndev); - return 0; /* no error = success */ -} - - -static int -chan_close(struct net_device *ndev) -{ - hdlc_device *hdlc = dev_to_hdlc(ndev); - const struct c4_priv *priv = hdlc->priv; - - netif_stop_queue(ndev); - musycc_chan_down((ci_t *) 0, priv->channum); - hdlc_close(ndev); - module_put(THIS_MODULE); - return 0; -} - - -static int -chan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - return hdlc_ioctl(dev, ifr, cmd); -} - - -static int -chan_attach_noop(struct net_device *ndev, unsigned short foo_1, - unsigned short foo_2) -{ - /* our driver has nothing to do here, show's - * over, go home - */ - return 0; -} - - -static struct net_device_stats * -chan_get_stats(struct net_device *ndev) -{ - mch_t *ch; - struct net_device_stats *nstats; - struct sbecom_chan_stats *stats; - int channum; - - { - struct c4_priv *priv; - - priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; - channum = priv->channum; - } - - ch = c4_find_chan(channum); - if (ch == NULL) - return NULL; - - nstats = &ndev->stats; - stats = &ch->s; - - memset(nstats, 0, sizeof(struct net_device_stats)); - nstats->rx_packets = stats->rx_packets; - nstats->tx_packets = stats->tx_packets; - nstats->rx_bytes = stats->rx_bytes; - nstats->tx_bytes = stats->tx_bytes; - nstats->rx_errors = stats->rx_length_errors + - stats->rx_over_errors + - stats->rx_crc_errors + - stats->rx_frame_errors + - stats->rx_fifo_errors + - stats->rx_missed_errors; - nstats->tx_errors = stats->tx_dropped + - stats->tx_aborted_errors + - stats->tx_fifo_errors; - nstats->rx_dropped = stats->rx_dropped; - nstats->tx_dropped = stats->tx_dropped; - - nstats->rx_length_errors = stats->rx_length_errors; - nstats->rx_over_errors = stats->rx_over_errors; - nstats->rx_crc_errors = stats->rx_crc_errors; - nstats->rx_frame_errors = stats->rx_frame_errors; - nstats->rx_fifo_errors = stats->rx_fifo_errors; - nstats->rx_missed_errors = stats->rx_missed_errors; - - nstats->tx_aborted_errors = stats->tx_aborted_errors; - nstats->tx_fifo_errors = stats->tx_fifo_errors; - - return nstats; -} - - -static ci_t * -get_ci_by_dev(struct net_device *ndev) -{ - return (ci_t *)(netdev_priv(ndev)); -} - - -static int -c4_linux_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - const struct c4_priv *priv; - int rval; - - hdlc_device *hdlc = dev_to_hdlc(ndev); - - priv = hdlc->priv; - - rval = musycc_start_xmit(priv->ci, priv->channum, skb); - return rval; -} - -static const struct net_device_ops chan_ops = { - .ndo_open = chan_open, - .ndo_stop = chan_close, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = chan_dev_ioctl, - .ndo_get_stats = chan_get_stats, -}; - -static struct net_device * -create_chan(struct net_device *ndev, ci_t *ci, - struct sbecom_chan_param *cp) -{ - hdlc_device *hdlc; - struct net_device *dev; - hdw_info_t *hi; - int ret; - - if (c4_find_chan(cp->channum)) - return NULL; /* channel already exists */ - - { - struct c4_priv *priv; - - /* allocate then fill in private data structure */ - priv = kzalloc(sizeof(struct c4_priv), GFP_KERNEL); - if (!priv) { - pr_warning("%s: no memory for net_device !\n", - ci->devname); - return NULL; - } - dev = alloc_hdlcdev(priv); - if (!dev) { - pr_warning("%s: no memory for hdlc_device !\n", - ci->devname); - kfree(priv); - return NULL; - } - priv->ci = ci; - priv->channum = cp->channum; - } - - hdlc = dev_to_hdlc(dev); - - dev->base_addr = 0; /* not I/O mapped */ - dev->irq = ndev->irq; - dev->type = ARPHRD_RAWHDLC; - *dev->name = 0; /* default ifconfig name = "hdlc" */ - - hi = (hdw_info_t *)ci->hdw_info; - if (hi->mfg_info_sts == EEPROM_OK) { - switch (hi->promfmt) { - case PROM_FORMAT_TYPE1: - memcpy(dev->dev_addr, - (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - break; - case PROM_FORMAT_TYPE2: - memcpy(dev->dev_addr, - (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - break; - default: - memset(dev->dev_addr, 0, 6); - break; - } - } else - memset(dev->dev_addr, 0, 6); - - hdlc->xmit = c4_linux_xmit; - - dev->netdev_ops = &chan_ops; - /* - * The native hdlc stack calls this 'attach' routine during - * hdlc_raw_ioctl(), passing parameters for line encoding and parity. - * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' - * routine is actually registered or not, we supply a dummy routine which - * does nothing (since encoding and parity are setup for our driver via a - * special configuration application). - */ - - hdlc->attach = chan_attach_noop; - - /* needed due to Ioctl calling sequence */ - rtnl_unlock(); - ret = register_hdlc_device(dev); - /* NOTE: <stats> setting must occur AFTER registration in order to "take" */ - dev->tx_queue_len = MAX_DEFAULT_IFQLEN; - - /* needed due to Ioctl calling sequence */ - rtnl_lock(); - if (ret) { - if (cxt1e1_log_level >= LOG_WARN) - pr_info("%s: create_chan[%d] registration error = %d.\n", - ci->devname, cp->channum, ret); - /* cleanup */ - free_netdev(dev); - /* failed to register */ - return NULL; - } - return dev; -} - - -/* the idea here is to get port information and pass it back (using pointer) */ -static status_t -do_get_port(struct net_device *ndev, void *data) -{ - int ret; - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ - - if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; /* get card info */ - - ret = c4_get_port(ci, pp.portnum); - if (ret < 0) - return ret; - if (copy_to_user(data, &ci->port[pp.portnum].p, - sizeof(struct sbecom_port_param))) - return -EFAULT; - return 0; -} - -/* this function copys the user data and then calls the real action function */ -static status_t -do_set_port(struct net_device *ndev, void *data) -{ - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ - - if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; /* get card info */ - - if (pp.portnum >= ci->max_port) /* sanity check */ - return -ENXIO; - - memcpy(&ci->port[pp.portnum].p, &pp, sizeof(struct sbecom_port_param)); - return c4_set_port(ci, pp.portnum); -} - -/* work the port loopback mode as per directed */ -static status_t -do_port_loop(struct net_device *ndev, void *data) -{ - struct sbecom_port_param pp; - ci_t *ci; - - if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - return c4_loop_port(ci, pp.portnum, pp.port_mode); -} - -/* set the specified register with the given value / or just read it */ -static status_t -do_framer_rw(struct net_device *ndev, void *data) -{ - struct sbecom_port_param pp; - ci_t *ci; - int ret; - - if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - ret = c4_frame_rw(ci, &pp); - if (ret < 0) - return ret; - if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) - return -EFAULT; - return 0; -} - -/* set the specified register with the given value / or just read it */ -static status_t -do_pld_rw(struct net_device *ndev, void *data) -{ - struct sbecom_port_param pp; - ci_t *ci; - int ret; - - if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - - ret = c4_pld_rw(ci, &pp); - if (ret) - return ret; - if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) - return -EFAULT; - return 0; -} - -/* set the specified register with the given value / or just read it */ -static status_t -do_musycc_rw(struct net_device *ndev, void *data) -{ - struct c4_musycc_param mp; - ci_t *ci; - int ret; - - if (copy_from_user(&mp, data, sizeof(struct c4_musycc_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - ret = c4_musycc_rw(ci, &mp); - if (ret < 0) - return ret; - if (copy_to_user(data, &mp, sizeof(struct c4_musycc_param))) - return -EFAULT; - return 0; -} - -static status_t -do_get_chan(struct net_device *ndev, void *data) -{ - struct sbecom_chan_param cp; - int ret; - - if (copy_from_user(&cp, data, - sizeof(struct sbecom_chan_param))) - return -EFAULT; - - ret = c4_get_chan(cp.channum, &cp); - if (ret < 0) - return ret; - - if (copy_to_user(data, &cp, sizeof(struct sbecom_chan_param))) - return -EFAULT; - return 0; -} - -static status_t -do_set_chan(struct net_device *ndev, void *data) -{ - struct sbecom_chan_param cp; - ci_t *ci; - - if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - return c4_set_chan(cp.channum, &cp); -} - -static status_t -do_create_chan(struct net_device *ndev, void *data) -{ - ci_t *ci; - struct net_device *dev; - struct sbecom_chan_param cp; - int ret; - - if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - dev = create_chan(ndev, ci, &cp); - if (!dev) - return -EBUSY; - ret = c4_new_chan(ci, cp.port, cp.channum, dev); - if (ret < 0) { - /* needed due to Ioctl calling sequence */ - rtnl_unlock(); - unregister_hdlc_device(dev); - /* needed due to Ioctl calling sequence */ - rtnl_lock(); - free_netdev(dev); - } - return ret; -} - -static status_t -do_get_chan_stats(struct net_device *ndev, void *data) -{ - struct c4_chan_stats_wrap ccs; - int ret; - - if (copy_from_user(&ccs, data, - sizeof(struct c4_chan_stats_wrap))) - return -EFAULT; - - ret = c4_get_chan_stats(ccs.channum, &ccs.stats); - if (ret < 0) - return ret; - - if (copy_to_user(data, &ccs, - sizeof(struct c4_chan_stats_wrap))) - return -EFAULT; - return 0; -} -static status_t -do_set_loglevel(struct net_device *ndev, void *data) -{ - unsigned int cxt1e1_log_level; - - if (copy_from_user(&cxt1e1_log_level, data, sizeof(int))) - return -EFAULT; - sbecom_set_loglevel(cxt1e1_log_level); - return 0; -} - -static status_t -do_deluser(struct net_device *ndev, int lockit) -{ - if (ndev->flags & IFF_UP) - return -EBUSY; - - { - ci_t *ci; - mch_t *ch; - const struct c4_priv *priv; - int channum; - - priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; - ci = priv->ci; - channum = priv->channum; - - ch = c4_find_chan(channum); - if (ch == NULL) - return -ENOENT; - ch->user = NULL; /* will be freed, below */ - } - - /* needed if Ioctl calling sequence */ - if (lockit) - rtnl_unlock(); - unregister_hdlc_device(ndev); - /* needed if Ioctl calling sequence */ - if (lockit) - rtnl_lock(); - free_netdev(ndev); - return 0; -} - -int -do_del_chan(struct net_device *musycc_dev, void *data) -{ - struct sbecom_chan_param cp; - char buf[sizeof(CHANNAME) + 3]; - struct net_device *dev; - int ret; - - if (copy_from_user(&cp, data, - sizeof(struct sbecom_chan_param))) - return -EFAULT; - if (cp.channum > 999) - return -EINVAL; - snprintf(buf, sizeof(buf), CHANNAME "%d", cp.channum); - dev = __dev_get_by_name(&init_net, buf); - if (!dev) - return -ENODEV; - ret = do_deluser(dev, 1); - if (ret) - return ret; - return c4_del_chan(cp.channum); -} -int c4_reset_board(void *); - -int -do_reset(struct net_device *musycc_dev, void *data) -{ - const struct c4_priv *priv; - int i; - - for (i = 0; i < 128; i++) { - struct net_device *ndev; - char buf[sizeof(CHANNAME) + 3]; - - sprintf(buf, CHANNAME "%d", i); - ndev = __dev_get_by_name(&init_net, buf); - if (!ndev) - continue; - priv = dev_to_hdlc(ndev)->priv; - - if ((unsigned long) (priv->ci) == - (unsigned long) (netdev_priv(musycc_dev))) { - ndev->flags &= ~IFF_UP; - netif_stop_queue(ndev); - do_deluser(ndev, 1); - } - } - return 0; -} - -int -do_reset_chan_stats(struct net_device *musycc_dev, void *data) -{ - struct sbecom_chan_param cp; - - if (copy_from_user(&cp, data, - sizeof(struct sbecom_chan_param))) - return -EFAULT; - return c4_del_chan_stats(cp.channum); -} - -static status_t -c4_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) -{ - ci_t *ci; - void *data; - int iocmd, iolen; - status_t ret; - static struct data { - union { - u_int8_t c; - u_int32_t i; - struct sbe_brd_info bip; - struct sbe_drv_info dip; - struct sbe_iid_info iip; - struct sbe_brd_addr bap; - struct sbecom_chan_stats stats; - struct sbecom_chan_param param; - struct temux_card_stats cards; - struct sbecom_card_param cardp; - struct sbecom_framer_param frp; - } u; - } arg; - - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (cmd != SIOCDEVPRIVATE + 15) - return -EINVAL; - ci = get_ci_by_dev(ndev); - if (!ci) - return -EINVAL; - if (ci->state != C_RUNNING) - return -ENODEV; - if (copy_from_user(&iocmd, ifr->ifr_data, sizeof(iocmd))) - return -EFAULT; -#if 0 - if (copy_from_user(&len, ifr->ifr_data + sizeof(iocmd), sizeof(len))) - return -EFAULT; -#endif - -#if 0 - pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, - _IOC_DIR(iocmd), _IOC_TYPE(iocmd), _IOC_NR(iocmd), - _IOC_SIZE(iocmd)); -#endif - iolen = _IOC_SIZE(iocmd); - if (iolen > sizeof(arg)) - return -EFAULT; - data = ifr->ifr_data + sizeof(iocmd); - if (copy_from_user(&arg, data, iolen)) - return -EFAULT; - - ret = 0; - switch (iocmd) { - case SBE_IOC_PORT_GET: - ret = do_get_port(ndev, data); - break; - case SBE_IOC_PORT_SET: - ret = do_set_port(ndev, data); - break; - case SBE_IOC_CHAN_GET: - ret = do_get_chan(ndev, data); - break; - case SBE_IOC_CHAN_SET: - ret = do_set_chan(ndev, data); - break; - case C4_DEL_CHAN: - ret = do_del_chan(ndev, data); - break; - case SBE_IOC_CHAN_NEW: - ret = do_create_chan(ndev, data); - break; - case SBE_IOC_CHAN_GET_STAT: - ret = do_get_chan_stats(ndev, data); - break; - case SBE_IOC_LOGLEVEL: - ret = do_set_loglevel(ndev, data); - break; - case SBE_IOC_RESET_DEV: - ret = do_reset(ndev, data); - break; - case SBE_IOC_CHAN_DEL_STAT: - ret = do_reset_chan_stats(ndev, data); - break; - case C4_LOOP_PORT: - ret = do_port_loop(ndev, data); - break; - case C4_RW_FRMR: - ret = do_framer_rw(ndev, data); - break; - case C4_RW_MSYC: - ret = do_musycc_rw(ndev, data); - break; - case C4_RW_PLD: - ret = do_pld_rw(ndev, data); - break; - case SBE_IOC_IID_GET: - ret = (iolen == sizeof(struct sbe_iid_info)) ? - c4_get_iidinfo(ci, &arg.u.iip) : -EFAULT; - if (ret == 0) /* no error, copy data */ - if (copy_to_user(data, &arg, iolen)) - return -EFAULT; - break; - default: - ret = -EINVAL; - break; - } - return ret; -} - -static const struct net_device_ops c4_ops = { - .ndo_open = void_open, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = c4_ioctl, -}; - -static void c4_setup(struct net_device *dev) -{ - dev->type = ARPHRD_VOID; - dev->netdev_ops = &c4_ops; -} - -struct net_device *__init -c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, - int irq0, int irq1) -{ - struct net_device *ndev; - ci_t *ci; - - ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); - if (!ndev) { - pr_warning("%s: no memory for struct net_device !\n", - hi->devname); - error_flag = -ENOMEM; - return NULL; - } - ci = (ci_t *)(netdev_priv(ndev)); - ndev->irq = irq0; - - ci->hdw_info = hi; - ci->state = C_INIT; /* mark as hardware not available */ - ci->next = c4_list; - c4_list = ci; - ci->brdno = ci->next ? ci->next->brdno + 1 : 0; - - if (!CI) - CI = ci; /* DEBUG, only board 0 usage */ - - strcpy(ci->devname, hi->devname); - - /* tasklet */ -#if defined(SBE_ISR_TASKLET) - tasklet_init(&ci->ci_musycc_isr_tasklet, - (void (*) (unsigned long)) musycc_intr_bh_tasklet, - (unsigned long) ci); - - if (atomic_read(&ci->ci_musycc_isr_tasklet.count) == 0) - tasklet_disable_nosync(&ci->ci_musycc_isr_tasklet); -#elif defined(SBE_ISR_IMMEDIATE) - ci->ci_musycc_isr_tq.routine = (void *)(unsigned long)musycc_intr_bh_tasklet; - ci->ci_musycc_isr_tq.data = ci; -#endif - - - if (register_netdev(ndev) || - (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) { - kfree(netdev_priv(ndev)); - kfree(ndev); - error_flag = -ENODEV; - return NULL; - } - /************************************************************* - * int request_irq(unsigned int irq, - * void (*handler)(int, void *, struct pt_regs *), - * unsigned long flags, const char *dev_name, void *dev_id); - * wherein: - * irq -> The interrupt number that is being requested. - * handler -> Pointer to handling function being installed. - * flags -> A bit mask of options related to interrupt management. - * dev_name -> String used in /proc/interrupts to show owner of interrupt. - * dev_id -> Pointer (for shared interrupt lines) to point to its own - * private data area (to identify which device is interrupting). - * - * extern void free_irq(unsigned int irq, void *dev_id); - **************************************************************/ - - if (request_irq(irq0, &c4_linux_interrupt, - IRQF_SHARED, - ndev->name, ndev)) { - pr_warning("%s: MUSYCC could not get irq: %d\n", - ndev->name, irq0); - unregister_netdev(ndev); - kfree(netdev_priv(ndev)); - kfree(ndev); - error_flag = -EIO; - return NULL; - } -#ifdef CONFIG_SBE_PMCC4_NCOMM - if (request_irq(irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) { - pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); - unregister_netdev(ndev); - free_irq(irq0, ndev); - kfree(netdev_priv(ndev)); - kfree(ndev); - error_flag = -EIO; - return NULL; - } -#endif - - /* setup board identification information */ - - { - u_int32_t tmp; - - /* also sets PROM format type (promfmt) for later usage */ - hdw_sn_get(hi, brdno); - - switch (hi->promfmt) { - case PROM_FORMAT_TYPE1: - memcpy(ndev->dev_addr, - (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - /* unaligned data acquisition */ - memcpy(&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); - ci->brd_id = cpu_to_be32(tmp); - break; - case PROM_FORMAT_TYPE2: - memcpy(ndev->dev_addr, - (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - /* unaligned data acquisition */ - memcpy(&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); - ci->brd_id = cpu_to_be32(tmp); - break; - default: - ci->brd_id = 0; - memset(ndev->dev_addr, 0, 6); - break; - } - -#if 1 - /* requires bid to be preset */ - sbeid_set_hdwbid(ci); -#else - /* requires hdw_bid to be preset */ - sbeid_set_bdtype(ci); -#endif - } - -#ifdef CONFIG_PROC_FS - sbecom_proc_brd_init(ci); -#endif -#if defined(SBE_ISR_TASKLET) - tasklet_enable(&ci->ci_musycc_isr_tasklet); -#endif - - error_flag = c4_init2(ci); - if (error_flag != SBE_DRVR_SUCCESS) { -#ifdef CONFIG_PROC_FS - sbecom_proc_brd_cleanup(ci); -#endif - unregister_netdev(ndev); - free_irq(irq1, ndev); - free_irq(irq0, ndev); - kfree(netdev_priv(ndev)); - kfree(ndev); - /* failure, error_flag is set */ - return NULL; - } - return ndev; -} - -static int __init -c4_mod_init(void) -{ - int rtn; - - rtn = c4hw_attach_all(); - if (rtn) - return -rtn; /* installation failure - see system log */ - - /* housekeeping notifications */ - if (cxt1e1_log_level != log_level_default) - pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n", - log_level_default, cxt1e1_log_level); - if (cxt1e1_max_mru != max_mru_default) - pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n", - max_mru_default, cxt1e1_max_mru); - if (cxt1e1_max_mtu != max_mtu_default) - pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n", - max_mtu_default, cxt1e1_max_mtu); - if (max_rxdesc_used != max_rxdesc_default) { - if (max_rxdesc_used > 2000) - max_rxdesc_used = 2000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n", - max_rxdesc_default, max_rxdesc_used); - } - if (max_txdesc_used != max_txdesc_default) { - if (max_txdesc_used > 1000) - max_txdesc_used = 1000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n", - max_txdesc_default, max_txdesc_used); - } - return 0; /* installation success */ -} - - - /* - * find any still allocated hdlc registrations and unregister via call to - * do_deluser() - */ - -static void __exit -cleanup_hdlc(void) -{ - hdw_info_t *hi; - ci_t *ci; - struct net_device *ndev; - int i, j, k; - - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { - if (hi->ndev) { /* a board has been attached */ - ci = (ci_t *)(netdev_priv(hi->ndev)); - for (j = 0; j < ci->max_port; j++) - for (k = 0; k < MUSYCC_NCHANS; k++) { - ndev = ci->port[j].chan[k]->user; - if (ndev) - do_deluser(ndev, 0); - } - } - } -} - - -static void __exit -c4_mod_remove(void) -{ - cleanup_hdlc(); /* delete any missed channels */ - cleanup_devs(); - c4_cleanup(); - cleanup_ioremap(); - pr_info("SBE - driver removed.\n"); -} - -module_init(c4_mod_init); -module_exit(c4_mod_remove); - -MODULE_AUTHOR("SBE Technical Services <support@sbei.com>"); -MODULE_DESCRIPTION("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -/*** End-of-File ***/ |