wanpipe-kernel-sources/kdrivers/src/wan_aften/wan_aften.c

1423 lines
35 KiB
C

#include "wanpipe_includes.h"
#include "wanpipe_api.h"
#include "wan_aften.h"
#if 0
# define DEBUG_REG
#endif
#define WAN_AFTEN_FE_RW 0
#if WAN_AFTEN_FE_RW
#ifndef DEFINE_MUTEX
# define DEFINE_MUTEX
#endif
# include "wanpipe_common.h"
# define DEBUG_FE_EXPORT if(0)DEBUG_EVENT
static wan_mutexlock_t rw_mutex;
int wan_aftup_te1_reg_write(void *card, unsigned short reg, unsigned short in_data);
int wan_aftup_te1_reg_read(void *card, unsigned short reg, unsigned char *out_data);
/* Maxim chip definitions */
#define REG_IDR 0xF8
#define DEVICE_ID_DS26519 0xD9
#define DEVICE_ID_DS26528 0x0B
#define DEVICE_ID_DS26524 0x0C
#define DEVICE_ID_DS26522 0x0D
#define DEVICE_ID_DS26521 0x0E
#define DEVICE_ID_BAD 0x00
#define DEVICE_ID_SHIFT 3
#define DEVICE_ID_MASK 0x1F
#define DEVICE_ID_DS(dev_id) ((dev_id) >> DEVICE_ID_SHIFT) & DEVICE_ID_MASK
#define DECODE_CHIPID(chip_id) \
(chip_id == DEVICE_ID_DS26519) ? "DS26519" : \
(chip_id == DEVICE_ID_DS26528) ? "DS26528" : \
(chip_id == DEVICE_ID_DS26524) ? "DS26524" : \
(chip_id == DEVICE_ID_DS26522) ? "DS26522" : \
(chip_id == DEVICE_ID_DS26521) ? "DS26521" : "Unknown"
#endif
static char *wan_drvname = "wan_aften";
static char wan_fullname[] = "WANPIPE(tm) Sangoma AFT (lite) Driver";
static char wan_copyright[] = "(c) 1995-2008 Sangoma Technologies Inc.";
static int ncards;
static sdla_t* card_list = NULL; /* adapter data space */
extern wan_iface_t wan_iface;
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
static int wan_aften_callback_add_device(void);
static int wan_aften_callback_delete_device(char *);
extern sdladrv_callback_t sdladrv_callback;
extern int sdla_get_hw_usb_adptr_cnt (void);
#endif
static int wan_aften_init(void*);
static int wan_aften_exit(void*);
#if 0
static int wan_aften_shutdown(void*);
static int wan_aften_ready_unload(void*);
#endif
static int wan_aften_add_device(int index);
static int wan_aften_delete_device(sdla_t *card);
static int wan_aften_setup(sdla_t *card, netdevice_t *dev);
static int wan_aften_release(sdla_t *card);
static int wan_aften_update_ports(void);
static int wan_aften_open(netdevice_t*);
static int wan_aften_close(netdevice_t*);
static int wan_aften_ioctl (netdevice_t*, struct ifreq*, wan_ioctl_cmd_t);
#if defined(__OpenBSD__)
struct cdevsw wan_aften_devsw = {
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
WAN_MODULE_DEFINE(
wan_aften,"wan_aften",
"Alex Feldman <al.feldman@sangoma.com>",
"WAN AFT Enable",
"GPL",
wan_aften_init, wan_aften_exit,/* wan_aften_shutdown, wan_aften_ready_unload,*/
&wan_aften_devsw);
#else
WAN_MODULE_DEFINE(
wan_aften,"wan_aften",
"Alex Feldman <al.feldman@sangoma.com>",
"WAN AFT Enable",
"GPL",
wan_aften_init, wan_aften_exit,/*wan_aften_shutdown, wan_aften_ready_unload,*/
NULL);
#endif
WAN_MODULE_DEPEND(wan_aften, sdladrv, 1, SDLADRV_MAJOR_VER, SDLADRV_MAJOR_VER);
WAN_MODULE_VERSION(wan_aften, WAN_AFTEN_VER);
static int wan_aften_init(void *arg)
{
int err = 0, i, extra_ncards = 0;
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
sdladrv_callback.add_device = wan_aften_callback_add_device;
sdladrv_callback.delete_device = wan_aften_callback_delete_device;
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__)
sdladrv_init();
#endif
sdladrv_hw_mode(SDLADRV_MODE_LIMITED);
DEBUG_EVENT("%s v%d %s\n",
wan_fullname,
WAN_AFTEN_VER,
wan_copyright);
ncards = sdla_hw_probe();
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
ncards += sdla_get_hw_usb_adptr_cnt();
#endif
if (!(ncards+extra_ncards)){
DEBUG_EVENT("No Sangoma cards found, unloading modules!\n");
return -ENODEV;
}
for (i=0;i<ncards;i++){
if (wan_aften_add_device(i)){
goto wan_aften_init_done;
}
}
wan_aften_update_ports();
wan_aften_init_done:
if (err) wan_aften_exit(arg);
return err;
}
static int wan_aften_exit(void *arg)
{
sdla_t *card;
int err = 0;
for (card=card_list;card_list;){
DEBUG_EVENT("%s: Unregistering device\n",
card->devname);
wan_aften_delete_device(card);
card_list = card->list;
wan_free(card);
card = card_list;
}
card_list=NULL;
#if defined(__OpenBSD__) || defined(__NetBSD__)
sdladrv_exit();
#endif
DEBUG_EVENT("\n");
DEBUG_EVENT("%s Unloaded.\n", wan_fullname);
return err;
}
#if 0
int wan_aften_shutdown(void *arg)
{
DEBUG_EVENT("Shutting down WAN_AFTEN module ...\n");
return 0;
}
int wan_aften_ready_unload(void *arg)
{
DEBUG_EVENT("Is WAN_AFTEN module ready to unload...\n");
return 0;
}
#endif
static int wan_aften_add_device(int index)
{
struct wan_aften_priv *priv = NULL;
struct wan_dev_le *devle;
sdla_t *card, *tmp;
wan_device_t *wandev;
netdevice_t *dev = NULL;
static int if_index = 0;
card=wan_malloc(sizeof(sdla_t));
if (!card){
DEBUG_EVENT("%s: Failed allocate new card!\n",
wan_drvname);
return -EINVAL;
}
memset(card, 0, sizeof(sdla_t));
/* Allocate HDLC device */
if (wan_iface.alloc)
dev = wan_iface.alloc(1,WAN_IFT_OTHER);
if (dev == NULL){
wan_free(card);
return -EINVAL;
}
devle = wan_malloc(sizeof(struct wan_dev_le));
if (devle == NULL){
DEBUG_EVENT("%s: Failed allocate memory!\n",
wan_drvname);
wan_free(card);
return -EINVAL;
}
if ((priv = wan_malloc(sizeof(struct wan_aften_priv))) == NULL){
DEBUG_EVENT("%s: Failed to allocate priv structure!\n",
wan_drvname);
wan_free(card);
wan_free(devle);
return -EINVAL;
}
priv->common.is_netdev = 1;
priv->common.iface.open = &wan_aften_open;
priv->common.iface.close = &wan_aften_close;
priv->common.iface.ioctl = &wan_aften_ioctl;
priv->common.card = card;
wan_netif_set_priv(dev, priv);
#if defined(__LINUX__)
/*sprintf(card->devname, "hdlc%d", if_index++);*/
sprintf(card->devname, "w%dg1", ++if_index);
#else
sprintf(card->devname, "w%cg1",
'a' + if_index++);
#endif
/* Register in HDLC device */
if (!wan_iface.attach || wan_iface.attach(dev, card->devname, 1)){
wan_free(devle);
if (wan_iface.free) wan_iface.free(dev);
return -EINVAL;
}
wandev = &card->wandev;
wandev->magic = ROUTER_MAGIC;
wandev->name = card->devname;
wandev->priv = card;
devle->dev = dev;
/* Set device pointer */
WAN_LIST_INIT(&wandev->dev_head);
WAN_LIST_INSERT_HEAD(&wandev->dev_head, devle, dev_link);
card->list = NULL;
if (card_list){
for(tmp = card_list;tmp->list;tmp = tmp->list);
tmp->list = card;
}else{
card_list = card;
}
#if 0
card->list = card_list;
card_list = card;
#endif
if (wan_aften_setup(card, dev)){
DEBUG_EVENT("%s: Failed setup new device!\n",
card->devname);
WAN_LIST_REMOVE(devle, dev_link);
wan_free(devle);
if (wan_iface.detach) wan_iface.detach(dev, 1);
if (wan_iface.free) wan_iface.free(dev);
if (card_list == card){
card_list = NULL;
}else{
for(tmp = card_list;
tmp->list != card; tmp = tmp->list);
tmp->list = card->list;
card->list = NULL;
}
wan_free(card);
return -EINVAL;
}
return 0;
}
static int wan_aften_delete_device(sdla_t *card)
{
struct wan_dev_le *devle;
devle = WAN_LIST_FIRST(&card->wandev.dev_head);
if (devle && devle->dev){
struct wan_aften_priv *priv = NULL;
priv = wan_netif_priv(devle->dev);
DEBUG_EVENT("%s: Unregistering interface...\n",
wan_netif_name(devle->dev));
if (wan_iface.detach)
wan_iface.detach(devle->dev, 1);
wan_free(priv);
if (wan_iface.free)
wan_iface.free(devle->dev);
WAN_LIST_REMOVE(devle, dev_link);
wan_free(devle);
}
DEBUG_EVENT("%s: Release device (%p)\n",
card->devname, card);
wan_aften_release(card);
return 0;
}
static int wan_aften_setup(sdla_t *card, netdevice_t *dev)
{
struct wan_aften_priv *priv = wan_netif_priv(dev);
int err;
card->hw = sdla_register(&card->hw_iface, NULL, card->devname);
if (card->hw == NULL){
DEBUG_EVENT("%s: Failed to register hw device\n",
card->devname);
goto wan_aften_setup_error;
}
err = card->hw_iface.setup(card->hw, NULL);
if (err){
DEBUG_EVENT("%s: Hardware setup Failed %d\n",
card->devname,err);
sdla_unregister(&card->hw, card->devname);
goto wan_aften_setup_error;
}
WAN_HWCALL(getcfg, (card->hw, SDLA_CARDTYPE, &card->type));
if (card->type != SDLA_USB){
WAN_HWCALL(getcfg, (card->hw, SDLA_BUS, &priv->bus));
WAN_HWCALL(getcfg, (card->hw, SDLA_SLOT, &priv->slot));
WAN_HWCALL(getcfg, (card->hw, SDLA_IRQ, &priv->irq));
WAN_HWCALL(pci_read_config_dword,
(card->hw, 0x04, &priv->base_class));
WAN_HWCALL(pci_read_config_dword,
(card->hw, PCI_IO_BASE_DWORD, &priv->base_addr0));
WAN_HWCALL(pci_read_config_dword,
(card->hw, PCI_MEM_BASE0_DWORD, &priv->base_addr1));
DEBUG_EVENT("%s: BaseClass %X BaseAddr %X:%X IRQ %d\n",
wan_netif_name(dev),
priv->base_class,
priv->base_addr0,
priv->base_addr1,
priv->irq);
/* Save pci bridge config (if needed) */
WAN_HWCALL(getcfg,
(card->hw, SDLA_PCIEXPRESS, &priv->pci_express_bridge));
if (priv->pci_express_bridge){
int off = 0;
WAN_HWCALL(pci_bridge_read_config_dword,
(card->hw, 0x04, &priv->pci_bridge_base_class));
WAN_HWCALL(pci_bridge_read_config_dword,
(card->hw, PCI_IO_BASE_DWORD, &priv->pci_bridge_base_addr0));
WAN_HWCALL(pci_bridge_read_config_dword,
(card->hw, PCI_MEM_BASE0_DWORD, &priv->pci_bridge_base_addr1));
WAN_HWCALL(pci_bridge_read_config_byte,
(card->hw, PCI_INT_LINE_BYTE, &priv->pci_bridge_irq));
for(off=0;off<=15;off++){
WAN_HWCALL(pci_bridge_read_config_dword,
(card->hw, off*4, &priv->pci_bridge_cfg[off]));
}
DEBUG_EVENT("%s: PCI_ExpressBridge: BaseClass %X BaseAddr %X:%X IRQ %d\n",
wan_netif_name(dev),
priv->pci_bridge_base_class,
priv->pci_bridge_base_addr0,
priv->pci_bridge_base_addr1,
priv->pci_bridge_irq);
}
#if defined(ENABLED_IRQ)
if(request_irq(irq, wan_aften_isr, SA_SHIRQ, card->devname, card)){
DEBUG_EVENT("%s: Can't reserve IRQ %d!\n",
card->devname, irq);
sdla_unregister(&card->hw, card->devname);
goto wan_aften_setup_error;
}
#endif
}else{
DEBUG_EVENT("%s: USB device is ready (%p)\n",
card->devname, card);
}
return 0;
wan_aften_setup_error:
return -EINVAL;
}
static int wan_aften_release(sdla_t *card)
{
if (card->type != SDLA_USB){
#if defined(ENABLED_IRQ)
struct wan_aften_priv *priv = wan_netif_priv(dev);
free_irq(priv->irq, card);
#endif
}
if (card->hw_iface.hw_down){
card->hw_iface.hw_down(card->hw);
}
if (card->hw){
sdla_unregister(&card->hw, card->devname);
}else{
DEBUG_EVENT("%s: ERROR: HW device pointer is NULL!\n",
card->devname);
}
return 0;
}
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
static int wan_aften_callback_add_device(void)
{
int err = 0;
err = wan_aften_add_device(0);
if (err){
DEBUG_EVENT("%s: ERROR: Failed to add new device!\n",
__FUNCTION__);
return -EINVAL;
}
return 0;
}
static int wan_aften_callback_delete_device(char *devname)
{
sdla_t *card, *card_prev = NULL;
int err = -ENODEV;
for (card=card_list;card;){
if (strcmp(card->devname, devname) == 0){
wan_aften_delete_device(card);
if (card_list == card){
card_list = card->list;
}else{
card_prev->list = card->list;
}
wan_free(card);
return 0;
}
card_prev = card;
card = card->list;
}
return err;
}
#endif
static int wan_aften_update_ports(void)
{
sdla_t *card, *prev = NULL;
#if 0
unsigned char *hwprobe;
int err;
#endif
DEBUG_TEST("\n\nList of available Sangoma devices:\n");
for (card=card_list; card; card = card->list){
netdevice_t *dev;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (dev){
if (prev && prev->hw == card->hw){
card->wandev.comm_port =
prev->wandev.comm_port + 1;
}
DEBUG_TEST("dev name: %s\n", wan_netif_name(dev));
#if 0
err = card->hw_iface.get_hwprobe(
card->hw,
card->wandev.comm_port,
(void**)&hwprobe);
if (!err){
hwprobe[strlen(hwprobe)] = '\0';
DEBUG_EVENT("%s: %s\n",
wan_netif_name(dev),
hwprobe);
}
#endif
}
prev = card;
}
return 0;
}
static int wan_aften_read_reg(sdla_t *card, wan_cmd_api_t *api_cmd, int idata)
{
if (api_cmd->len == 1){
if (api_cmd->offset <= 0x3C){
card->hw_iface.pci_read_config_byte(
card->hw,
api_cmd->offset,
(unsigned char*)&api_cmd->data[idata]);
}else{
card->hw_iface.bus_read_1(
card->hw,
api_cmd->offset,
(unsigned char*)&api_cmd->data[idata]);
}
DEBUG_TEST("%s: Reading Off=0x%08X Len=%i Data=0x%02X\n",
card->devname,
api_cmd->offset,
api_cmd->len,
*(unsigned char*)&api_cmd->data[idata]);
}else if (api_cmd->len == 2){
if (api_cmd->offset <= 0x3C){
card->hw_iface.pci_read_config_word(
card->hw,
api_cmd->offset,
(unsigned short*)&api_cmd->data[idata]);
}else{
card->hw_iface.bus_read_2(
card->hw,
api_cmd->offset,
(unsigned short*)&api_cmd->data[idata]);
}
DEBUG_TEST("%s: Reading Off=0x%08X Len=%i Data=0x%04X\n",
card->devname,
api_cmd->offset,
api_cmd->len,
*(unsigned short*)&api_cmd->data[idata]);
}else if (api_cmd->len == 4){
if (api_cmd->offset <= 0x3C){
card->hw_iface.pci_read_config_dword(
card->hw,
api_cmd->offset,
(unsigned int*)&api_cmd->data[idata]);
}else{
card->hw_iface.bus_read_4(
card->hw,
api_cmd->offset,
(unsigned int*)&api_cmd->data[idata]);
}
DEBUG_TEST("ADEBUG: %s: Reading Off=0x%08X Len=%i Data=0x%04X (idata=%d)\n",
card->devname,
api_cmd->offset,
api_cmd->len,
*(unsigned int*)&api_cmd->data[idata],
idata);
}else{
card->hw_iface.peek(
card->hw,
api_cmd->offset,
(unsigned char*)&api_cmd->data[idata],
api_cmd->len);
#if 0
memcpy_fromio((unsigned char*)&api_cmd.data[0],
(unsigned char*)vector, api_cmd.len);
#endif
DEBUG_TEST("%s: Reading Off=0x%08X Len=%i\n",
card->devname,
api_cmd->offset,
api_cmd->len);
}
return 0;
}
static int wan_aften_all_read_reg(sdla_t *card_head, wan_cmd_api_t *api_cmd)
{
sdla_t *card, *prev = NULL;
int idata = 0;
for (card=card_list; card; card = card->list){
#if 0
if (prev == NULL || prev->hw != card->hw){
#endif
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
wan_aften_read_reg(card, api_cmd, idata);
idata += api_cmd->len;
}
prev = card;
}
/*Update api_cmd->len to the new length of data to copy up
as the ioctl call will copy up only api_cmd->len to increase
the speed of a firmware update*/
api_cmd->len=idata;
return 0;
}
static int wan_aften_write_reg(sdla_t *card, wan_cmd_api_t *api_cmd)
{
if (api_cmd->len == 1){
card->hw_iface.bus_write_1(
card->hw,
api_cmd->offset,
*(unsigned char*)&api_cmd->data[0]);
DEBUG_TEST("%s: Write Offset=0x%08X Data=0x%02X\n",
card->devname,api_cmd->offset,
*(unsigned char*)&api_cmd->data[0]);
}else if (api_cmd->len == 2){
card->hw_iface.bus_write_2(
card->hw,
api_cmd->offset,
*(unsigned short*)&api_cmd->data[0]);
DEBUG_TEST("%s: Write Offset=0x%08X Data=0x%04X\n",
card->devname,api_cmd->offset,
*(unsigned short*)&api_cmd->data[0]);
}else if (api_cmd->len == 4){
card->hw_iface.bus_write_4(
card->hw,
api_cmd->offset,
*(unsigned int*)&api_cmd->data[0]);
DEBUG_TEST("ADEBUG: %s: Write Offset=0x%08X Data=0x%08X\n",
card->devname,api_cmd->offset,
*(unsigned int*)&api_cmd->data[0]);
}else{
card->hw_iface.poke(
card->hw,
api_cmd->offset,
(unsigned char*)&api_cmd->data[0],
api_cmd->len);
#if 0
memcpy_toio((unsigned char*)vector,
(unsigned char*)&api_cmd->data[0], api_cmd->len);
#endif
}
return 0;
}
static int wan_aften_all_write_reg(sdla_t *card_head, wan_cmd_api_t *api_cmd)
{
sdla_t *card, *prev = NULL;
for (card=card_list; card; card = card->list){
#if 0
if (prev == NULL || prev->hw != card->hw){
#endif
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
wan_aften_write_reg(card, api_cmd);
}
prev = card;
}
return 0;
}
static int wan_aften_set_pci_bios(sdla_t *card)
{
netdevice_t *dev = NULL;
struct wan_aften_priv *priv;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (dev == NULL){
return -EINVAL;
}
priv= wan_netif_priv(dev);
DEBUG_TEST("%s: Set PCI BaseClass %X BaseAddr0 %X BaseAddr1 %X IRQ %d\n",
wan_netif_name(dev),
priv->base_class,
priv->base_addr0,
priv->base_addr1,
priv->irq);
if (priv->pci_express_bridge){
int off = 0;
WAN_HWCALL(pci_bridge_write_config_dword,
(card->hw, 0x04, priv->pci_bridge_base_class));
WAN_HWCALL(pci_bridge_write_config_dword,
(card->hw, PCI_IO_BASE_DWORD, priv->pci_bridge_base_addr0));
WAN_HWCALL(pci_bridge_write_config_dword,
(card->hw, PCI_MEM_BASE0_DWORD, priv->pci_bridge_base_addr1));
WAN_HWCALL(pci_bridge_write_config_byte,
(card->hw, PCI_INT_LINE_BYTE, priv->pci_bridge_irq));
for(off=0;off<=15;off++){
WAN_HWCALL(pci_bridge_write_config_dword,
(card->hw, off*4, priv->pci_bridge_cfg[off]));
}
}
WP_DELAY(200);
card->hw_iface.pci_write_config_dword(
card->hw, 0x04, priv->base_class);
card->hw_iface.pci_write_config_dword(
card->hw, PCI_IO_BASE_DWORD, priv->base_addr0);
card->hw_iface.pci_write_config_dword(
card->hw, PCI_MEM_BASE0_DWORD, priv->base_addr1);
card->hw_iface.pci_write_config_byte(
card->hw, PCI_INT_LINE_BYTE, priv->irq);
return 0;
}
static int wan_aften_all_set_pci_bios(sdla_t *card_head)
{
sdla_t *card, *prev = NULL;
for (card=card_list; card; card = card->list){
#if 0
if (prev == NULL || prev->hw != card->hw){
#endif
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
if (wan_aften_set_pci_bios(card)){
return -EINVAL;
}
}
prev = card;
}
return 0;
}
static int wan_aften_hwprobe(sdla_t *card, wan_cmd_api_t *api_cmd)
{
netdevice_t *dev;
unsigned char *str;
int err;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (dev && card->hw_iface.get_hwprobe && card->hw_iface.getcfg){
char ver;
memcpy(&api_cmd->data[api_cmd->len],
wan_netif_name(dev),
strlen(wan_netif_name(dev)));
api_cmd->len += strlen(wan_netif_name(dev));
api_cmd->data[api_cmd->len++] = ':';
api_cmd->data[api_cmd->len++] = ' ';
err = card->hw_iface.get_hwprobe(
card->hw, card->wandev.comm_port, (void**)&str);
if (err){
return err;
}
str[strlen(str)] = '\0';
memcpy(&api_cmd->data[api_cmd->len], str, strlen(str));
api_cmd->len += strlen(str); /* set to number of cards */
api_cmd->data[api_cmd->len++] = ' ';
api_cmd->data[api_cmd->len++] = '(';
api_cmd->data[api_cmd->len++] = 'V';
api_cmd->data[api_cmd->len++] = 'e';
api_cmd->data[api_cmd->len++] = 'r';
api_cmd->data[api_cmd->len++] = '.';
err = card->hw_iface.getcfg(
card->hw, SDLA_COREREV, &ver);
if (err){
return err;
}
sprintf(&api_cmd->data[api_cmd->len], "%02X", ver);
api_cmd->len += 2;
api_cmd->data[api_cmd->len++] = ')';
api_cmd->data[api_cmd->len++] = '\n';
DEBUG_TEST("%s: Read card hwprobe (%s)!\n",
wan_netif_name(dev),
api_cmd->data);
}else{
return -EINVAL;
}
return 0;
}
static int wan_aften_all_hwprobe(sdla_t *card_head, wan_cmd_api_t *api_cmd)
{
sdla_t *card, *prev=NULL;
#if 0
int bus = -1, slot = -1;
#endif
int err = 0;
for (card=card_list; card; card = card->list){
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
if ((err = wan_aften_hwprobe(card, api_cmd))){
return err;
}
}
prev = card;
#if 0
netdevice_t *dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
struct wan_aften_priv *priv = wan_netif_priv(dev);
if (bus == -1 ||
!(bus == priv->bus && slot == priv->slot)){
if ((err = wan_aften_hwprobe(card, api_cmd))){
return err;
}
}
bus = priv->bus;
slot = priv->slot;
#endif
}
return 0;
}
static int
wan_aften_read_pcibridge_reg(sdla_t *card, wan_cmd_api_t *api_cmd, int idata)
{
if (card->hw_iface.pci_bridge_read_config_dword == NULL){
return -EINVAL;
}
card->hw_iface.pci_bridge_read_config_dword(
card->hw,
api_cmd->offset,
(u32*)&api_cmd->data[idata]);
DEBUG_TEST("%s: Reading value from %X: %X\n",
card->devname,
api_cmd->offset,
api_cmd->data[idata]);
return 0;
}
static int
wan_aften_all_read_pcibridge_reg(sdla_t *card_head, wan_cmd_api_t *api_cmd)
{
sdla_t *card, *prev = NULL;
int idata = 0;
for (card=card_list; card; card = card->list){
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
wan_aften_read_pcibridge_reg(card, api_cmd, idata);
idata += api_cmd->len;
}
prev = card;
}
return 0;
}
static int wan_aften_write_pcibridge_reg(sdla_t *card, wan_cmd_api_t *api_cmd)
{
if (card->hw_iface.pci_bridge_write_config_dword == NULL){
return -EINVAL;
}
card->hw_iface.pci_bridge_write_config_dword(
card->hw,
api_cmd->offset,
*(unsigned int*)&api_cmd->data[0]);
DEBUG_TEST("%s: Writing value %X to %X\n",
card->devname,
*(unsigned int*)&api_cmd->data[0],
api_cmd->offset);
return 0;
}
static int wan_aften_all_write_pcibridge_reg(sdla_t *card_head, wan_cmd_api_t *api_cmd)
{
sdla_t *card, *prev = NULL;
for (card=card_list; card; card = card->list){
if (prev == NULL||!card->hw_iface.hw_same(prev->hw, card->hw)){
wan_aften_write_pcibridge_reg(card, api_cmd);
}
prev = card;
}
return 0;
}
static int wan_aften_open(netdevice_t *dev)
{
WAN_NETIF_START_QUEUE(dev);
return 0;
}
static int wan_aften_close(netdevice_t *dev)
{
WAN_NETIF_STOP_QUEUE(dev);
return 0;
}
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
static int wan_aften_usb_write_access(sdla_t *card, wan_cmd_api_t *api_cmd)
{
if (card->type != SDLA_USB){
DEBUG_EVENT("%s: Unsupported command for current device!\n",
card->devname);
return -EINVAL;
}
switch(api_cmd->cmd){
case SIOC_WAN_USB_CPU_WRITE_REG:
DEBUG_TEST("%s: Write USB-CPU CMD: Reg:0x%02X <- 0x%02X\n",
card->devname,
(unsigned char)api_cmd->offset,
(unsigned char)api_cmd->data[0]);
api_cmd->ret = card->hw_iface.usb_cpu_write(
card->hw,
(u_int8_t)api_cmd->offset,
(u_int8_t)api_cmd->data[0]);
break;
case SIOC_WAN_USB_FW_DATA_WRITE:
if (api_cmd->len){
DEBUG_TEST("%s: Write USB-FXO DATA: %d (%d) bytes\n",
card->devname, api_cmd->len, api_cmd->offset);
api_cmd->len = card->hw_iface.usb_txdata_raw(
card->hw,
&api_cmd->data[0],
api_cmd->len);
api_cmd->ret = 0;
}else{
DEBUG_TEST("%s: Write USB-FXO DATA Ready?\n",
card->devname);
api_cmd->ret = card->hw_iface.usb_txdata_raw_ready(card->hw);
}
break;
case SIOC_WAN_USB_FE_WRITE_REG:
DEBUG_TEST("%s: Write USB-FXO CMD: Module:%d Reg:%d <- 0x%02X\n",
card->devname, api_cmd->bar,
(unsigned char)api_cmd->offset,
(unsigned char)api_cmd->data[0]);
api_cmd->ret = card->hw_iface.fe_write(card->hw,
api_cmd->bar,
(u_int8_t)api_cmd->offset,
(u_int8_t)api_cmd->data[0]);
break;
default:
DEBUG_EVENT("%s: %s:%d: Invalid command\n", card->devname,__FUNCTION__,__LINE__);
api_cmd->ret = -EBUSY;
break;
}
return 0;
}
static int wan_aften_usb_read_access(sdla_t *card, wan_cmd_api_t *api_cmd)
{
int err = 0;
if (card->type != SDLA_USB){
DEBUG_EVENT("%s: Unsupported command for current device!\n",
card->devname);
return -EINVAL;
}
switch(api_cmd->cmd){
case SIOC_WAN_USB_CPU_READ_REG:
api_cmd->data[0] = 0xFF;
/* Add function here */
err = card->hw_iface.usb_cpu_read(
card->hw,
(u_int8_t)api_cmd->offset,
(u_int8_t*)&api_cmd->data[0]);
if (err){
api_cmd->ret = -EBUSY;
return 0;
}
DEBUG_TEST("%s: Read USB-CPU CMD: Reg:0x%02x -> 0x%02X\n",
card->devname,
(unsigned char)api_cmd->offset,
(unsigned char)api_cmd->data[0]);
api_cmd->ret = 0;
api_cmd->len = 1;
break;
case SIOC_WAN_USB_FW_DATA_READ:
api_cmd->len =
card->hw_iface.usb_rxdata_raw( card->hw,
&api_cmd->data[0],
api_cmd->len);
DEBUG_TEST("%s: Read USB-FXO Data: %d (%d) bytes\n",
card->devname, api_cmd->ret, api_cmd->len);
api_cmd->ret = 0;
break;
case SIOC_WAN_USB_FE_READ_REG:
/* Add function here */
api_cmd->data[0] = card->hw_iface.fe_read(
card->hw,
api_cmd->bar,
(u_int8_t)api_cmd->offset);
DEBUG_TEST("%s: Read USB-FXO CMD: Mod:%d Reg:%d -> 0x%02X\n",
card->devname, api_cmd->bar,
(unsigned char)api_cmd->offset,
(unsigned char)api_cmd->data[0]);
api_cmd->ret = 0;
api_cmd->len = 1;
break;
default:
DEBUG_EVENT("%s: %s:%d: Invalid command\n", card->devname,__FUNCTION__,__LINE__);
api_cmd->ret = -EBUSY;
break;
}
return 0;
}
static int wan_aften_usb_fwupdate_enable(sdla_t *card)
{
if (card->type != SDLA_USB){
DEBUG_EVENT("%s: Unsupported command for current device!\n",
card->devname);
return -EINVAL;
}
return card->hw_iface.usb_fwupdate_enable(card->hw);
}
#endif
static int
wan_aften_ioctl (netdevice_t *dev, struct ifreq *ifr, wan_ioctl_cmd_t cmd)
{
sdla_t *card;
struct wan_aften_priv *priv= wan_netif_priv(dev);
wan_cmd_api_t *api_cmd;
wan_cmd_api_t *usr_api_cmd;
wan_cmd_api_t api_cmd_struct;
int err=-EINVAL;
api_cmd=&api_cmd_struct;
if (!priv || !priv->common.card){
DEBUG_EVENT("%s: Invalid structures!\n", wan_netif_name(dev));
return -ENODEV;
}
DEBUG_TEST("%s: CMD=0x%X\n",__FUNCTION__,cmd);
if (cmd != SIOC_WAN_DEVEL_IOCTL){
DEBUG_IOCTL("%s: Unsupported IOCTL call!\n",
wan_netif_name(dev));
return -EINVAL;
}
if (!ifr->ifr_data){
DEBUG_EVENT("%s: No API data!\n", wan_netif_name(dev));
return -EINVAL;
}
memset(api_cmd,0,sizeof(wan_cmd_api_t));
card = priv->common.card;
usr_api_cmd = (wan_cmd_api_t*)ifr->ifr_data;
/* Only copy the struct header + 8 bytes of data */
if (WAN_COPY_FROM_USER(api_cmd,usr_api_cmd,sizeof(wan_cmd_api_t)-WAN_MAX_CMD_DATA_SIZE+8)){
return -EFAULT;
}
/* If there is any length in data copy the data structure */
if (api_cmd->len) {
if (WAN_COPY_FROM_USER(api_cmd->data,usr_api_cmd->data,api_cmd->len)){
return -EFAULT;
}
}
/* Hardcode bar access FELD */
switch (api_cmd->cmd){
case SIOC_WAN_READ_REG:
err = wan_aften_read_reg(card, api_cmd, 0);
break;
case SIOC_WAN_ALL_READ_REG:
err = wan_aften_all_read_reg(card_list, api_cmd);
break;
case SIOC_WAN_WRITE_REG:
err = wan_aften_write_reg(card, api_cmd);
break;
case SIOC_WAN_ALL_WRITE_REG:
err = wan_aften_all_write_reg(card_list, api_cmd);
break;
case SIOC_WAN_SET_PCI_BIOS:
err = wan_aften_set_pci_bios(card);
break;
case SIOC_WAN_ALL_SET_PCI_BIOS:
err = wan_aften_all_set_pci_bios(card_list);
break;
case SIOC_WAN_HWPROBE:
DEBUG_TEST("%s: Read Sangoma device hwprobe!\n",
wan_netif_name(dev));
memset(&api_cmd->data[0], 0, WAN_MAX_CMD_DATA_SIZE);
api_cmd->len = 0;
err = wan_aften_hwprobe(card, api_cmd);
break;
case SIOC_WAN_ALL_HWPROBE:
DEBUG_TEST("%s: Read list of Sangoma devices!\n",
wan_netif_name(dev));
memset(&api_cmd->data[0], 0, WAN_MAX_CMD_DATA_SIZE);
api_cmd->len = 0;
err = wan_aften_all_hwprobe(card, api_cmd);
break;
case SIOC_WAN_COREREV:
if (card->hw_iface.getcfg){
err = card->hw_iface.getcfg(
card->hw,
SDLA_COREREV,
&api_cmd->data[0]);
api_cmd->len = 1;
}
DEBUG_TEST("%s: Get core revision (rev %X)!\n",
wan_netif_name(dev), api_cmd->data[0]);
break;
case SIOC_WAN_READ_PCIBRIDGE_REG:
err = wan_aften_read_pcibridge_reg(card, api_cmd, 0);
break;
case SIOC_WAN_ALL_READ_PCIBRIDGE_REG:
err = wan_aften_all_read_pcibridge_reg(card, api_cmd);
break;
case SIOC_WAN_WRITE_PCIBRIDGE_REG:
err = wan_aften_write_pcibridge_reg(card, api_cmd);
break;
case SIOC_WAN_ALL_WRITE_PCIBRIDGE_REG:
err = wan_aften_all_write_pcibridge_reg(card, api_cmd);
break;
#if defined(CONFIG_PRODUCT_WANPIPE_USB)
case SIOC_WAN_USB_CPU_READ_REG:
case SIOC_WAN_USB_FW_DATA_READ:
case SIOC_WAN_USB_FE_READ_REG:
err = wan_aften_usb_read_access(card, api_cmd);
break;
case SIOC_WAN_USB_CPU_WRITE_REG:
case SIOC_WAN_USB_FW_DATA_WRITE:
case SIOC_WAN_USB_FE_WRITE_REG:
err = wan_aften_usb_write_access(card, api_cmd);
break;
case SIOC_WAN_USB_FWUPDATE_ENABLE:
err = wan_aften_usb_fwupdate_enable(card);
break;
#endif
default:
DEBUG_EVENT("%s: Unknown WAN_AFTEN command %X\n",
card->devname, api_cmd->cmd);
}
DEBUG_TEST("%s: CMD Executed err= %d len=%i\n",card->devname,api_cmd->cmd,api_cmd->len);
if (WAN_COPY_TO_USER(usr_api_cmd,api_cmd,sizeof(wan_cmd_api_t)-WAN_MAX_CMD_DATA_SIZE)){
return -EFAULT;
}
if (api_cmd->len) {
if (api_cmd->len >= WAN_MAX_CMD_DATA_SIZE) {
DEBUG_EVENT("%s: Error API CMD exceeded available data space!\n",card->devname);
return -EFAULT;
}
if (WAN_COPY_TO_USER(usr_api_cmd->data,api_cmd->data,api_cmd->len)){
return -EFAULT;
}
}
return err;
}
#if WAN_AFTEN_FE_RW
/********* Private Functions **********/
static void wan_aftup_init_critical_section(void *pmutex)
{
wan_mutex_lock_init(pmutex, "fe_rw_mutex");
}
static void wan_aftup_enter_critical_section(void *pmutex)
{
wan_mutex_lock(pmutex, NULL);
}
static void wan_aftup_leave_critical_section(void *pmutex)
{
wan_mutex_unlock(pmutex, NULL);
}
static unsigned int wan_aft_read_maxim(void *card, int offset, int size, void *out_buffer)
{
int err;
wan_cmd_api_t api_cmd;
DEBUG_FE_EXPORT("%s()\n", __FUNCTION__);
memset(&api_cmd, 0x00, sizeof(api_cmd));
api_cmd.len = size;
api_cmd.offset = offset;
err = wan_aften_read_reg(card, &api_cmd, 0);
if (!err) {
memcpy(out_buffer, api_cmd.data, size);
}
return err;
}
static unsigned int wan_aft_write_maxim(void *card, int offset, int size, void *in_buffer)
{
int err;
wan_cmd_api_t api_cmd;
DEBUG_FE_EXPORT("%s()\n", __FUNCTION__);
memset(&api_cmd, 0x00, sizeof(api_cmd));
api_cmd.len = size;
api_cmd.offset = offset;
memcpy(api_cmd.data, in_buffer, size);
err = wan_aften_write_reg(card, &api_cmd);
return err;
}
unsigned int write_cpld(sdla_t *card, unsigned short cpld_off, unsigned short cpld_data)
{
cpld_off &= ~AFT8_BIT_DEV_ADDR_CLEAR;
cpld_off |= AFT8_BIT_DEV_ADDR_CPLD;
wan_aft_write_maxim(card, 0x46, 2, &cpld_off);
wan_aft_write_maxim(card, 0x44, 2, &cpld_data);
return 0;
}
static int wan_aften_te1_disable_global_chip_reset(sdla_t *card)
{
unsigned int data;
int err, i;
for (i = 0; i < 2; i++) {
/* put in reset */
write_cpld(card, 0x00, 0x06);
/* sangoma_msleep(50); */
/* Disable Global Chip/FrontEnd/CPLD Reset */
err = wan_aft_read_maxim(card, 0x40, 4, &data);
if (err){
return 1;
}
data &= ~0x6;
err = wan_aft_write_maxim(card, 0x40, 4, &data);
if (err){
return 1;
}
/* sangoma_msleep(50); */
}
return 0;
}
static int wan_aften_check_id_reg(sdla_t *card)
{
unsigned char val, fe_id;
wan_aftup_te1_reg_read(card, REG_IDR, &val);
DEBUG_FE_EXPORT("val = 0x%X\n", val);
fe_id = DEVICE_ID_DS(val);
switch(fe_id)
{
case DEVICE_ID_DS26528:
DEBUG_EVENT("Device is DS26528\n");
break;
case DEVICE_ID_DS26524:
DEBUG_EVENT("Device is DS26524\n");
break;
/*
case DEVICE_ID_DS26522: //not installed on Sangoma HW
DEBUG_EVENT("Device is DS26522!\n");
break;
*/
case DEVICE_ID_DS26521:
DEBUG_EVENT("Device is DS26521\n");
break;
default:
DEBUG_ERROR("Failed to read Maxim ID (%02X)\n", val);
return 1;
}
return 0;
}
/************ Public Functions ************/
void *wan_aftup_te1_global_init(int card_number)
{
sdla_t *card = NULL, *found_card = NULL;
int card_counter = 0;
DEBUG_FE_EXPORT("%s()\n", __FUNCTION__);
wan_aftup_init_critical_section(&rw_mutex);
for (card = card_list; card; card = card->list){
if (card_counter == card_number){
/* found the card */
found_card = card;
DEBUG_FE_EXPORT("card name: %s\n", card->devname);
break;
}
card_counter++;
}
if (!found_card) {
DEBUG_ERROR("Error: failed to find card_number %d",
card_number);
return NULL;
}
if (wan_aften_te1_disable_global_chip_reset(found_card)) {
return NULL;
}
/* read the Chip ID and check is it valid */
if (wan_aften_check_id_reg(found_card)) {
return NULL;
}
return found_card;
}
int wan_aftup_te1_reg_write(void *card, unsigned short reg, unsigned short in_data)
{
unsigned int tmp;
DEBUG_FE_EXPORT("%s()\n", __FUNCTION__);
wan_aftup_enter_critical_section(&rw_mutex);
if (reg & 0x800) reg |= 0x2000;
if (reg & 0x1000) reg |= 0x4000;
reg &= ~AFT8_BIT_DEV_ADDR_CLEAR;
//reg |= AFT8_BIT_DEV_MAXIM_ADDR_CPLD;
DEBUG_FE_EXPORT("%s(): Reg 0x%04X Data 0x%04X\n", __FUNCTION__, reg, in_data);
/* write the register where the data will be written to */
if (wan_aft_write_maxim(card, AFT_MCPU_INTERFACE_ADDR, 2, &reg)) {
DEBUG_ERROR("%s(): Failed to write to AFT_MCPU_INTERFACE_ADDR!\n",
__FUNCTION__);
wan_aftup_leave_critical_section(&rw_mutex);
/* return error */
return 1;
}
/* read to avoid bridge optimization of two writes by PCI */
if (wan_aft_read_maxim(card, AFT_MCPU_INTERFACE, 4, &tmp)) {
DEBUG_ERROR("%s(): Failed to read from AFT_MCPU_INTERFACE!\n",
__FUNCTION__);
wan_aftup_leave_critical_section(&rw_mutex);
/* return error */
return 1;
}
/* write the data to the register */
if (wan_aft_write_maxim(card, AFT_MCPU_INTERFACE, 2, &in_data)) {
DEBUG_ERROR("%s(): Failed to write to AFT_MCPU_INTERFACE!\n",
__FUNCTION__);
wan_aftup_leave_critical_section(&rw_mutex);
/* return error */
return 1;
}
wan_aftup_leave_critical_section(&rw_mutex);
/* return success */
return 0;
}
int wan_aftup_te1_reg_read(void *card, unsigned short reg, unsigned char *out_data)
{
unsigned int data;
DEBUG_FE_EXPORT("%s()\n", __FUNCTION__);
wan_aftup_enter_critical_section(&rw_mutex);
if (reg & 0x800) reg |= 0x2000;
if (reg & 0x1000) reg |= 0x4000;
reg &= ~AFT8_BIT_DEV_ADDR_CLEAR;
//reg |= AFT8_BIT_DEV_MAXIM_ADDR_CPLD;
/* write the register where data will be read from */
if (wan_aft_write_maxim(card, AFT_MCPU_INTERFACE_ADDR, 2, &reg)) {
DEBUG_ERROR("%s(): Failed to write to AFT_MCPU_INTERFACE_ADDR!\n",
__FUNCTION__);
wan_aftup_leave_critical_section(&rw_mutex);
/* return error */
return 1;
}
if (wan_aft_read_maxim(card, AFT_MCPU_INTERFACE, 4, &data)) {
DEBUG_ERROR("%s(): Failed to read from AFT_MCPU_INTERFACE!\n",
__FUNCTION__);
wan_aftup_leave_critical_section(&rw_mutex);
/* return error */
return 1;
}
DEBUG_FE_EXPORT("%s(): Reg 0x%04X Data 0x%08X\n", __FUNCTION__, reg, data);
/* store data in user buffer*/
*out_data = (unsigned char)data;
wan_aftup_leave_critical_section(&rw_mutex);
/* return success */
return 0;
}
/* exported functions to be called by other modules */
EXPORT_SYMBOL(wan_aftup_te1_global_init);
EXPORT_SYMBOL(wan_aftup_te1_reg_write);
EXPORT_SYMBOL(wan_aftup_te1_reg_read);
#endif /* WAN_AFTEN_FE_RW */