Commit 84cadf5c authored by Kai Germaschewski's avatar Kai Germaschewski

ISDN/HiSax: Clean up the gazel subdriver

Instead of having "switch (subtype)" in just about every function,
rather use separate functions and invoke the right one using
the now existing struct card_ops infrastructure.
parent 8686ec19
...@@ -70,115 +70,103 @@ write_fifo(unsigned int adr, u8 * data, int size) ...@@ -70,115 +70,103 @@ write_fifo(unsigned int adr, u8 * data, int size)
} }
static u8 static u8
isac_read(struct IsdnCardState *cs, u8 offset) r685_isac_read(struct IsdnCardState *cs, u8 off)
{ {
u_short off2 = offset; return readreg(cs->hw.gazel.isac, off);
}
switch (cs->subtyp) { static u8
case R647: r647_isac_read(struct IsdnCardState *cs, u8 off)
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); {
case R685: return readreg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf));
return (readreg(cs->hw.gazel.isac, off2));
}
return 0;
} }
static void static void
isac_write(struct IsdnCardState *cs, u8 offset, u8 value) r685_isac_write(struct IsdnCardState *cs, u8 off, u8 value)
{ {
u_short off2 = offset; writereg(cs->hw.gazel.isac, off, value);
}
switch (cs->subtyp) { static void
case R647: r647_isac_write(struct IsdnCardState *cs, u8 off, u8 value)
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); {
case R685: writereg(cs->hw.gazel.isac, (off << 8 & 0xf000) | (off & 0xf), value);
writereg(cs->hw.gazel.isac, off2, value);
break;
}
} }
static void static void
isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size) isac_read_fifo(struct IsdnCardState *cs, u8 * data, int size)
{ {
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.isacfifo, data, size); read_fifo(cs->hw.gazel.isacfifo, data, size);
break;
}
} }
static void static void
isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size) isac_write_fifo(struct IsdnCardState *cs, u8 * data, int size)
{ {
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.isacfifo, data, size); write_fifo(cs->hw.gazel.isacfifo, data, size);
break;
}
} }
static struct dc_hw_ops isac_ops = { static struct dc_hw_ops r685_isac_ops = {
.read_reg = isac_read, .read_reg = r685_isac_read,
.write_reg = isac_write, .write_reg = r685_isac_write,
.read_fifo = isac_read_fifo,
.write_fifo = isac_write_fifo,
};
static struct dc_hw_ops r647_isac_ops = {
.read_reg = r647_isac_read,
.write_reg = r647_isac_write,
.read_fifo = isac_read_fifo, .read_fifo = isac_read_fifo,
.write_fifo = isac_write_fifo, .write_fifo = isac_write_fifo,
}; };
static u8 static u8
hscx_read(struct IsdnCardState *cs, int hscx, u8 offset) r685_hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
{ {
u_short off2 = offset; return readreg(cs->hw.gazel.hscx[hscx], off);
}
switch (cs->subtyp) { static u8
case R647: r647_hscx_read(struct IsdnCardState *cs, int hscx, u8 off)
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); {
case R685: return readreg(cs->hw.gazel.hscx[hscx],
return readreg(cs->hw.gazel.hscx[hscx], off2); (off << 8 & 0xf000) | (off & 0xf));
}
return 0;
} }
static void static void
hscx_write(struct IsdnCardState *cs, int hscx, u8 offset, u8 value) r685_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value)
{ {
u_short off2 = offset; writereg(cs->hw.gazel.hscx[hscx], off, value);
}
switch (cs->subtyp) { static void
case R647: r647_hscx_write(struct IsdnCardState *cs, int hscx, u8 off, u8 value)
off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); {
case R685: writereg(cs->hw.gazel.hscx[hscx],
writereg(cs->hw.gazel.hscx[hscx], off2, value); (off << 8 & 0xf000) | (off & 0xf), value);
break;
}
} }
static void static void
hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) hscx_read_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
{ {
switch (cs->subtyp) {
case R647:
case R685:
read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
}
} }
static void static void
hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size) hscx_write_fifo(struct IsdnCardState *cs, int hscx, u8 * data, int size)
{ {
switch (cs->subtyp) {
case R647:
case R685:
write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size);
break;
}
} }
static struct bc_hw_ops hscx_ops = { static struct bc_hw_ops r685_hscx_ops = {
.read_reg = hscx_read, .read_reg = r685_hscx_read,
.write_reg = hscx_write, .write_reg = r685_hscx_write,
.read_fifo = hscx_read_fifo,
.write_fifo = hscx_write_fifo,
};
static struct bc_hw_ops r647_hscx_ops = {
.read_reg = r647_hscx_read,
.write_reg = r647_hscx_write,
.read_fifo = hscx_read_fifo, .read_fifo = hscx_read_fifo,
.write_fifo = hscx_write_fifo, .write_fifo = hscx_write_fifo,
}; };
...@@ -227,51 +215,21 @@ ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size) ...@@ -227,51 +215,21 @@ ipac_writefifo(struct IsdnCardState *cs, u8 off, u8 * data, int size)
BUILD_IPAC_OPS(ipac); BUILD_IPAC_OPS(ipac);
static void static int
gazel_release(struct IsdnCardState *cs) r647_reset(struct IsdnCardState *cs)
{
unsigned int i;
switch (cs->subtyp) {
case R647:
for (i = 0x0000; i < 0xC000; i += 0x1000)
release_region(i + cs->hw.gazel.hscx[0], 16);
release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
break;
case R685:
release_region(cs->hw.gazel.hscx[0], 0x100);
release_region(cs->hw.gazel.cfg_reg, 0x80);
break;
}
}
static void
gazel_ipac_release(struct IsdnCardState *cs)
{ {
switch (cs->subtyp) { writereg(cs->hw.gazel.cfg_reg, 0, 0);
case R753: HZDELAY(10);
release_region(cs->hw.gazel.ipac, 0x8); writereg(cs->hw.gazel.cfg_reg, 0, 1);
release_region(cs->hw.gazel.cfg_reg, 0x80); HZDELAY(2);
break; return 0;
case R742:
release_region(cs->hw.gazel.ipac, 8);
break;
}
} }
static int static int
gazel_reset(struct IsdnCardState *cs) r685_reset(struct IsdnCardState *cs)
{ {
unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
switch (cs->subtyp) {
case R647:
writereg(addr, 0, 0);
HZDELAY(10);
writereg(addr, 0, 1);
HZDELAY(2);
break;
case R685:
plxcntrl = inl(addr + PLX_CNTRL); plxcntrl = inl(addr + PLX_CNTRL);
plxcntrl |= (RESET_9050 + RESET_GAZEL); plxcntrl |= (RESET_9050 + RESET_GAZEL);
outl(plxcntrl, addr + PLX_CNTRL); outl(plxcntrl, addr + PLX_CNTRL);
...@@ -280,18 +238,14 @@ gazel_reset(struct IsdnCardState *cs) ...@@ -280,18 +238,14 @@ gazel_reset(struct IsdnCardState *cs)
outl(plxcntrl, addr + PLX_CNTRL); outl(plxcntrl, addr + PLX_CNTRL);
HZDELAY(10); HZDELAY(10);
outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR);
break;
}
return 0; return 0;
} }
static int static int
gazel_ipac_reset(struct IsdnCardState *cs) r753_reset(struct IsdnCardState *cs)
{ {
unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
switch (cs->subtyp) {
case R753:
if (test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags)) if (test_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags))
/* we can't read, assume the default */ /* we can't read, assume the default */
plxcntrl = 0x18784db6; plxcntrl = 0x18784db6;
...@@ -311,8 +265,12 @@ gazel_ipac_reset(struct IsdnCardState *cs) ...@@ -311,8 +265,12 @@ gazel_ipac_reset(struct IsdnCardState *cs)
ipac_write(cs, IPAC_CONF, 0x1); ipac_write(cs, IPAC_CONF, 0x1);
outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR);
ipac_write(cs, IPAC_MASK, 0xc0); ipac_write(cs, IPAC_MASK, 0xc0);
break; return 0;
case R742: }
static int
r742_reset(struct IsdnCardState *cs)
{
ipac_write(cs, IPAC_POTA2, 0x20); ipac_write(cs, IPAC_POTA2, 0x20);
HZDELAY(4); HZDELAY(4);
ipac_write(cs, IPAC_POTA2, 0x00); ipac_write(cs, IPAC_POTA2, 0x00);
...@@ -321,8 +279,6 @@ gazel_ipac_reset(struct IsdnCardState *cs) ...@@ -321,8 +279,6 @@ gazel_ipac_reset(struct IsdnCardState *cs)
ipac_write(cs, IPAC_MASK, 0xff); ipac_write(cs, IPAC_MASK, 0xff);
ipac_write(cs, IPAC_CONF, 0x1); ipac_write(cs, IPAC_CONF, 0x1);
ipac_write(cs, IPAC_MASK, 0xc0); ipac_write(cs, IPAC_MASK, 0xc0);
break;
}
return 0; return 0;
} }
...@@ -341,81 +297,133 @@ gazel_init(struct IsdnCardState *cs) ...@@ -341,81 +297,133 @@ gazel_init(struct IsdnCardState *cs)
cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; cs->bcs[i].hw.hscx.tsaxr0 = 0x1f;
cs->bcs[i].hw.hscx.tsaxr1 = 0x23; cs->bcs[i].hw.hscx.tsaxr1 = 0x23;
} }
inithscxisac(cs);
} }
static struct card_ops gazel_ops = { static struct resource *
.init = gazel_init, gazel_request_region(unsigned long start, unsigned long n, const char *name)
.reset = gazel_reset, {
.release = gazel_release, struct resource *rc = request_region(start, n, name);
.irq_func = hscxisac_irq,
};
static struct card_ops gazel_ipac_ops = { if (!rc)
.init = ipac_init, printk(KERN_WARNING "Gazel: io %#lx-%#lx already in use\n",
.reset = gazel_ipac_reset, start, start + n);
.release = gazel_ipac_release, return rc;
.irq_func = ipac_irq, }
};
static int static int
reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) r647_reserve_regions(struct IsdnCardState *cs)
{ {
unsigned int i, base = 0, adr = 0, len = 0; int i, base;
switch (cs->subtyp) {
case R647:
base = cs->hw.gazel.hscx[0]; base = cs->hw.gazel.hscx[0];
for (i = 0x0000; i < 0xC000; i += 0x1000) { for (i = 0x0000; i < 0xC000; i += 0x1000) {
if (!request_region(adr = (i + base), len = 16, "gazel")) { if (!gazel_request_region(i + base, 16, "gazel")) {
int j; for (i -= 0x1000; i >= 0; i -= 0x1000)
release_region (i + base, 16);
for (j = 0x0000; j < i; j += 0x1000) return -EBUSY;
release_region ((j + base), len);
goto error;
} }
} }
if (!request_region(adr = (0xC000 + base), len = 1, "gazel")) { if (!gazel_request_region(0xC000 + base, 1, "gazel")) {
for (i = 0x0000; i < 0xC000; i += 0x1000) for (i = 0x0000; i < 0xC000; i += 0x1000)
release_region ((i + base), 16); release_region (i + base, 16);
goto error; return -EBUSY;
} }
return 0;
}
break; static void
r647_release(struct IsdnCardState *cs)
{
int i;
case R685: for (i = 0x0000; i < 0xC000; i += 0x1000)
if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel")) release_region(i + cs->hw.gazel.hscx[0], 16);
goto error; release_region(0xC000 + cs->hw.gazel.hscx[0], 1);
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { }
static int
r685_reserve_regions(struct IsdnCardState *cs)
{
if (!gazel_request_region(cs->hw.gazel.hscx[0], 0x100, "gazel")) {
return -EBUSY;
}
if (!gazel_request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel")) {
release_region (cs->hw.gazel.hscx[0], 0x100); release_region (cs->hw.gazel.hscx[0], 0x100);
goto error; return -EBUSY;
} }
return 0;
}
break; static void
r685_release(struct IsdnCardState *cs)
{
release_region(cs->hw.gazel.hscx[0], 0x100);
release_region(cs->hw.gazel.cfg_reg, 0x80);
}
case R753: static int
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) r742_reserve_regions(struct IsdnCardState *cs)
goto error; {
if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { if (!gazel_request_region(cs->hw.gazel.ipac, 0x8, "gazel"))
release_region (cs->hw.gazel.ipac, 0x8); return -EBUSY;
goto error; return 0;
} }
break; static void
r742_release(struct IsdnCardState *cs)
{
release_region(cs->hw.gazel.ipac, 8);
}
case R742: static int
if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) r753_reserve_regions(struct IsdnCardState *cs)
goto error; {
break; if (!gazel_request_region(cs->hw.gazel.ipac, 0x8, "gazel")) {
return -EBUSY;
}
if (!gazel_request_region(cs->hw.gazel.cfg_reg, 0x80, "gazel")) {
release_region (cs->hw.gazel.ipac, 0x8);
return -EBUSY;
} }
return 0; return 0;
}
error: static void
printk(KERN_WARNING "Gazel: %s io ports 0x%x-0x%x already in use\n", r753_release(struct IsdnCardState *cs)
CardType[cs->typ], adr, adr + len); {
return 1; release_region(cs->hw.gazel.ipac, 0x8);
release_region(cs->hw.gazel.cfg_reg, 0x80);
} }
static struct card_ops r647_ops = {
.init = gazel_init,
.reset = r647_reset,
.release = r647_release,
.irq_func = hscxisac_irq,
};
static struct card_ops r685_ops = {
.init = gazel_init,
.reset = r685_reset,
.release = r685_release,
.irq_func = hscxisac_irq,
};
static struct card_ops r742_ops = {
.init = ipac_init,
.reset = r742_reset,
.release = r742_release,
.irq_func = ipac_irq,
};
static struct card_ops r753_ops = {
.init = ipac_init,
.reset = r753_reset,
.release = r753_release,
.irq_func = ipac_irq,
};
static int __init static int __init
setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
{ {
...@@ -450,16 +458,15 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) ...@@ -450,16 +458,15 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
"Gazel: hscx A:0x%X hscx B:0x%X\n", "Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break; return r647_reserve_regions(cs);
case R742: case R742:
printk(KERN_INFO "Gazel: Card ISA R742 found\n"); printk(KERN_INFO "Gazel: Card ISA R742 found\n");
printk(KERN_INFO printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X\n", "Gazel: config irq:%d ipac:0x%X\n",
cs->irq, cs->hw.gazel.ipac); cs->irq, cs->hw.gazel.ipac);
break; return r742_reserve_regions(cs);
} }
return 0;
return (0);
} }
static struct pci_dev *dev_tel __initdata = NULL; static struct pci_dev *dev_tel __initdata = NULL;
...@@ -504,11 +511,11 @@ setup_gazelpci(struct IsdnCardState *cs) ...@@ -504,11 +511,11 @@ setup_gazelpci(struct IsdnCardState *cs)
} }
if (!found) { if (!found) {
printk(KERN_WARNING "Gazel: No PCI card found\n"); printk(KERN_WARNING "Gazel: No PCI card found\n");
return (1); return -ENODEV;
} }
if (!pci_irq) { if (!pci_irq) {
printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n"); printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n");
return 1; return -ENODEV;
} }
cs->hw.gazel.pciaddr[0] = pci_ioaddr0; cs->hw.gazel.pciaddr[0] = pci_ioaddr0;
cs->hw.gazel.pciaddr[1] = pci_ioaddr1; cs->hw.gazel.pciaddr[1] = pci_ioaddr1;
...@@ -536,7 +543,7 @@ setup_gazelpci(struct IsdnCardState *cs) ...@@ -536,7 +543,7 @@ setup_gazelpci(struct IsdnCardState *cs)
printk(KERN_INFO printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n", "Gazel: hscx A:0x%X hscx B:0x%X\n",
cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
break; return r685_reserve_regions(cs);
case PCI_DEVICE_ID_PLX_R753: case PCI_DEVICE_ID_PLX_R753:
case PCI_DEVICE_ID_PLX_DJINN_ITOO: case PCI_DEVICE_ID_PLX_DJINN_ITOO:
printk(KERN_INFO "Gazel: Card PCI R753 found\n"); printk(KERN_INFO "Gazel: Card PCI R753 found\n");
...@@ -556,10 +563,9 @@ setup_gazelpci(struct IsdnCardState *cs) ...@@ -556,10 +563,9 @@ setup_gazelpci(struct IsdnCardState *cs)
set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags); set_bit(FLG_BUGGY_PLX9050, &cs->HW_Flags);
} }
} }
break; return r753_reserve_regions(cs);
} }
return 0;
return (0);
} }
int __init int __init
...@@ -579,42 +585,43 @@ setup_gazel(struct IsdnCard *card) ...@@ -579,42 +585,43 @@ setup_gazel(struct IsdnCard *card)
if (setup_gazelisa(card, cs)) if (setup_gazelisa(card, cs))
return (0); return (0);
} else { } else {
#if CONFIG_PCI
if (setup_gazelpci(cs)) if (setup_gazelpci(cs))
return (0); return (0);
#else
printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n");
return (0);
#endif /* CONFIG_PCI */
} }
if (reserve_regions(card, cs)) {
return (0);
}
cs->cardmsg = &Gazel_card_msg; cs->cardmsg = &Gazel_card_msg;
switch (cs->subtyp) { switch (cs->subtyp) {
case R647: case R647:
case R685: case R685:
cs->dc_hw_ops = &isac_ops; if (cs->subtyp == R647) {
cs->bc_hw_ops = &hscx_ops; cs->dc_hw_ops = &r647_isac_ops;
gazel_reset(cs); cs->bc_hw_ops = &r647_hscx_ops;
cs->card_ops = &gazel_ops; cs->card_ops = &r647_ops;
} else {
cs->dc_hw_ops = &r685_isac_ops;
cs->bc_hw_ops = &r685_hscx_ops;
cs->card_ops = &r685_ops;
}
cs->card_ops->reset(cs);
ISACVersion(cs, "Gazel:"); ISACVersion(cs, "Gazel:");
if (HscxVersion(cs, "Gazel:")) { if (HscxVersion(cs, "Gazel:")) {
printk(KERN_WARNING printk(KERN_WARNING
"Gazel: wrong HSCX versions check IO address\n"); "Gazel: wrong HSCX versions check IO address\n");
gazel_release(cs); cs->card_ops->release(cs);
return (0); return (0);
} }
break; break;
case R742: case R742:
case R753: case R753:
if (cs->subtyp == R742) {
cs->card_ops = &r742_ops;
} else {
cs->card_ops = &r753_ops;
}
cs->dc_hw_ops = &ipac_dc_ops; cs->dc_hw_ops = &ipac_dc_ops;
cs->bc_hw_ops = &ipac_bc_ops; cs->bc_hw_ops = &ipac_bc_ops;
gazel_ipac_reset(cs); cs->card_ops->reset(cs);
cs->card_ops = &gazel_ipac_ops;
val = ipac_read(cs, IPAC_ID); val = ipac_read(cs, IPAC_ID);
printk(KERN_INFO "Gazel: IPAC version %x\n", val); printk(KERN_INFO "Gazel: IPAC version %x\n", val);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment