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); 93 Start_ISAR: 94 if (val & ISAR_IRQSTA) 95 isar_int_main(cs); 96 val = readb(cs->hw.isurf.isac + ISAC_ISTA); 97 Start_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 __devinitdata = NULL; 198#endif 199 200int __devinit 201setup_isurf(struct IsdnCard *card) 202{ 203 int ver; 204 struct IsdnCardState *cs = card->cs; 205 char tmp[64]; 206 207 strcpy(tmp, ISurf_revision); 208 printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); 209 210 if (cs->typ != ISDN_CTYPE_ISURF) 211 return(0); 212 if (card->para[1] && card->para[2]) { 213 cs->hw.isurf.reset = card->para[1]; 214 cs->hw.isurf.phymem = card->para[2]; 215 cs->irq = card->para[0]; 216 } else { 217#ifdef __ISAPNP__ 218 if (isapnp_present()) { 219 struct pnp_dev *pnp_d = NULL; 220 int err; 221 222 cs->subtyp = 0; 223 if ((pnp_c = pnp_find_card( 224 ISAPNP_VENDOR('S', 'I', 'E'), 225 ISAPNP_FUNCTION(0x0010), pnp_c))) { 226 if (!(pnp_d = pnp_find_dev(pnp_c, 227 ISAPNP_VENDOR('S', 'I', 'E'), 228 ISAPNP_FUNCTION(0x0010), pnp_d))) { 229 printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); 230 return (0); 231 } 232 pnp_disable_dev(pnp_d); 233 err = pnp_activate_dev(pnp_d); 234 cs->hw.isurf.reset = pnp_port_start(pnp_d, 0); 235 cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1); 236 cs->irq = pnp_irq(pnp_d, 0); 237 if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { 238 printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", 239 cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem); 240 pnp_disable_dev(pnp_d); 241 return(0); 242 } 243 } else { 244 printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); 245 return(0); 246 } 247 } else { 248 printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n"); 249 return(0); 250 } 251#else 252 printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n"); 253 return (0); 254#endif 255 } 256 if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) { 257 printk(KERN_WARNING 258 "HiSax: Siemens I-Surf config port %x already in use\n", 259 cs->hw.isurf.reset); 260 return (0); 261 } 262 if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) { 263 printk(KERN_WARNING "HiSax: Siemens I-Surf memory region " 264 "%lx-%lx already in use\n", 265 cs->hw.isurf.phymem, 266 cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); 267 release_region(cs->hw.isurf.reset, 1); 268 return (0); 269 } 270 cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); 271 cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; 272 printk(KERN_INFO 273 "ISurf: defined at 0x%x 0x%lx IRQ %d\n", 274 cs->hw.isurf.reset, 275 cs->hw.isurf.phymem, 276 cs->irq); 277 278 setup_isac(cs); 279 cs->cardmsg = &ISurf_card_msg; 280 cs->irq_func = &isurf_interrupt; 281 cs->auxcmd = &isurf_auxcmd; 282 cs->readisac = &ReadISAC; 283 cs->writeisac = &WriteISAC; 284 cs->readisacfifo = &ReadISACfifo; 285 cs->writeisacfifo = &WriteISACfifo; 286 cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; 287 cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; 288 test_and_set_bit(HW_ISAR, &cs->HW_Flags); 289 ISACVersion(cs, "ISurf:"); 290 cs->BC_Read_Reg = &ReadISAR; 291 cs->BC_Write_Reg = &WriteISAR; 292 cs->BC_Send_Data = &isar_fill_fifo; 293 ver = ISARVersion(cs, "ISurf:"); 294 if (ver < 0) { 295 printk(KERN_WARNING 296 "ISurf: wrong ISAR version (ret = %d)\n", ver); 297 release_io_isurf(cs); 298 return (0); 299 } 300 return (1); 301} 302