summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dahdi/wct4xxp/base.c517
1 files changed, 358 insertions, 159 deletions
diff --git a/drivers/dahdi/wct4xxp/base.c b/drivers/dahdi/wct4xxp/base.c
index a58fd99..3b69fc6 100644
--- a/drivers/dahdi/wct4xxp/base.c
+++ b/drivers/dahdi/wct4xxp/base.c
@@ -27,7 +27,6 @@
* Free Software Foundation. See the LICENSE file included with
* this program for more details.
*/
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -273,11 +272,13 @@ static struct devtype wct210 = { "Wildcard TE210P ", FLAG_2NDGEN | FLAG_2PORT };
struct t4;
+enum linemode {T1, E1, J1};
+
struct t4_span {
struct t4 *owner;
u32 *writechunk; /* Double-word aligned write memory */
u32 *readchunk; /* Double-word aligned read memory */
- enum {T1, E1, J1} linemode;
+ enum linemode linemode;
int sync;
int alarmtimer;
int notclear;
@@ -323,7 +324,6 @@ struct t4 {
struct pci_dev *dev; /* Pointer to PCI device */
unsigned int intcount;
int num; /* Which card we are */
- int t1e1; /* T1/E1 select pins */
int syncsrc; /* active sync source */
struct dahdi_device *ddev;
struct t4_span *tspans[4]; /* Individual spans */
@@ -335,7 +335,8 @@ struct t4 {
int irq; /* IRQ used by device */
int order; /* Order */
const struct devtype *devtype;
- unsigned int falc31 : 1; /* are we falc v3.1 (atomic not necessary) */
+ unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */
+ unsigned int t1e1:4; /* T1 / E1 select pins */
int ledreg; /* LED Register */
unsigned int gpio;
unsigned int gpioctl;
@@ -1754,6 +1755,323 @@ static void setup_chunks(struct t4 *wc, int which)
}
}
+/**
+ * t4_serial_setup - Setup serial parameters and system interface.
+ * @wc: The card to configure.
+ *
+ */
+static void t4_serial_setup(struct t4 *wc)
+{
+ unsigned long flags;
+ unsigned int unit;
+
+ if (debug) {
+ dev_info(&wc->dev->dev,
+ "TE%dXXP: Setting up global serial parameters\n",
+ wc->numspans);
+ }
+
+ spin_lock_irqsave(&wc->reglock, flags);
+ /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from
+ * channel 0 */
+ /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from
+ * channel 0 */
+ __t4_framer_out(wc, 0, 0x85, 0xe0);
+ /* IPC: Interrupt push/pull active low */
+ __t4_framer_out(wc, 0, 0x08, 0x01);
+
+ /* Global clocks (8.192 Mhz CLK) */
+ __t4_framer_out(wc, 0, 0x92, 0x00);
+ __t4_framer_out(wc, 0, 0x93, 0x18);
+ __t4_framer_out(wc, 0, 0x94, 0xfb);
+ __t4_framer_out(wc, 0, 0x95, 0x0b);
+ __t4_framer_out(wc, 0, 0x96, 0x00);
+ __t4_framer_out(wc, 0, 0x97, 0x0b);
+ __t4_framer_out(wc, 0, 0x98, 0xdb);
+ __t4_framer_out(wc, 0, 0x99, 0xdf);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ for (unit = 0; unit < PORTS_PER_FRAMER; ++unit) {
+ spin_lock_irqsave(&wc->reglock, flags);
+
+ /* Configure interrupts */
+ /* GCR: Interrupt on Activation/Deactivation of each */
+ __t4_framer_out(wc, unit, FRMR_GCR, 0x00);
+
+ /* Configure system interface */
+ /* SIC1: 8.192 Mhz clock/bus, double buffer receive /
+ * transmit, byte interleaved */
+ __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2);
+ /* SIC2: No FFS, no center receive eliastic buffer, phase */
+ __t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1));
+ /* SIC3: Edges for capture */
+ __t4_framer_out(wc, unit, FRMR_SIC3, 0x04);
+ /* CMR2: We provide sync and clock for tx and rx. */
+ __t4_framer_out(wc, unit, FRMR_CMR2, 0x00);
+
+ if (!has_e1_span(wc)) { /* T1/J1 mode */
+ __t4_framer_out(wc, unit, FRMR_XC0, 0x03);
+ __t4_framer_out(wc, unit, FRMR_XC1, 0x84);
+ if (J1 == wc->tspans[unit]->linemode)
+ __t4_framer_out(wc, unit, FRMR_RC0, 0x83);
+ else
+ __t4_framer_out(wc, unit, FRMR_RC0, 0x03);
+ __t4_framer_out(wc, unit, FRMR_RC1, 0x84);
+ } else { /* E1 mode */
+ __t4_framer_out(wc, unit, FRMR_XC0, 0x00);
+ __t4_framer_out(wc, unit, FRMR_XC1, 0x04);
+ __t4_framer_out(wc, unit, FRMR_RC0, 0x04);
+ __t4_framer_out(wc, unit, FRMR_RC1, 0x04);
+ }
+
+ /* Configure ports */
+
+ /* PC1: SPYR/SPYX input on RPA/XPA */
+ __t4_framer_out(wc, unit, 0x80, 0x00);
+
+ /* PC2: RMFB/XSIG output/input on RPB/XPB */
+ /* PC3: Some unused stuff */
+ /* PC4: Some more unused stuff */
+ if (wc->falc31) {
+ __t4_framer_out(wc, unit, 0x81, 0xBB);
+ __t4_framer_out(wc, unit, 0x82, 0xBB);
+ __t4_framer_out(wc, unit, 0x83, 0xBB);
+ } else {
+ __t4_framer_out(wc, unit, 0x81, 0x22);
+ __t4_framer_out(wc, unit, 0x82, 0x65);
+ __t4_framer_out(wc, unit, 0x83, 0x35);
+ }
+
+ /* PC5: XMFS active low, SCLKR is input, RCLK is output */
+ __t4_framer_out(wc, unit, 0x84, 0x01);
+
+ if (debug & DEBUG_MAIN) {
+ dev_notice(&wc->dev->dev,
+ "Successfully initialized serial bus "
+ "for unit %d\n", unit);
+ }
+
+ spin_unlock_irqrestore(&wc->reglock, flags);
+ }
+}
+
+/**
+ * t4_span_assigned - Called when the span is assigned by DAHDI.
+ * @span: Span that has been assigned.
+ *
+ * When this function is called, the span has a valid spanno and all the
+ * channels on the span have valid channel numbers assigned.
+ *
+ * This function is necessary because a device may be registered, and
+ * then user space may then later decide to assign span numbers and the
+ * channel numbers.
+ *
+ */
+static void t4_span_assigned(struct dahdi_span *span)
+{
+ struct t4_span *tspan = container_of(span, struct t4_span, span);
+ struct t4 *wc = tspan->owner;
+ struct dahdi_span *pos;
+ unsigned int unassigned_spans = 0;
+
+ /* We use this to make sure all the spans are assigned before
+ * running the serial setup. */
+ list_for_each_entry(pos, &wc->ddev->spans, device_node) {
+ if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags))
+ ++unassigned_spans;
+ }
+
+ if (0 == unassigned_spans)
+ t4_serial_setup(wc);
+}
+
+static void free_wc(struct t4 *wc)
+{
+ unsigned int x, y;
+
+ for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) {
+ if (!wc->tspans[x])
+ continue;
+ for (y = 0; y < ARRAY_SIZE(wc->tspans[x]->chans); y++) {
+ kfree(wc->tspans[x]->chans[y]);
+ kfree(wc->tspans[x]->ec[y]);
+ }
+ kfree(wc->tspans[x]);
+ }
+
+ kfree(wc->ddev->devicetype);
+ kfree(wc->ddev->location);
+ dahdi_free_device(wc->ddev);
+ kfree(wc);
+}
+
+/**
+ * t4_alloc_channels - Allocate the channels on a span.
+ * @wc: The board we're allocating for.
+ * @ts: The span we're allocating for.
+ * @linemode: Which mode (T1/E1/J1) to use for this span.
+ *
+ * This function must only be called before the span is assigned it's
+ * possible for user processes to have an open reference to the
+ * channels.
+ *
+ */
+static int t4_alloc_channels(struct t4 *wc, struct t4_span *ts,
+ enum linemode linemode)
+{
+ int i;
+
+ if (test_bit(DAHDI_FLAGBIT_REGISTERED, &ts->span.flags)) {
+ dev_dbg(&wc->dev->dev,
+ "Cannot allocate channels on a span that is already "
+ "assigned.\n");
+ return -EINVAL;
+ }
+
+ /* Cleanup any previously allocated channels. */
+ for (i = 0; i < ARRAY_SIZE(ts->chans); ++i) {
+ kfree(ts->chans[i]);
+ kfree(ts->ec[i]);
+ }
+
+ ts->linemode = linemode;
+ for (i = 0; i < ((E1 == ts->linemode) ? 31 : 24); i++) {
+ struct dahdi_chan *chan;
+ struct dahdi_echocan_state *ec;
+
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan) {
+ free_wc(wc);
+ return -ENOMEM;
+ }
+ ts->chans[i] = chan;
+
+ ec = kzalloc(sizeof(*ec), GFP_KERNEL);
+ if (!ec) {
+ free_wc(wc);
+ return -ENOMEM;
+ }
+ ts->ec[i] = ec;
+ }
+
+ return 0;
+}
+
+static void t4_init_one_span(struct t4 *wc, struct t4_span *ts)
+{
+ unsigned long flags;
+ unsigned int reg;
+ int i;
+
+ snprintf(ts->span.name, sizeof(ts->span.name) - 1,
+ "TE%d/%d/%d", wc->numspans, wc->num, ts->span.offset + 1);
+ snprintf(ts->span.desc, sizeof(ts->span.desc) - 1,
+ "T%dXXP (PCI) Card %d Span %d", wc->numspans, wc->num,
+ ts->span.offset + 1);
+
+ switch (ts->linemode) {
+ case T1:
+ ts->span.spantype = "T1";
+ break;
+ case E1:
+ ts->span.spantype = "E1";
+ break;
+ case J1:
+ ts->span.spantype = "J1";
+ break;
+ }
+
+ /* HDLC Specific init */
+ ts->sigchan = NULL;
+ ts->sigmode = sigmode;
+ ts->sigactive = 0;
+
+ if (E1 != ts->linemode) {
+ ts->span.channels = 24;
+ ts->span.deflaw = DAHDI_LAW_MULAW;
+ ts->span.linecompat = DAHDI_CONFIG_AMI |
+ DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_D4 |
+ DAHDI_CONFIG_ESF;
+ } else {
+ ts->span.channels = 31;
+ ts->span.deflaw = DAHDI_LAW_ALAW;
+ ts->span.linecompat = DAHDI_CONFIG_AMI |
+ DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CCS |
+ DAHDI_CONFIG_CRC4;
+ }
+ ts->span.chans = ts->chans;
+ ts->span.flags = DAHDI_FLAG_RBS;
+
+ for (i = 0; i < ts->span.channels; i++) {
+ struct dahdi_chan *const chan = ts->chans[i];
+ chan->pvt = wc;
+ snprintf(chan->name, sizeof(chan->name) - 1,
+ "%s/%d", ts->span.name, i + 1);
+ t4_chan_set_sigcap(&ts->span, i);
+ chan->chanpos = i + 1;
+ }
+
+ /* Enable 1sec timer interrupt */
+ spin_lock_irqsave(&wc->reglock, flags);
+ reg = __t4_framer_in(wc, ts->span.offset, FMR1_T);
+ __t4_framer_out(wc, ts->span.offset, FMR1_T, (reg | FMR1_ECM));
+
+ /* Enable Errored Second interrupt */
+ __t4_framer_out(wc, ts->span.offset, ESM, 0);
+ spin_unlock_irqrestore(&wc->reglock, flags);
+
+ t4_reset_counters(&ts->span);
+}
+
+/**
+ * t4_set_linemode - Allows user space to change the linemode before spans are assigned.
+ * @span: span on which to change the linemode.
+ * @linemode: Textual description of the new linemode.
+ *
+ * This callback is used to override the E1/T1 mode jumper settings and set
+ * the linemode on for each span. Called when the "spantype" attribute
+ * is written in sysfs under the dahdi_device.
+ *
+ */
+static int t4_set_linemode(struct dahdi_span *span, const char *linemode)
+{
+ struct t4_span *ts = container_of(span, struct t4_span, span);
+ struct t4 *wc = ts->owner;
+ int res = 0;
+ enum linemode mode;
+
+ dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name, linemode);
+
+ if (!strcasecmp(span->spantype, linemode))
+ return 0;
+
+ if (!strcasecmp(linemode, "t1")) {
+ dev_info(&wc->dev->dev,
+ "Changing from %s to T1 line mode.\n", span->spantype);
+ mode = T1;
+ } else if (!strcasecmp(linemode, "e1")) {
+ dev_info(&wc->dev->dev,
+ "Changing from %s to E1 line mode.\n", span->spantype);
+ mode = E1;
+ } else if (!strcasecmp(linemode, "j1")) {
+ dev_info(&wc->dev->dev,
+ "Changing from %s to J1 line mode.\n", span->spantype);
+ mode = J1;
+ } else {
+ dev_err(&wc->dev->dev,
+ "'%s' is an unknown linemode.\n", linemode);
+ res = -EINVAL;
+ }
+
+ if (!res) {
+ t4_alloc_channels(wc, ts, mode);
+ t4_init_one_span(wc, ts);
+ dahdi_init_span(span);
+ }
+
+ return res;
+}
+
static const struct dahdi_span_ops t4_gen1_span_ops = {
.owner = THIS_MODULE,
.spanconfig = t4_spanconfig,
@@ -1766,6 +2084,8 @@ static const struct dahdi_span_ops t4_gen1_span_ops = {
.close = t4_close,
.ioctl = t4_ioctl,
.hdlc_hard_xmit = t4_hdlc_hard_xmit,
+ .assigned = t4_span_assigned,
+ .set_spantype = t4_set_linemode,
};
static const struct dahdi_span_ops t4_gen2_span_ops = {
@@ -1781,20 +2101,32 @@ static const struct dahdi_span_ops t4_gen2_span_ops = {
.ioctl = t4_ioctl,
.hdlc_hard_xmit = t4_hdlc_hard_xmit,
.dacs = t4_dacs,
+ .assigned = t4_span_assigned,
+ .set_spantype = t4_set_linemode,
#ifdef VPM_SUPPORT
.echocan_create = t4_echocan_create,
.echocan_name = t4_echocan_name,
#endif
};
+/**
+ * init_spans - Do first initialization on all the spans
+ * @wc: Card to initialize the spans on.
+ *
+ * This function is called *before* the dahdi_device is first registered
+ * with the system. What happens in t4_init_one_span can happen between
+ * when the device is registered and when the spans are assigned via
+ * sysfs (or automatically).
+ *
+ */
static void init_spans(struct t4 *wc)
{
- int x,y;
+ int x, y;
int gen2;
struct t4_span *ts;
unsigned int reg;
unsigned long flags;
-
+
gen2 = (wc->tspans[0]->spanflags & FLAG_2NDGEN);
for (x = 0; x < wc->numspans; x++) {
ts = wc->tspans[x];
@@ -1818,7 +2150,7 @@ static void init_spans(struct t4 *wc)
ts->sigchan = NULL;
ts->sigmode = sigmode;
ts->sigactive = 0;
-
+
if (E1 != ts->linemode) {
ts->span.channels = 24;
ts->span.deflaw = DAHDI_LAW_MULAW;
@@ -1875,104 +2207,6 @@ static void init_spans(struct t4 *wc)
wc->lastindex = 0;
}
-/**
- * t4_serial_setup - Setup serial parameters and system interface.
- * @wc: The card to configure.
- *
- */
-static void t4_serial_setup(struct t4 *wc)
-{
- unsigned long flags;
- unsigned int unit;
-
- if (debug) {
- dev_info(&wc->dev->dev,
- "TE%dXXP: Setting up global serial parameters\n",
- wc->numspans);
- }
-
- spin_lock_irqsave(&wc->reglock, flags);
- /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from
- * channel 0 */
- __t4_framer_out(wc, 0, 0x85, 0xe0); /* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from channel 0 */
- /* IPC: Interrupt push/pull active low */
- __t4_framer_out(wc, 0, 0x08, 0x01);
-
- /* Global clocks (8.192 Mhz CLK) */
- __t4_framer_out(wc, 0, 0x92, 0x00);
- __t4_framer_out(wc, 0, 0x93, 0x18);
- __t4_framer_out(wc, 0, 0x94, 0xfb);
- __t4_framer_out(wc, 0, 0x95, 0x0b);
- __t4_framer_out(wc, 0, 0x96, 0x00);
- __t4_framer_out(wc, 0, 0x97, 0x0b);
- __t4_framer_out(wc, 0, 0x98, 0xdb);
- __t4_framer_out(wc, 0, 0x99, 0xdf);
- spin_unlock_irqrestore(&wc->reglock, flags);
-
- for (unit = 0; unit < PORTS_PER_FRAMER; ++unit) {
- spin_lock_irqsave(&wc->reglock, flags);
-
- /* Configure interrupts */
- /* GCR: Interrupt on Activation/Deactivation of each */
- __t4_framer_out(wc, unit, FRMR_GCR, 0x00);
-
- /* Configure system interface */
- /* SIC1: 8.192 Mhz clock/bus, double buffer receive /
- * transmit, byte interleaved */
- __t4_framer_out(wc, unit, FRMR_SIC1, 0xc2);
- /* SIC2: No FFS, no center receive eliastic buffer, phase */
- __t4_framer_out(wc, unit, FRMR_SIC2, 0x20 | (unit << 1));
- /* SIC3: Edges for capture */
- __t4_framer_out(wc, unit, FRMR_SIC3, 0x04);
- /* CMR2: We provide sync and clock for tx and rx. */
- __t4_framer_out(wc, unit, FRMR_CMR2, 0x00);
-
- if (!has_e1_span(wc)) { /* T1/J1 mode */
- __t4_framer_out(wc, unit, FRMR_XC0, 0x03);
- __t4_framer_out(wc, unit, FRMR_XC1, 0x84);
- if (J1 == wc->tspans[unit]->linemode)
- __t4_framer_out(wc, unit, FRMR_RC0, 0x83);
- else
- __t4_framer_out(wc, unit, FRMR_RC0, 0x03);
- __t4_framer_out(wc, unit, FRMR_RC1, 0x84);
- } else { /* E1 mode */
- __t4_framer_out(wc, unit, FRMR_XC0, 0x00);
- __t4_framer_out(wc, unit, FRMR_XC1, 0x04);
- __t4_framer_out(wc, unit, FRMR_RC0, 0x04);
- __t4_framer_out(wc, unit, FRMR_RC1, 0x04);
- }
-
- /* Configure ports */
-
- /* PC1: SPYR/SPYX input on RPA/XPA */
- __t4_framer_out(wc, unit, 0x80, 0x00);
-
- /* PC2: RMFB/XSIG output/input on RPB/XPB */
- /* PC3: Some unused stuff */
- /* PC4: Some more unused stuff */
- if (wc->falc31) {
- __t4_framer_out(wc, unit, 0x81, 0xBB);
- __t4_framer_out(wc, unit, 0x82, 0xBB);
- __t4_framer_out(wc, unit, 0x83, 0xBB);
- } else {
- __t4_framer_out(wc, unit, 0x81, 0x22);
- __t4_framer_out(wc, unit, 0x82, 0x65);
- __t4_framer_out(wc, unit, 0x83, 0x35);
- }
-
- /* PC5: XMFS active low, SCLKR is input, RCLK is output */
- __t4_framer_out(wc, unit, 0x84, 0x01);
-
- if (debug & DEBUG_MAIN) {
- dev_notice(&wc->dev->dev,
- "Successfully initialized serial bus "
- "for unit %d\n", unit);
- }
-
- spin_unlock_irqrestore(&wc->reglock, flags);
- }
-}
-
static int syncsrc = 0;
static int syncnum = 0 /* -1 */;
static int syncspan = 0;
@@ -4042,8 +4276,6 @@ static int __devinit t4_launch(struct t4 *wc)
wc->order);
}
- t4_serial_setup(wc);
-
wc->ddev->manufacturer = "Digium";
if (!ignore_rotary && (1 == order_index[wc->order])) {
wc->ddev->location = kasprintf(GFP_KERNEL,
@@ -4079,26 +4311,6 @@ static int __devinit t4_launch(struct t4 *wc)
return 0;
}
-static void free_wc(struct t4 *wc)
-{
- unsigned int x, y;
-
- for (x = 0; x < ARRAY_SIZE(wc->tspans); x++) {
- if (!wc->tspans[x])
- continue;
- for (y = 0; y < ARRAY_SIZE(wc->tspans[x]->chans); y++) {
- kfree(wc->tspans[x]->chans[y]);
- kfree(wc->tspans[x]->ec[y]);
- }
- kfree(wc->tspans[x]);
- }
-
- kfree(wc->ddev->devicetype);
- kfree(wc->ddev->location);
- dahdi_free_device(wc->ddev);
- kfree(wc);
-}
-
/**
* wct4xxp_sort_cards - Sort the cards in card array by rotary switch settings.
*
@@ -4130,7 +4342,7 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i
{
int res;
struct t4 *wc;
- unsigned int x, f;
+ unsigned int x;
int init_latency;
if (pci_enable_device(pdev)) {
@@ -4229,6 +4441,7 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i
/* Allocate pieces we need here */
for (x = 0; x < PORTS_PER_FRAMER; x++) {
struct t4_span *ts;
+ enum linemode linemode;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (!ts) {
@@ -4237,34 +4450,12 @@ static int __devinit t4_init_one(struct pci_dev *pdev, const struct pci_device_i
}
wc->tspans[x] = ts;
- if (wc->t1e1 & (1 << x))
- ts->linemode = E1;
- else
- ts->linemode = (j1mode) ? J1 : T1;
-
- for (f = 0; f < ((E1 == ts->linemode) ? 31 : 24); f++) {
- struct dahdi_chan *chan;
- struct dahdi_echocan_state *ec;
-
- chan = kzalloc(sizeof(*chan), GFP_KERNEL);
- if (!chan) {
- free_wc(wc);
- return -ENOMEM;
- }
- ts->chans[f] = chan;
-
- ec = kzalloc(sizeof(*ec), GFP_KERNEL);
- if (!ec) {
- free_wc(wc);
- return -ENOMEM;
- }
- ts->ec[f] = ec;
- }
-
#ifdef ENABLE_WORKQUEUES
INIT_WORK(&ts->swork, workq_handlespan, ts);
#endif
ts->spanflags |= wc->devtype->flags;
+ linemode = (wc->t1e1 & (1 << x)) ? E1 : ((j1mode) ? J1 : T1);
+ t4_alloc_channels(wc, wc->tspans[x], linemode);
}
/* Continue hardware intiialization */
@@ -4466,19 +4657,28 @@ static int __init t4_init(void)
{
int i;
int res;
+
+ if (-1 != t1e1override) {
+ pr_info("'t1e1override' module parameter is deprecated. "
+ "Please use 'default_linemode' instead.\n");
+ }
+
res = dahdi_pci_module(&t4_driver);
if (res)
return -ENODEV;
- /* initialize cards since we have all of them */
- /* warn for missing zero and duplicate numbers */
- if (cards[0] && cards[0]->order != 0) {
- printk(KERN_NOTICE "wct4xxp: Ident of first card is not zero (%d)\n",
- cards[0]->order);
- }
/* If we're ignoring the rotary switch settings, then we've already
* registered in the context of .probe */
if (!ignore_rotary) {
+
+ /* Initialize cards since we have all of them. Warn for
+ * missing zero and duplicate numbers. */
+
+ if (cards[0] && cards[0]->order != 0) {
+ printk(KERN_NOTICE "wct4xxp: Ident of first card is not zero (%d)\n",
+ cards[0]->order);
+ }
+
for (i = 0; cards[i]; i++) {
/* warn the user of duplicate ident values it is
* probably unintended */
@@ -4504,7 +4704,6 @@ static void __exit t4_cleanup(void)
pci_unregister_driver(&t4_driver);
}
-
MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
MODULE_DESCRIPTION("Wildcard Dual-/Quad-port Digital Card Driver");
MODULE_ALIAS("wct2xxp");