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