#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 ", "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 ", "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;idevname); 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, ®)) { 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, ®)) { 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 */