[svn-commits] fjoe: freebsd/trunk r8627 - /freebsd/trunk/drivers/dahdi/wcfxo.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun May 16 04:28:04 CDT 2010


Author: fjoe
Date: Sun May 16 04:28:01 2010
New Revision: 8627

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=8627
Log:
Initial FreeBSD port.

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

Modified: freebsd/trunk/drivers/dahdi/wcfxo.c
URL: http://svnview.digium.com/svn/dahdi/freebsd/trunk/drivers/dahdi/wcfxo.c?view=diff&rev=8627&r1=8626&r2=8627
==============================================================================
--- freebsd/trunk/drivers/dahdi/wcfxo.c (original)
+++ freebsd/trunk/drivers/dahdi/wcfxo.c Sun May 16 04:28:01 2010
@@ -23,6 +23,20 @@
  * this program for more details.
  */
 
+#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>
 #include <linux/module.h>
@@ -32,6 +46,7 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 #include <linux/moduleparam.h>
+#endif /* !__FreeBSD__ */
 
 #include <dahdi/kernel.h>
 
@@ -109,9 +124,15 @@
 #define PEGTIME		50 * 8		/* 50ms peak to peak gets us rings of 10 Hz or more */
 #define PEGCOUNT	5		/* 5 cycles of pegging means RING */
 
+#if defined(__FreeBSD__)
+#define	wcfxo_printk(level, span, fmt, ...)	\
+	printk(KERN_ ## level "%s-%s: %s: " fmt, #level,	\
+		"wcfxo", (span).name, ## __VA_ARGS__)
+#else
 #define	wcfxo_printk(level, span, fmt, ...)	\
 	printk(KERN_ ## level "%s-%s: %s: " fmt, #level,	\
 		THIS_MODULE->name, (span).name, ## __VA_ARGS__)
+#endif
 
 #define wcfxo_notice(span, fmt, ...) \
 	wcfxo_printk(NOTICE, span, fmt, ## __VA_ARGS__)
@@ -134,6 +155,9 @@
 };
 
 struct wcfxo {
+#if defined(__FreeBSD__)
+	struct pci_dev _dev;
+#endif
 	struct pci_dev *dev;
 	char *variety;
 	struct dahdi_span span;
@@ -170,9 +194,26 @@
 	unsigned char lasttx[DAHDI_CHUNKSIZE];
 	/* Up to 32 registers of whatever we most recently read */
 	unsigned char readregs[32];
+#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;
 	dma_addr_t	writedma;
+#endif /* !__FreeBSD__ */
 	volatile int *writechunk;					/* Double-word aligned write memory */
 	volatile int *readchunk;					/* Double-word aligned read memory */
 #ifdef ZERO_BATT_RING
@@ -210,9 +251,11 @@
 static struct wcfxo_desc generic = { "Generic Clone",
 		FLAG_USE_XTAL | FLAG_DOUBLE_CLOCK };
 
+#if !defined(__FreeBSD__)
 static struct wcfxo *ifaces[WC_MAX_IFACES];
 
 static void wcfxo_release(struct wcfxo *wc);
+#endif
 
 static int debug = 0;
 
@@ -240,6 +283,39 @@
 										   Greece, Iceland, Ireland, Italy, Luxembourg, Netherlands,
 										   Norway, Portugal, Spain, Sweden, Switzerland, and UK */
 };
+
+static inline u8
+wcfxo_inb(struct wcfxo *wc, int reg)
+{
+#if defined(__FreeBSD__)
+	return bus_space_read_1(rman_get_bustag(wc->io_res),
+	    rman_get_bushandle(wc->io_res), reg);
+#else
+	return inb(wc->ioaddr + reg);
+#endif
+}
+
+static inline void
+wcfxo_outb(struct wcfxo *wc, int reg, u8 value)
+{
+#if defined(__FreeBSD__)
+	bus_space_write_1(rman_get_bustag(wc->io_res),
+	    rman_get_bushandle(wc->io_res), reg, value);
+#else
+	outb(value, wc->ioaddr + reg);
+#endif
+}
+
+static inline void
+wcfxo_outl(struct wcfxo *wc, int reg, u32 value)
+{
+#if defined(__FreeBSD__)
+	bus_space_write_4(rman_get_bustag(wc->io_res),
+	    rman_get_bushandle(wc->io_res), reg, value);
+#else
+	outl(value, wc->ioaddr + reg);
+#endif
+}
 
 static inline void wcfxo_transmitprep(struct wcfxo *wc, unsigned char ints)
 {
@@ -322,6 +398,9 @@
 		wc->regs[x].flags = FLAG_EMPTY;
 	}
 
+#if defined(__FreeBSD__)
+	bus_dmamap_sync(wc->write_dma_tag, wc->write_dma_map, BUS_DMASYNC_PREWRITE);
+#endif
 }
 
 static inline void wcfxo_receiveprep(struct wcfxo *wc, unsigned char ints)
@@ -336,6 +415,9 @@
 		readchunk = wc->readchunk;
 	else
 		readchunk = wc->readchunk + DAHDI_CHUNKSIZE * 2;
+#if defined(__FreeBSD__)
+	bus_dmamap_sync(wc->read_dma_tag, wc->read_dma_map, BUS_DMASYNC_POSTREAD);
+#endif
 
 	/* Keep track of how quickly our peg alternates */
 	wc->pegtimer+=DAHDI_CHUNKSIZE;
@@ -437,13 +519,17 @@
 	static int oldcnt = 0;
 #endif
 
-	ints = inb(wc->ioaddr + WC_INTSTAT);
+	ints = wcfxo_inb(wc, WC_INTSTAT);
 
 
 	if (!ints)
+#if defined(__FreeBSD__)
+		return FILTER_STRAY;
+#else
 		return IRQ_NONE;
-
-	outb(ints, wc->ioaddr + WC_INTSTAT);
+#endif
+
+	wcfxo_outb(wc, WC_INTSTAT, ints);
 
 	if (ints & 0x0c) {  /* if there is a rx interrupt pending */
 #ifdef ENABLE_TASKLETS
@@ -466,12 +552,20 @@
 		printk(KERN_INFO "FXO PCI Master abort\n");
 		/* Stop DMA andlet the watchdog start it again */
 		wcfxo_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
 	}
 	if (1 /* !(wc->report % 0xf) */) {
 		/* Check for BATTERY from register and debounce for 8 ms */
@@ -546,7 +640,11 @@
 
 	}
 
+#if defined(__FreeBSD__)
+	return FILTER_HANDLED;
+#else
 	return IRQ_RETVAL(1);
+#endif
 }
 
 static int wcfxo_setreg(struct wcfxo *wc, unsigned char reg, unsigned char value)
@@ -584,9 +682,11 @@
 {
 	struct wcfxo *wc = chan->pvt;
 	wc->usecount--;
+#if !defined(__FreeBSD__)
 	/* If we're dead, release us now */
 	if (!wc->usecount && wc->dead)
 		wcfxo_release(wc);
+#endif /* !__FreeBSD__ */
 	return 0;
 }
 
@@ -641,7 +741,7 @@
 	snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
 	sprintf(wc->chan->name, "WCFXO/%d/%d", wc->pos, 0);
 	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));
 	wc->chan->sigcap = DAHDI_SIG_FXSKS | DAHDI_SIG_FXSLS | DAHDI_SIG_SF;
@@ -649,7 +749,7 @@
 	wc->span.chans = &wc->chan;
 	wc->span.channels = 1;
 	wc->span.hooksig = wcfxo_hooksig;
-	wc->span.irq = wc->dev->irq;
+	wc->span.irq = dahdi_pci_get_irq(wc->dev);
 	wc->span.open = wcfxo_open;
 	wc->span.close = wcfxo_close;
 	wc->span.flags = DAHDI_FLAG_RBS;
@@ -673,13 +773,13 @@
 {
 	/* Hardware stuff */
 	/* Reset PCI Interface chip and registers */
-	outb(0x0e, wc->ioaddr + WC_CNTL);
+	wcfxo_outb(wc, WC_CNTL, 0x0e);
 
 	/* Set all to outputs except AUX 4, which is an input */
-	outb(0xef, wc->ioaddr + WC_AUXC);
+	wcfxo_outb(wc, WC_AUXC, 0xef);
 
 	/* Reset the DAA (DAA uses AUX5 for reset) */
-	outb(0x00, wc->ioaddr + WC_AUXD);
+	wcfxo_outb(wc, WC_AUXD, 0x00);
 	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(1 + HZ / 800);
 
@@ -687,87 +787,87 @@
 	if (wc->flags & FLAG_RESET_ON_AUX5) {
 		/* Set hook state to on hook for when we switch.
 		   Make sure reset is high */
-		outb(0x34, wc->ioaddr + WC_AUXD);
+		wcfxo_outb(wc, WC_AUXD, 0x34);
 	} else {
 		/* Set hook state to on hook for when we switch */
-		outb(0x24, wc->ioaddr + WC_AUXD);
+		wcfxo_outb(wc, WC_AUXD, 0x24);
 	}
 
 	/* Back to normal, with automatic DMA wrap around */
-	outb(0x01, wc->ioaddr + WC_CNTL);
+	wcfxo_outb(wc, WC_CNTL, 0x01);
 
 	/* Make sure serial port and DMA are out of reset */
-	outb(inb(wc->ioaddr + WC_CNTL) & 0xf9, wc->ioaddr + WC_CNTL);
+	wcfxo_outb(wc, WC_CNTL, wcfxo_inb(wc, WC_CNTL) & 0xf9);
 
 	/* Configure serial port for MSB->LSB operation */
 	if (wc->flags & FLAG_DOUBLE_CLOCK)
-		outb(0xc1, wc->ioaddr + WC_SERCTL);
+		wcfxo_outb(wc, WC_SERCTL, 0xc1);
 	else
-		outb(0xc0, wc->ioaddr + WC_SERCTL);
+		wcfxo_outb(wc, WC_SERCTL, 0xc0);
 
 	if (wc->flags & FLAG_USE_XTAL) {
 		/* Use the crystal oscillator */
-		outb(0x04, wc->ioaddr + WC_AUXFUNC);
+		wcfxo_outb(wc, WC_AUXFUNC, 0x04);
 	}
 
 	/* Delay FSC by 2 so it's properly aligned */
-	outb(0x2, wc->ioaddr + WC_FSCDELAY);
+	wcfxo_outb(wc, WC_FSCDELAY, 0x2);
 
 	/* Setup DMA Addresses */
-	outl(wc->writedma,                    wc->ioaddr + WC_DMAWS);		/* Write start */
-	outl(wc->writedma + DAHDI_CHUNKSIZE * 8 - 4, wc->ioaddr + WC_DMAWI);		/* Middle (interrupt) */
-	outl(wc->writedma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMAWE);			/* End */
-	
-	outl(wc->readdma,                    	 wc->ioaddr + WC_DMARS);	/* Read start */
-	outl(wc->readdma + DAHDI_CHUNKSIZE * 8 - 4, 	 wc->ioaddr + WC_DMARI);	/* Middle (interrupt) */
-	outl(wc->readdma + DAHDI_CHUNKSIZE * 16 - 4, wc->ioaddr + WC_DMARE);	/* End */
-	
+	wcfxo_outl(wc, WC_DMAWS, wc->writedma);		/* Write start */
+	wcfxo_outl(wc, WC_DMAWI, wc->writedma + DAHDI_CHUNKSIZE * 8 - 4);	/* Middle (interrupt) */
+	wcfxo_outl(wc, WC_DMAWE, wc->writedma + DAHDI_CHUNKSIZE * 16 - 4);	/* End */
+
+	wcfxo_outl(wc, WC_DMARS, wc->readdma);		/* Read start */
+	wcfxo_outl(wc, WC_DMARI, wc->readdma + DAHDI_CHUNKSIZE * 8 - 4);	/* Middle (interrupt) */
+	wcfxo_outl(wc, WC_DMARE, wc->readdma + DAHDI_CHUNKSIZE * 16 - 4);	/* End */
+
 	/* Clear interrupts */
-	outb(0xff, wc->ioaddr + WC_INTSTAT);
+	wcfxo_outb(wc, WC_INTSTAT, 0xff);
 	return 0;
 }
 
 static void wcfxo_enable_interrupts(struct wcfxo *wc)
 {
 	/* Enable interrupts (we care about all of them) */
-	outb(0x3f, wc->ioaddr + WC_MASK0);
+	wcfxo_outb(wc, WC_MASK0, 0x3f);
 	/* No external interrupts */
-	outb(0x00, wc->ioaddr + WC_MASK1);
+	wcfxo_outb(wc, WC_MASK1, 0x00);
 }
 
 static void wcfxo_start_dma(struct wcfxo *wc)
 {
 	/* Reset Master and TDM */
-	outb(0x0f, wc->ioaddr + WC_CNTL);
+	wcfxo_outb(wc, WC_CNTL, 0x0f);
 	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(1);
-	outb(0x01, wc->ioaddr + WC_CNTL);
-	outb(0x01, wc->ioaddr + WC_OPER);
+	wcfxo_outb(wc, WC_CNTL, 0x01);
+	wcfxo_outb(wc, WC_OPER, 0x01);
 }
 
 static void wcfxo_restart_dma(struct wcfxo *wc)
 {
 	/* Reset Master and TDM */
-	outb(0x01, wc->ioaddr + WC_CNTL);
-	outb(0x01, wc->ioaddr + WC_OPER);
+	wcfxo_outb(wc, WC_CNTL, 0x01);
+	wcfxo_outb(wc, WC_OPER, 0x01);
 }
 
 
 static void wcfxo_stop_dma(struct wcfxo *wc)
 {
-	outb(0x00, wc->ioaddr + WC_OPER);
+	wcfxo_outb(wc, WC_OPER, 0x00);
 }
 
 static void wcfxo_reset_tdm(struct wcfxo *wc)
 {
 	/* Reset TDM */
-	outb(0x0f, wc->ioaddr + WC_CNTL);
+	wcfxo_outb(wc, WC_CNTL, 0x0f);
 }
 
 static void wcfxo_disable_interrupts(struct wcfxo *wc)	
 {
-	outb(0x00, wc->ioaddr + WC_MASK0);
-	outb(0x00, wc->ioaddr + WC_MASK1);
+	wcfxo_outb(wc, WC_MASK0, 0x00);
+	wcfxo_outb(wc, WC_MASK1, 0x00);
 }
 
 static void wcfxo_set_daa_mode(struct wcfxo *wc)
@@ -886,6 +986,7 @@
 	return 0;
 }
 
+#if !defined(__FreeBSD__)
 static int __devinit wcfxo_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct wcfxo *wc;
@@ -974,7 +1075,7 @@
 		free_irq(pdev->irq, wc);
 
 		/* Reset PCI chip and registers */
-		outb(0x0e, wc->ioaddr + WC_CNTL);
+		wcfxo_outb(wc, WC_CNTL, 0x0e);
 
 		if (wc->freeregion)
 			release_region(wc->ioaddr, 0xff);
@@ -1013,7 +1114,7 @@
 		free_irq(pdev->irq, wc);
 
 		/* Reset PCI chip and registers */
-		outb(0x0e, wc->ioaddr + WC_CNTL);
+		wcfxo_outb(wc, WC_CNTL, 0x0e);
 
 		/* Release span, possibly delayed */
 		if (!wc->usecount)
@@ -1022,6 +1123,7 @@
 			wc->dead = 1;
 	}
 }
+#endif /* !__FreeBSD__ */
 
 static struct pci_device_id wcfxo_pci_tbl[] = {
 	{ 0xe159, 0x0001, 0x8084, PCI_ANY_ID, 0, 0, (unsigned long) &generic },
@@ -1032,6 +1134,293 @@
 	{ 0 }
 };
 
+#if defined(__FreeBSD__)
+SYSCTL_NODE(_dahdi, OID_AUTO, wcfxo, CTLFLAG_RW, 0, "DAHDI wcfxo");
+#define MODULE_PARAM_PREFIX "dahdi.wcfxo"
+#define MODULE_PARAM_PARENT _dahdi_wcfxo
+
+static void wcfxo_dma_free(bus_dma_tag_t *ptag, bus_dmamap_t *pmap, void **pvaddr, uint32_t *ppaddr);
+
+static void
+wcfxo_release_resources(struct wcfxo *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 */
+	wcfxo_dma_free(&wc->write_dma_tag, &wc->write_dma_map, __DECONST(void **, &wc->writechunk), &wc->writedma);
+	wcfxo_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
+wcfxo_setup_intr(struct wcfxo *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,
+	    wcfxo_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
+wcfxo_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	uint32_t *paddr = arg;
+	*paddr = segs->ds_addr;
+}
+
+static int
+wcfxo_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, wcfxo_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
+wcfxo_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
+wcfxo_device_probe(device_t dev)
+{
+	struct pci_device_id *id;
+	struct wcfxo_desc *d;
+
+	id = dahdi_pci_device_id_lookup(dev, wcfxo_pci_tbl);
+	if (id == NULL)
+		return ENXIO;
+
+	/* found device */
+	device_printf(dev, "vendor=%x device=%x subvendor=%x\n",
+	    id->vendor, id->device, id->subvendor);
+	d = (struct wcfxo_desc *) id->driver_data;
+	device_set_desc(dev, d->name);
+	return (0);
+}
+
+static int
+wcfxo_device_attach(device_t dev)
+{
+	int res;
+	struct pci_device_id *id;
+	struct wcfxo_desc *d;
+	struct wcfxo *wc;
+
+	id = dahdi_pci_device_id_lookup(dev, wcfxo_pci_tbl);
+	if (id == NULL)
+		return ENXIO;
+
+	d = (struct wcfxo_desc *) id->driver_data;
+	wc = device_get_softc(dev);
+	wc->dev = &wc->_dev;
+	wc->dev->dev = dev;
+	wc->chan = &wc->_chan;
+	wc->pos = device_get_unit(dev);
+	wc->variety = d->name;
+	wc->flags = 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 = wcfxo_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 = wcfxo_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 = wcfxo_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 (wcfxo_initialize(wc) < 0) {
+		res = ENXIO;
+		goto err;
+	}
+
+	wcfxo_hardware_init(wc);
+
+	/* enable interrupts */
+	wcfxo_enable_interrupts(wc);
+
+	/* start DMA */
+	wcfxo_start_dma(wc);
+
+	/* initialize DAA (after it's started) */
+	if (wcfxo_init_daa(wc)) {
+		printk(KERN_NOTICE "Failed to initailize DAA, giving up...\n");
+		res = ENXIO;
+		goto err;
+	}
+	wcfxo_set_daa_mode(wc);
+	printk(KERN_INFO "Found a Wildcard FXO: %s\n", wc->variety);
+	return 0;
+
+err:
+	if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->span.flags))
+		dahdi_unregister(&wc->span);
+
+	wcfxo_stop_dma(wc);
+	wcfxo_disable_interrupts(wc);
+
+	/* reset PCI chip and registers */
+	wcfxo_outb(wc, WC_CNTL, 0x0e);
+
+	/* release resources */
+	wcfxo_release_resources(wc);
+	return res;
+}
+
+static int
+wcfxo_device_detach(device_t dev)
+{
+	struct wcfxo *wc = device_get_softc(dev);
+
+	/* Stop any DMA */
+	wcfxo_stop_dma(wc);
+	wcfxo_reset_tdm(wc);
+
+	/* In case hardware is still there */
+	wcfxo_disable_interrupts(wc);
+
+	/* Reset PCI chip and registers */
+	wcfxo_outb(wc, WC_CNTL, 0x0e);
+
+	/* Unregister */
+	dahdi_unregister(&wc->span);
+
+	/* Release resources */
+	wcfxo_release_resources(wc);
+
+	return (0);
+}
+
+static int
+wcfxo_device_shutdown(device_t dev)
+{
+	DPRINTF(dev, "%s shutdown\n", device_get_name(dev));
+	return (0);
+}
+
+static int
+wcfxo_device_suspend(device_t dev)
+{
+	DPRINTF(dev, "%s suspend\n", device_get_name(dev));
+	return (0);
+}
+
+static int
+wcfxo_device_resume(device_t dev)
+{
+	DPRINTF(dev, "%s resume\n", device_get_name(dev));
+	return (0);
+}
+
+static device_method_t wcfxo_methods[] = {
+	DEVMETHOD(device_probe,     wcfxo_device_probe),
+	DEVMETHOD(device_attach,    wcfxo_device_attach),
+	DEVMETHOD(device_detach,    wcfxo_device_detach),
+	DEVMETHOD(device_shutdown,  wcfxo_device_shutdown),
+	DEVMETHOD(device_suspend,   wcfxo_device_suspend),
+	DEVMETHOD(device_resume,    wcfxo_device_resume),
+	{ 0, 0 }
+};
+
+static driver_t wcfxo_pci_driver = {
+	"wcfxo",
+	wcfxo_methods,
+	sizeof(struct wcfxo)
+};
+
+static devclass_t wcfxo_devclass;
+
+DRIVER_MODULE(wcfxo, pci, wcfxo_pci_driver, wcfxo_devclass, 0, 0);
+MODULE_DEPEND(wcfxo, pci, 1, 1, 1);
+MODULE_DEPEND(wcfxo, dahdi, 1, 1, 1);
+#else /* !__FreeBSD__ */
 MODULE_DEVICE_TABLE (pci, wcfxo_pci_tbl);
 
 static struct pci_driver wcfxo_driver = {
@@ -1061,6 +1450,7 @@
 {
 	pci_unregister_driver(&wcfxo_driver);
 }
+#endif /* !__FreeBSD__ */
 
 module_param(debug, int, 0644);
 module_param(quiet, int, 0444);
@@ -1068,9 +1458,11 @@
 module_param(monitor, int, 0444);
 module_param(opermode, int, 0444);
 
+#if !defined(__FreeBSD__)
 MODULE_DESCRIPTION("Wildcard X100P Driver");
 MODULE_AUTHOR("Mark Spencer <markster at digium.com>");
 MODULE_LICENSE("GPL v2");
 
 module_init(wcfxo_init);
 module_exit(wcfxo_cleanup);
+#endif /* !__FreeBSD__ */




More information about the svn-commits mailing list