diff options
author | Bob Beers <bob.beers@gmail.com> | 2010-03-04 08:40:46 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-11 11:35:31 -0700 |
commit | 50ee11fe383255db8e5c3307319d470015616f27 (patch) | |
tree | d6900a217a10602d53199d360487548650e100e2 /drivers/staging/cxt1e1/hwprobe.c | |
parent | 588063a10f4e21cd3a2cc693c0c1ebb846ac4ce5 (diff) |
staging: Add driver to support wanPMC-CxT1E1 card.
Obviously still needs serious attention, but it compiles.
Original author: Rick Dobbs
Add driver to support wanPMC-CxT1E1 card.
This card provides 1-4 ports of T1E1 in PMC form factor.
Note, Rick doesn't want his email showing up as the "From:" author, but
has given his blessing to have the code included in the kernel tree.
Signed-off-by: Bob Beers <bob.beers@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/cxt1e1/hwprobe.c')
-rw-r--r-- | drivers/staging/cxt1e1/hwprobe.c | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c new file mode 100644 index 000000000000..0f9d6539a9a6 --- /dev/null +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -0,0 +1,400 @@ +/* Copyright (C) 2007 One Stop Systems + * Copyright (C) 2003-2005 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. + */ + +#include <linux/netdevice.h> +#include <linux/hdlc.h> +#include <linux/if_arp.h> +#include <asm/uaccess.h> +#include <linux/rtnetlink.h> +#include <linux/pci.h> +#include "pmcc4_sysdep.h" +#include "sbecom_inline_linux.h" +#include "libsbew.h" +#include "pmcc4_private.h" +#include "pmcc4.h" +#include "pmcc4_ioctls.h" +#include "pmc93x6_eeprom.h" +#ifdef CONFIG_PROC_FS +#include "sbeproc.h" +#endif + +#ifdef SBE_INCLUDE_SYMBOLS +#define STATIC +#else +#define STATIC static +#endif + +extern int log_level; +extern int error_flag; +extern int drvr_state; + +/* forward references */ +void c4_stopwd (ci_t *); +struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int); + + +struct s_hdw_info hdw_info[MAX_BOARDS]; + + +void __init +show_two (hdw_info_t * hi, int brdno) +{ + ci_t *ci; + struct pci_dev *pdev; + char *bid; + char *bp, banner[80]; + char sn[6]; + + bp = banner; + memset (banner, 0, 80); /* clear print buffer */ + + ci = (ci_t *)(netdev_priv(hi->ndev)); + bid = sbeid_get_bdname (ci); + switch (hi->promfmt) + { + case PROM_FORMAT_TYPE1: + memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + break; + case PROM_FORMAT_TYPE2: + memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + break; + default: + memset (sn, 0, 6); + break; + } + + sprintf (banner, "%s: %s S/N %06X, MUSYCC Rev %02X", + hi->devname, bid, + ((sn[3] << 16) & 0xff0000) | + ((sn[4] << 8) & 0x00ff00) | + (sn[5] & 0x0000ff), + (u_int8_t) hi->revid[0]); + + printk ("%s\n", banner); + + pdev = hi->pdev[0]; + printk ("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "MUSYCC", + (unsigned long) hi->addr_mapped[0], hi->addr[0], + hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), + (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); + + pdev = hi->pdev[1]; + printk ("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "EBUS ", + (unsigned long) hi->addr_mapped[1], hi->addr[1], + hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), + (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); +} + + +void __init +hdw_sn_get (hdw_info_t * hi, int brdno) +{ + /* obtain hardware EEPROM information */ + long addr; + + addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; + + /* read EEPROM with largest known format size... */ + pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2)); + +#if 0 + { + unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; + + printk ("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); + printk ("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); + printk ("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); + printk ("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); + printk ("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); + printk ("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); + } +#endif +#if 0 + printk ("sn: %x %x %x %x %x %x\n", + hi->mfg_info.Serial[0], + hi->mfg_info.Serial[1], + hi->mfg_info.Serial[2], + hi->mfg_info.Serial[3], + hi->mfg_info.Serial[4], + hi->mfg_info.Serial[5]); +#endif + + if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) + { + /* bad crc, data is suspect */ + if (log_level >= LOG_WARN) + printk ("%s: EEPROM cksum error\n", hi->devname); + hi->mfg_info_sts = EEPROM_CRCERR; + } else + hi->mfg_info_sts = EEPROM_OK; +} + + +void __init +prep_hdw_info (void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + hi->pci_busno = 0xff; + hi->pci_slot = 0xff; + hi->pci_pin[0] = 0; + hi->pci_pin[1] = 0; + hi->ndev = 0; + hi->addr[0] = 0L; + hi->addr[1] = 0L; + hi->addr_mapped[0] = 0L; + hi->addr_mapped[1] = 0L; + } +} + +void +cleanup_ioremap (void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->pci_slot == 0xff) + break; + if (hi->addr_mapped[0]) + { + iounmap ((void *) (hi->addr_mapped[0])); + release_mem_region ((long) hi->addr[0], hi->len[0]); + hi->addr_mapped[0] = 0; + } + if (hi->addr_mapped[1]) + { + iounmap ((void *) (hi->addr_mapped[1])); + release_mem_region ((long) hi->addr[1], hi->len[1]); + hi->addr_mapped[1] = 0; + } + } +} + + +void +cleanup_devs (void) +{ + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->pci_slot == 0xff || !hi->ndev) + break; + c4_stopwd(netdev_priv(hi->ndev)); +#ifdef CONFIG_PROC_FS + sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); +#endif + unregister_netdev (hi->ndev); + free_irq (hi->pdev[0]->irq, hi->ndev); +#ifdef CONFIG_SBE_PMCC4_NCOMM + free_irq (hi->pdev[1]->irq, hi->ndev); +#endif + OS_kfree (hi->ndev); + } +} + + +STATIC int __init +c4_hdw_init (struct pci_dev * pdev, int found) +{ + hdw_info_t *hi; + int i; + int fun, slot; + unsigned char busno = 0xff; + + /* our MUSYCC chip supports two functions, 0 & 1 */ + if ((fun = PCI_FUNC (pdev->devfn)) > 1) + { + printk (KERN_WARNING "%s: unexpected devfun: 0x%x\n", THIS_MODULE->name, pdev->devfn); + return 0; + } + if (pdev->bus) /* obtain bus number */ + busno = pdev->bus->number; + else + busno = 0; /* default for system PCI inconsistency */ + slot = pdev->devfn & ~0x07; + + /* + * Functions 0 & 1 for a given board (identified by same bus(busno) and + * slot(slot)) are placed into the same 'hardware' structure. The first + * part of the board's functionality will be placed into an unpopulated + * element, identified by "slot==(0xff)". The second part of a board's + * functionality will match the previously loaded slot/busno. + */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + /* + * match with board's first found interface, otherwise this is first + * found + */ + if ((hi->pci_slot == 0xff) || /* new board */ + ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) + break; /* found for-loop exit */ + } + if (i == MAX_BOARDS) /* no match in above loop means MAX + * exceeded */ + { + printk (KERN_WARNING "%s: exceeded number of allowed devices (>%d)?\n", + THIS_MODULE->name, MAX_BOARDS); + return 0; + } + if (pdev->bus) + hi->pci_busno = pdev->bus->number; + else + hi->pci_busno = 0; /* default for system PCI inconsistency */ + hi->pci_slot = slot; + pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); + pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]); + hi->bus = pdev->bus; + hi->addr[fun] = pci_resource_start (pdev, 0); + hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1; + hi->pdev[fun] = pdev; + + { + /* + * create device name from module name, plus add the appropriate + * board number + */ + char *cp = hi->devname; + + strcpy (cp, THIS_MODULE->name); + cp += strlen (cp); /* reposition */ + *cp++ = '-'; + *cp++ = '0' + (found / 2); /* there are two found interfaces per + * board */ + *cp = 0; /* termination */ + } + + return 1; +} + + +status_t __init +c4hw_attach_all (void) +{ + hdw_info_t *hi; + struct pci_dev *pdev = NULL; + int found = 0, i, j; + + error_flag = 0; + prep_hdw_info (); + /*** scan PCI bus for all possible boards */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT, + PCI_DEVICE_ID_CN8474, + pdev))) +#else + while ((pdev = pci_find_device (PCI_VENDOR_ID_CONEXANT, + PCI_DEVICE_ID_CN8474, + pdev))) +#endif + { + if (c4_hdw_init (pdev, found)) + found++; + } + if (!found) + { + printk (KERN_WARNING "%s: No boards found.\n", THIS_MODULE->name); + return ENODEV; + } + /* sanity check for consistant hardware found */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) + { + printk (KERN_WARNING "%s: something very wrong with pci_get_device.\n", hi->devname); + return EIO; + } + } + /* bring board's memory regions on/line */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->pci_slot == 0xff) + break; + for (j = 0; j < 2; j++) + { + if (request_mem_region (hi->addr[j], hi->len[j], hi->devname) == 0) + { + printk (KERN_WARNING "%s: memory in use, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap (); + return ENOMEM; + } + hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); + if (!hi->addr_mapped[j]) + { + printk (KERN_WARNING "%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap (); + return ENOMEM; + } +#ifdef SBE_MAP_DEBUG + printk (KERN_WARNING "%s: io remapped from phys %x to virt %x\n", + hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]); +#endif + } + } + + drvr_state = SBE_DRVR_AVAILABLE; + + /* Have now memory mapped all boards. Now allow board's access to system */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->pci_slot == 0xff) + break; + if (pci_enable_device (hi->pdev[0]) || + pci_enable_device (hi->pdev[1])) + { + drvr_state = SBE_DRVR_DOWN; + printk (KERN_WARNING "%s: failed to enable card %d slot %d\n", + hi->devname, i, hi->pci_slot); + cleanup_devs (); + cleanup_ioremap (); + return EIO; + } + pci_set_master (hi->pdev[0]); + pci_set_master (hi->pdev[1]); + if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0], + (long) hi->addr_mapped[1], + hi->pdev[0]->irq, + hi->pdev[1]->irq))) + { + drvr_state = SBE_DRVR_DOWN; + cleanup_ioremap (); + /* NOTE: c4_add_dev() does its own device cleanup */ +#if 0 + cleanup_devs (); +#endif + return error_flag; /* error_flag set w/in add_dev() */ + } + show_two (hi, i); /* displays found information */ + } + return 0; +} + +/*** End-of-File ***/ |