1/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $ 2 * 3 * low level stuff for Siemens I-Surf/I-Talk cards 4 * 5 * Author Karsten Keil 6 * Copyright by Karsten Keil <keil@isdn4linux.de> 7 * 8 * This software may be used and distributed according to the terms 9 * of the GNU General Public License, incorporated herein by reference. 10 * 11 */ 12 13#include <linux/init.h> 14#include "hisax.h" 15#include "isac.h" 16#include "isar.h" 17#include "isdnl1.h" 18#include <linux/isapnp.h> 19 20static const char *ISurf_revision = "$Revision: 1.12.2.4 $"; 21 22#define byteout(addr, val) outb(val, addr) 23#define bytein(addr) inb(addr) 24 25#define ISURF_ISAR_RESET 1 26#define ISURF_ISAC_RESET 2 27#define ISURF_ISAR_EA 4 28#define ISURF_ARCOFI_RESET 8 29#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET) 30 31#define ISURF_ISAR_OFFSET 0 32#define ISURF_ISAC_OFFSET 0x100 33#define ISURF_IOMEM_SIZE 0x400 34/* Interface functions */ 35 36static u_char 37ReadISAC(struct IsdnCardState *cs, u_char offset) 38{ 39 return (readb(cs->hw.isurf.isac + offset)); 40} 41 42static void 43WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 44{ 45 writeb(value, cs->hw.isurf.isac + offset); mb(); 46} 47 48static void 49ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) 50{ 51 register int i; 52 for (i = 0; i < size; i++) 53 data[i] = readb(cs->hw.isurf.isac); 54} 55 56static void 57WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) 58{ 59 register int i; 60 for (i = 0; i < size; i++) { 61 writeb(data[i], cs->hw.isurf.isac); mb(); 62 } 63} 64 65/* ISAR access routines 66 * mode = 0 access with IRQ on 67 * mode = 1 access with IRQ off 68 * mode = 2 access with IRQ off and using last offset 69 */ 70 71static u_char 72ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) 73{ 74 return (readb(cs->hw.isurf.isar + offset)); 75} 76 77static void 78WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) 79{ 80 writeb(value, cs->hw.isurf.isar + offset); mb(); 81} 82 83static irqreturn_t 84isurf_interrupt(int intno, void *dev_id) 85{ 86 struct IsdnCardState *cs = dev_id; 87 u_char val; 88 int cnt = 5; 89 u_long flags; 90 91 spin_lock_irqsave(&cs->lock, flags); 92 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); 93Start_ISAR: 94 if (val & ISAR_IRQSTA) 95 isar_int_main(cs); 96 val = readb(cs->hw.isurf.isac + ISAC_ISTA); 97Start_ISAC: 98 if (val) 99 isac_interrupt(cs, val); 100 val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); 101 if ((val & ISAR_IRQSTA) && --cnt) { 102 if (cs->debug & L1_DEB_HSCX) 103 debugl1(cs, "ISAR IntStat after IntRoutine"); 104 goto Start_ISAR; 105 } 106 val = readb(cs->hw.isurf.isac + ISAC_ISTA); 107 if (val && --cnt) { 108 if (cs->debug & L1_DEB_ISAC) 109 debugl1(cs, "ISAC IntStat after IntRoutine"); 110 goto Start_ISAC; 111 } 112 if (!cnt) 113 printk(KERN_WARNING "ISurf IRQ LOOP\n"); 114 115 writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); 116 writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK); mb(); 117 writeb(0, cs->hw.isurf.isac + ISAC_MASK); mb(); 118 writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); 119 spin_unlock_irqrestore(&cs->lock, flags); 120 return IRQ_HANDLED; 121} 122 123static void 124release_io_isurf(struct IsdnCardState *cs) 125{ 126 release_region(cs->hw.isurf.reset, 1); 127 iounmap(cs->hw.isurf.isar); 128 release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); 129} 130 131static void 132reset_isurf(struct IsdnCardState *cs, u_char chips) 133{ 134 printk(KERN_INFO "ISurf: resetting card\n"); 135 136 byteout(cs->hw.isurf.reset, chips); /* Reset On */ 137 mdelay(10); 138 byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ 139 mdelay(10); 140} 141 142static int 143ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) 144{ 145 u_long flags; 146 147 switch (mt) { 148 case CARD_RESET: 149 spin_lock_irqsave(&cs->lock, flags); 150 reset_isurf(cs, ISURF_RESET); 151 spin_unlock_irqrestore(&cs->lock, flags); 152 return (0); 153 case CARD_RELEASE: 154 release_io_isurf(cs); 155 return (0); 156 case CARD_INIT: 157 spin_lock_irqsave(&cs->lock, flags); 158 reset_isurf(cs, ISURF_RESET); 159 clear_pending_isac_ints(cs); 160 writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); 161 initisac(cs); 162 initisar(cs); 163 /* Reenable ISAC IRQ */ 164 cs->writeisac(cs, ISAC_MASK, 0); 165 /* RESET Receiver and Transmitter */ 166 cs->writeisac(cs, ISAC_CMDR, 0x41); 167 spin_unlock_irqrestore(&cs->lock, flags); 168 return (0); 169 case CARD_TEST: 170 return (0); 171 } 172 return (0); 173} 174 175static int 176isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { 177 int ret; 178 u_long flags; 179 180 if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { 181 ret = isar_auxcmd(cs, ic); 182 spin_lock_irqsave(&cs->lock, flags); 183 if (!ret) { 184 reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | 185 ISURF_ARCOFI_RESET); 186 initisac(cs); 187 cs->writeisac(cs, ISAC_MASK, 0); 188 cs->writeisac(cs, ISAC_CMDR, 0x41); 189 } 190 spin_unlock_irqrestore(&cs->lock, flags); 191 return (ret); 192 } 193 return (isar_auxcmd(cs, ic)); 194} 195 196#ifdef __ISAPNP__ 197static struct pnp_card *pnp_c = NULL; 198#endif 199 200int setup_isurf(struct IsdnCard *card) 201{ 202 int ver; 203 struct IsdnCardState *cs = card->cs; 204 char tmp[64]; 205 206 strcpy(tmp, ISurf_revision); 207 printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); 208 209 if (cs->typ != ISDN_CTYPE_ISURF) 210 return (0); 211 if (card->para[1] && card->para[2]) { 212 cs->hw.isurf.reset = card->para[1]; 213 cs->hw.isurf.phymem = card->para[2]; 214 cs->irq = card->para[0]; 215 } else { 216#ifdef __ISAPNP__ 217 if (isapnp_present()) { 218 struct pnp_dev *pnp_d = NULL; 219 int err; 220 221 cs->subtyp = 0; 222 if ((pnp_c = pnp_find_card( 223 ISAPNP_VENDOR('S', 'I', 'E'), 224 ISAPNP_FUNCTION(0x0010), pnp_c))) { 225 if (!(pnp_d = pnp_find_dev(pnp_c, 226 ISAPNP_VENDOR('S', 'I', 'E'), 227 ISAPNP_FUNCTION(0x0010), pnp_d))) { 228 printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); 229 return (0); 230 } 231 pnp_disable_dev(pnp_d); 232 err = pnp_activate_dev(pnp_d); 233 if (err < 0) { 234 pr_warn("%s: pnp_activate_dev ret=%d\n", 235 __func__, err); 236 return 0; 237 } 238 cs->hw.isurf.reset = pnp_port_start(pnp_d, 0); 239 cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1); 240 cs->irq = pnp_irq(pnp_d, 0); 241 if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { 242 printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", 243 cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem); 244 pnp_disable_dev(pnp_d); 245 return (0); 246 } 247 } else { 248 printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); 249 return (0); 250 } 251 } else { 252 printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n"); 253 return (0); 254 } 255#else 256 printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n"); 257 return (0); 258#endif 259 } 260 if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) { 261 printk(KERN_WARNING 262 "HiSax: Siemens I-Surf config port %x already in use\n", 263 cs->hw.isurf.reset); 264 return (0); 265 } 266 if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) { 267 printk(KERN_WARNING "HiSax: Siemens I-Surf memory region " 268 "%lx-%lx already in use\n", 269 cs->hw.isurf.phymem, 270 cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); 271 release_region(cs->hw.isurf.reset, 1); 272 return (0); 273 } 274 cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); 275 cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; 276 printk(KERN_INFO 277 "ISurf: defined at 0x%x 0x%lx IRQ %d\n", 278 cs->hw.isurf.reset, 279 cs->hw.isurf.phymem, 280 cs->irq); 281 282 setup_isac(cs); 283 cs->cardmsg = &ISurf_card_msg; 284 cs->irq_func = &isurf_interrupt; 285 cs->auxcmd = &isurf_auxcmd; 286 cs->readisac = &ReadISAC; 287 cs->writeisac = &WriteISAC; 288 cs->readisacfifo = &ReadISACfifo; 289 cs->writeisacfifo = &WriteISACfifo; 290 cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; 291 cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; 292 test_and_set_bit(HW_ISAR, &cs->HW_Flags); 293 ISACVersion(cs, "ISurf:"); 294 cs->BC_Read_Reg = &ReadISAR; 295 cs->BC_Write_Reg = &WriteISAR; 296 cs->BC_Send_Data = &isar_fill_fifo; 297 ver = ISARVersion(cs, "ISurf:"); 298 if (ver < 0) { 299 printk(KERN_WARNING 300 "ISurf: wrong ISAR version (ret = %d)\n", ver); 301 release_io_isurf(cs); 302 return (0); 303 } 304 return (1); 305} 306