[svn-commits] fjoe: freebsd/trunk r8662 - /freebsd/trunk/drivers/dahdi/wctdm.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue May 18 01:05:54 CDT 2010


Author: fjoe
Date: Tue May 18 01:05:50 2010
New Revision: 8662

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8662
Log:
Initial version of wctdm port.

Modified:
    freebsd/trunk/drivers/dahdi/wctdm.c

Modified: freebsd/trunk/drivers/dahdi/wctdm.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/wctdm.c?view=diff&rev=8662&r1=8661&r2=8662
==============================================================================
--- freebsd/trunk/drivers/dahdi/wctdm.c (original)
+++ freebsd/trunk/drivers/dahdi/wctdm.c Tue May 18 01:05:50 2010
@@ -24,6 +24,18 @@
  */
 
 #if defined(__FreeBSD__)
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#define DPRINTF(dev, fmt, args...)      device_rlprintf(20, dev, fmt, ##args)
+
+#define set_current_state(x)
 #else /* !__FreeBSD__ */
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -206,6 +218,9 @@
 };
 
 struct wctdm {
+#if defined(__FreeBSD__)
+	struct pci_dev _dev;
+#endif
 	struct pci_dev *dev;
 	char *variety;
 	struct dahdi_span span;
@@ -269,6 +284,20 @@
 	unsigned char reg1shadow[NUM_CARDS];
 
 #if defined(__FreeBSD__)
+	struct resource *io_res;
+	int io_rid;
+
+	struct resource *irq_res;		/* resource for irq */
+	int irq_rid;
+	void *irq_handle;
+
+	uint32_t readdma;
+	bus_dma_tag_t   read_dma_tag;
+	bus_dmamap_t    read_dma_map;
+
+	uint32_t writedma;
+	bus_dma_tag_t   write_dma_tag;
+	bus_dmamap_t    write_dma_map;
 #else /* !__FreeBSD__ */
 	unsigned long ioaddr;
 	dma_addr_t 	readdma;
@@ -292,9 +321,11 @@
 static struct wctdm_desc wctdmi = { "Wildcard TDM400P REV I", 0 };
 static int acim2tiss[16] = { 0x0, 0x1, 0x4, 0x5, 0x7, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x2, 0x0, 0x3 };
 
+#if !defined(__FreeBSD__)
 static struct wctdm *ifaces[WC_MAX_IFACES];
 
 static void wctdm_release(struct wctdm *wc);
+#endif
 
 static unsigned int fxovoltage;
 static unsigned int battdebounce;
@@ -402,6 +433,9 @@
 #endif		
 	}
 
+#if defined(__FreeBSD__)
+	bus_dmamap_sync(wc->write_dma_tag, wc->write_dma_map, BUS_DMASYNC_PREWRITE);
+#endif
 }
 
 #ifdef AUDIO_RINGCHECK
@@ -465,6 +499,10 @@
 	else
 		/* Read is at interrupt address.  Valid data is available at normal offset */
 		readchunk = wc->readchunk;
+#if defined(__FreeBSD__)
+	bus_dmamap_sync(wc->read_dma_tag, wc->read_dma_map, BUS_DMASYNC_POSTREAD);
+#endif
+
 	for (x=0;x<DAHDI_CHUNKSIZE;x++) {
 #ifdef __BIG_ENDIAN
 		if (wc->cardflag & (1 << 3))
@@ -671,12 +709,12 @@
     long origjiffies;
     int count = 0;
 
-    #define MAX 6000 /* attempts */
+    #define MAX_ATTEMPTS 6000 /* attempts */
 
 
     origjiffies = jiffies;
     /* Wait for indirect access */
-    while (count++ < MAX)
+    while (count++ < MAX_ATTEMPTS)
 	 {
 		data = __wctdm_getreg(wc, card, I_STATUS);
 
@@ -685,7 +723,7 @@
 
 	 }
 
-    if(count > (MAX-1)) printk(KERN_NOTICE " ##### Loop error (%02x) #####\n", data);
+    if(count > (MAX_ATTEMPTS-1)) printk(KERN_NOTICE " ##### Loop error (%02x) #####\n", data);
 
 	return 0;
 }
@@ -1132,7 +1170,11 @@
 	ints = wctdm_inb(wc, WC_INTSTAT);
 
 	if (!ints)
+#if defined(__FreeBSD__)
+		return FILTER_STRAY;
+#else
 		return IRQ_NONE;
+#endif
 
 	wctdm_outb(wc, WC_INTSTAT, ints);
 
@@ -1140,12 +1182,20 @@
 		/* Stop DMA, wait for watchdog */
 		printk(KERN_INFO "TDM PCI Master abort\n");
 		wctdm_stop_dma(wc);
+#if defined(__FreeBSD__)
+		return FILTER_HANDLED;
+#else
 		return IRQ_RETVAL(1);
+#endif
 	}
 	
 	if (ints & 0x20) {
 		printk(KERN_INFO "PCI Target abort\n");
+#if defined(__FreeBSD__)
+		return FILTER_HANDLED;
+#else
 		return IRQ_RETVAL(1);
+#endif
 	}
 
 	for (x=0;x<4;x++) {
@@ -1245,7 +1295,11 @@
 		wctdm_transmitprep(wc, ints);
 	}
 
+#if defined(__FreeBSD__)
+	return FILTER_HANDLED;
+#else
 	return IRQ_RETVAL(1);
+#endif
 }
 
 static int wctdm_voicedaa_insane(struct wctdm *wc, int card)
@@ -2155,9 +2209,11 @@
 						SLIC_LF_ACTIVE_FWD;
 		fxs->idletxhookstate = idlehookstate;
 	}
+#if !defined(__FreeBSD__)
 	/* If we're dead, release us now */
 	if (!wc->usecount && wc->dead) 
 		wctdm_release(wc);
+#endif /* !__FreeBSD__ */
 	return 0;
 }
 
@@ -2385,7 +2441,7 @@
 	sprintf(wc->span.name, "WCTDM/%d", wc->pos);
 	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
 	snprintf(wc->span.location, sizeof(wc->span.location) - 1,
-		 "PCI Bus %02d Slot %02d", wc->dev->bus->number, PCI_SLOT(wc->dev->devfn) + 1);
+		 "PCI Bus %02d Slot %02d", dahdi_pci_get_bus(wc->dev), dahdi_pci_get_slot(wc->dev) + 1);
 	wc->span.manufacturer = "Digium";
 	dahdi_copy_string(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype));
 	if (alawoverride) {
@@ -2405,7 +2461,7 @@
 	wc->span.chans = wc->chans;
 	wc->span.channels = NUM_CARDS;
 	wc->span.hooksig = wctdm_hooksig;
-	wc->span.irq = wc->dev->irq;
+	wc->span.irq = dahdi_pci_get_irq(wc->dev);
 	wc->span.open = wctdm_open;
 	wc->span.close = wctdm_close;
 	wc->span.flags = DAHDI_FLAG_RBS;
@@ -2610,6 +2666,7 @@
 	wctdm_outb(wc, WC_MASK1, 0x00);
 }
 
+#if !defined(__FreeBSD__)
 static int __devinit wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	int res;
@@ -2766,6 +2823,48 @@
 		else
 			wc->dead = 1;
 	}
+}
+#endif /* !__FreeBSD__ */
+
+static int
+wctdm_validate_params(void)
+{
+	int x;
+
+	for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
+		if (!strcmp(fxo_modes[x].name, opermode))
+			break;
+	}
+	if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
+		_opermode = x;
+	} else {
+		printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified.  Please choose one of:\n", opermode);
+		for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
+			printk(KERN_INFO "  %s\n", fxo_modes[x].name);
+		printk(KERN_INFO "Note this option is CASE SENSITIVE!\n");
+		return -ENODEV;
+	}
+
+	if (!strcmp(opermode, "AUSTRALIA")) {
+		boostringer = 1;
+		fxshonormode = 1;
+	}
+
+	/* for the voicedaa_check_hook defaults, if the user has not overridden
+	   them by specifying them as module parameters, then get the values
+	   from the selected operating mode
+	*/
+	if (battdebounce == 0) {
+		battdebounce = fxo_modes[_opermode].battdebounce;
+	}
+	if (battalarm == 0) {
+		battalarm = fxo_modes[_opermode].battalarm;
+	}
+	if (battthresh == 0) {
+		battthresh = fxo_modes[_opermode].battthresh;
+	}
+
+	return 0;
 }
 
 static struct pci_device_id wctdm_pci_tbl[] = {
@@ -2788,6 +2887,305 @@
 };
 
 #if defined(__FreeBSD__)
+SYSCTL_NODE(_dahdi, OID_AUTO, wctdm, CTLFLAG_RW, 0, "DAHDI wctdm");
+#define MODULE_PARAM_PREFIX "dahdi.wctdm"
+#define MODULE_PARAM_PARENT _dahdi_wctdm
+
+static void wctdm_dma_free(bus_dma_tag_t *ptag, bus_dmamap_t *pmap, void **pvaddr, uint32_t *ppaddr);
+
+static void
+wctdm_release_resources(struct wctdm *wc)
+{
+        /* disconnect the interrupt handler */
+	if (wc->irq_handle != NULL) {
+		bus_teardown_intr(wc->dev->dev, wc->irq_res, wc->irq_handle);
+		wc->irq_handle = NULL;
+	}
+
+	if (wc->irq_res != NULL) {
+		bus_release_resource(wc->dev->dev, SYS_RES_IRQ, wc->irq_rid, wc->irq_res);
+		wc->irq_res = NULL;
+	}
+
+	/* release DMA resources */
+	wctdm_dma_free(&wc->write_dma_tag, &wc->write_dma_map, __DECONST(void **, &wc->writechunk), &wc->writedma);
+	wctdm_dma_free(&wc->read_dma_tag, &wc->read_dma_map, __DECONST(void **, &wc->readchunk), &wc->readdma);
+
+	/* release memory window */
+	if (wc->io_res != NULL) {
+		bus_release_resource(wc->dev->dev, SYS_RES_IOPORT, wc->io_rid, wc->io_res);
+		wc->io_res = NULL;
+	}
+}
+
+static int
+wctdm_setup_intr(struct wctdm *wc)
+{
+	int error;
+
+	wc->irq_res = bus_alloc_resource_any(
+	     wc->dev->dev, SYS_RES_IRQ, &wc->irq_rid, RF_SHAREABLE | RF_ACTIVE);
+	if (wc->irq_res == NULL) {
+		device_printf(wc->dev->dev, "Can't allocate irq resource\n");
+		return -ENXIO;
+	}
+
+	error = bus_setup_intr(
+	    wc->dev->dev, wc->irq_res, INTR_TYPE_CLK | INTR_MPSAFE,
+	    wctdm_interrupt, NULL, wc, &wc->irq_handle);
+	if (error) {
+		device_printf(wc->dev->dev, "Can't setup interrupt handler (error %d)\n", error);
+		return -ENXIO;
+	}
+
+	return (0);
+}
+
+static void
+wctdm_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	uint32_t *paddr = arg;
+	*paddr = segs->ds_addr;
+}
+
+static int
+wctdm_dma_allocate(int size, bus_dma_tag_t *ptag, bus_dmamap_t *pmap, void **pvaddr, uint32_t *ppaddr)
+{
+	int res;
+
+	res = bus_dma_tag_create(NULL, 8, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    size, 1, size, BUS_DMA_ALLOCNOW, NULL, NULL, ptag);
+	if (res)
+		return res;
+
+	res = bus_dmamem_alloc(*ptag, pvaddr, BUS_DMA_NOWAIT | BUS_DMA_ZERO, pmap);
+	if (res) {
+		bus_dma_tag_destroy(*ptag);
+		*ptag = NULL;
+		return res;
+	}
+
+	res = bus_dmamap_load(*ptag, *pmap, *pvaddr, size, wctdm_dma_map_addr, ppaddr, 0);
+	if (res) {
+		bus_dmamem_free(*ptag, *pvaddr, *pmap);
+		*pvaddr = NULL;
+
+		bus_dmamap_destroy(*ptag, *pmap);
+		*pmap = NULL;
+
+		bus_dma_tag_destroy(*ptag);
+		*ptag = NULL;
+		return res;
+	}
+
+	return 0;
+}
+
+static void
+wctdm_dma_free(bus_dma_tag_t *ptag, bus_dmamap_t *pmap, void **pvaddr, uint32_t *ppaddr)
+{
+	if (*ppaddr != 0) {
+		bus_dmamap_unload(*ptag, *pmap);
+		*ppaddr = 0;
+	}
+	if (*pvaddr != NULL) {
+		bus_dmamem_free(*ptag, *pvaddr, *pmap);
+		*pvaddr = NULL;
+
+		bus_dmamap_destroy(*ptag, *pmap);
+		*pmap = NULL;
+	}
+	if (*ptag != NULL) {
+		bus_dma_tag_destroy(*ptag);
+		*ptag = NULL;
+	}
+}
+
+static int
+wctdm_device_probe(device_t dev)
+{
+	struct pci_device_id *id;
+	struct wctdm_desc *d;
+
+	id = dahdi_pci_device_id_lookup(dev, wctdm_pci_tbl);
+	if (id == NULL)
+		return ENXIO;
+
+	if (wctdm_validate_params())
+		return ENXIO;
+
+	/* found device */
+	device_printf(dev, "vendor=%x device=%x subvendor=%x\n",
+	    id->vendor, id->device, id->subvendor);
+	d = (struct wctdm_desc *) id->driver_data;
+	device_set_desc(dev, d->name);
+	return (0);
+}
+
+static int
+wctdm_device_attach(device_t dev)
+{
+	int x, cardcount;
+	int res;
+	struct pci_device_id *id;
+	struct wctdm_desc *d;
+	struct wctdm *wc;
+
+	id = dahdi_pci_device_id_lookup(dev, wctdm_pci_tbl);
+	if (id == NULL)
+		return ENXIO;
+
+	d = (struct wctdm_desc *) id->driver_data;
+	wc = device_get_softc(dev);
+	wc->dev = &wc->_dev;
+	wc->dev->dev = dev;
+	for (x = 0; x < sizeof(wc->chans)/sizeof(wc->chans[0]); ++x) {
+		wc->chans[x] = &wc->_chans[x];
+	}
+	spin_lock_init(&wc->lock);
+	wc->curcard = -1;
+	wc->pos = device_get_unit(dev);
+	wc->variety = d->name;
+	for (x=0; x < NUM_CARDS; x++)
+		wc->flags[x] = d->flags;
+
+        /* allocate IO resource */
+	wc->io_rid = PCIR_BAR(0);
+	wc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wc->io_rid, RF_ACTIVE);
+	if (wc->io_res == NULL) {
+		device_printf(dev, "Can't allocate IO resource\n");
+		return ENXIO;
+	}
+
+	/* enable bus mastering */
+	pci_enable_busmaster(dev);
+
+	res = wctdm_setup_intr(wc);
+	if (res)
+		goto err;
+
+	/* allocate enough memory for two zt chunks.  Each sample uses
+	   32 bits.  Allocate an extra set just for control too */
+	res = wctdm_dma_allocate(DAHDI_MAX_CHUNKSIZE * 2 * 2 * 4, &wc->write_dma_tag, &wc->write_dma_map,
+	    __DECONST(void **, &wc->writechunk), &wc->writedma);
+	if (res)
+		goto err;
+
+	res = wctdm_dma_allocate(DAHDI_MAX_CHUNKSIZE * 2 * 2 * 4, &wc->read_dma_tag, &wc->read_dma_map,
+	    __DECONST(void **, &wc->readchunk), &wc->readdma);
+	if (res)
+		goto err;
+
+	if (wctdm_initialize(wc) < 0) {
+		printk(KERN_NOTICE "wctdm: Unable to intialize FXS\n");
+
+		res = ENXIO;
+		goto err;
+	}
+
+	if (wctdm_hardware_init(wc)) {
+		res = ENXIO;
+		goto err;
+	}
+
+	wctdm_post_initialize(wc);
+
+	/* enable interrupts */
+	wctdm_enable_interrupts(wc);
+
+	/* start DMA */
+	wctdm_start_dma(wc);
+
+	cardcount = 0;
+	for (x = 0; x < NUM_CARDS; x++) {
+		if (wc->cardflag & (1 << x))
+			cardcount++;
+	}
+	printk(KERN_INFO "Found a Wildcard TDM: %s (%d modules)\n", wc->variety, cardcount);
+
+	return 0;
+
+err:
+	/* Set Reset Low */
+	x = wctdm_inb(wc, WC_CNTL);
+	wctdm_outb(wc, WC_CNTL, (~0x1)&x);
+
+	/* Unregister */
+	if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->span.flags))
+		dahdi_unregister(&wc->span);
+
+	/* release resources */
+	wctdm_release_resources(wc);
+	return res;
+}
+
+static int
+wctdm_device_detach(device_t dev)
+{
+	struct wctdm *wc = device_get_softc(dev);
+
+	/* Stop any DMA */
+	wctdm_stop_dma(wc);
+	wctdm_reset_tdm(wc);
+
+	/* In case hardware is still there */
+	wctdm_disable_interrupts(wc);
+
+	/* Reset PCI chip and registers */
+	wctdm_outb(wc, WC_CNTL, 0x0e);
+
+	/* Unregister */
+	dahdi_unregister(&wc->span);
+
+	/* Release resources */
+	wctdm_release_resources(wc);
+
+	return (0);
+}
+
+static int
+wctdm_device_shutdown(device_t dev)
+{
+	DPRINTF(dev, "%s shutdown\n", device_get_name(dev));
+	return (0);
+}
+
+static int
+wctdm_device_suspend(device_t dev)
+{
+	DPRINTF(dev, "%s suspend\n", device_get_name(dev));
+	return (0);
+}
+
+static int
+wctdm_device_resume(device_t dev)
+{
+	DPRINTF(dev, "%s resume\n", device_get_name(dev));
+	return (0);
+}
+
+static device_method_t wctdm_methods[] = {
+	DEVMETHOD(device_probe,     wctdm_device_probe),
+	DEVMETHOD(device_attach,    wctdm_device_attach),
+	DEVMETHOD(device_detach,    wctdm_device_detach),
+	DEVMETHOD(device_shutdown,  wctdm_device_shutdown),
+	DEVMETHOD(device_suspend,   wctdm_device_suspend),
+	DEVMETHOD(device_resume,    wctdm_device_resume),
+	{ 0, 0 }
+};
+
+static driver_t wctdm_pci_driver = {
+	"wctdm",
+	wctdm_methods,
+	sizeof(struct wctdm)
+};
+
+static devclass_t wctdm_devclass;
+
+DRIVER_MODULE(wctdm, pci, wctdm_pci_driver, wctdm_devclass, 0, 0);
+MODULE_DEPEND(wctdm, pci, 1, 1, 1);
+MODULE_DEPEND(wctdm, dahdi, 1, 1, 1);
 #else /* !__FreeBSD__ */
 MODULE_DEVICE_TABLE(pci, wctdm_pci_tbl);
 
@@ -2803,40 +3201,10 @@
 static int __init wctdm_init(void)
 {
 	int res;
-	int x;
-
-	for (x = 0; x < (sizeof(fxo_modes) / sizeof(fxo_modes[0])); x++) {
-		if (!strcmp(fxo_modes[x].name, opermode))
-			break;
-	}
-	if (x < sizeof(fxo_modes) / sizeof(fxo_modes[0])) {
-		_opermode = x;
-	} else {
-		printk(KERN_NOTICE "Invalid/unknown operating mode '%s' specified.  Please choose one of:\n", opermode);
-		for (x = 0; x < sizeof(fxo_modes) / sizeof(fxo_modes[0]); x++)
-			printk(KERN_INFO "  %s\n", fxo_modes[x].name);
-		printk(KERN_INFO "Note this option is CASE SENSITIVE!\n");
+
+	res = wctdm_validate_params();
+	if (res)
 		return -ENODEV;
-	}
-
-	if (!strcmp(opermode, "AUSTRALIA")) {
-		boostringer = 1;
-		fxshonormode = 1;
-	}
-
-	/* for the voicedaa_check_hook defaults, if the user has not overridden
-	   them by specifying them as module parameters, then get the values
-	   from the selected operating mode
-	*/
-	if (battdebounce == 0) {
-		battdebounce = fxo_modes[_opermode].battdebounce;
-	}
-	if (battalarm == 0) {
-		battalarm = fxo_modes[_opermode].battalarm;
-	}
-	if (battthresh == 0) {
-		battthresh = fxo_modes[_opermode].battthresh;
-	}
 
 	res = dahdi_pci_module(&wctdm_driver);
 	if (res)




More information about the svn-commits mailing list