/* 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. T