1/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $ 2 * 3 * low level stuff for HST Saphir 1 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 * Thanks to HST High Soft Tech GmbH 12 * 13 */ 14 15#include <linux/init.h> 16#include "hisax.h" 17#include "isac.h" 18#include "hscx.h" 19#include "isdnl1.h" 20 21static char *saphir_rev = "$Revision: 1.10.2.4 $"; 22 23#define byteout(addr, val) outb(val, addr) 24#define bytein(addr) inb(addr) 25 26#define ISAC_DATA 0 27#define HSCX_DATA 1 28#define ADDRESS_REG 2 29#define IRQ_REG 3 30#define SPARE_REG 4 31#define RESET_REG 5 32 33static inline u_char 34readreg(unsigned int ale, unsigned int adr, u_char off) 35{ 36 register u_char ret; 37 38 byteout(ale, off); 39 ret = bytein(adr); 40 return (ret); 41} 42 43static inline void 44readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) 45{ 46 byteout(ale, off); 47 insb(adr, data, size); 48} 49 50 51static inline void 52writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) 53{ 54 byteout(ale, off); 55 byteout(adr, data); 56} 57 58static inline void 59writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) 60{ 61 byteout(ale, off); 62 outsb(adr, data, size); 63} 64 65/* Interface functions */ 66 67static u_char 68ReadISAC(struct IsdnCardState *cs, u_char offset) 69{ 70 return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); 71} 72 73static void 74WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 75{ 76 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); 77} 78 79static void 80ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) 81{ 82 readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); 83} 84 85static void 86WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) 87{ 88 writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); 89} 90 91static u_char 92ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 93{ 94 return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, 95 offset + (hscx ? 0x40 : 0))); 96} 97 98static void 99WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 100{ 101 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, 102 offset + (hscx ? 0x40 : 0), value); 103} 104 105#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ 106 cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) 107#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ 108 cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) 109 110#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ 111 cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) 112 113#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ 114 cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) 115 116#include "hscx_irq.c" 117 118static irqreturn_t 119saphir_interrupt(int intno, void *dev_id) 120{ 121 struct IsdnCardState *cs = dev_id; 122 u_char val; 123 u_long flags; 124 125 spin_lock_irqsave(&cs->lock, flags); 126 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); 127Start_HSCX: 128 if (val) 129 hscx_int_main(cs, val); 130 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); 131Start_ISAC: 132 if (val) 133 isac_interrupt(cs, val); 134 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); 135 if (val) { 136 if (cs->debug & L1_DEB_HSCX) 137 debugl1(cs, "HSCX IntStat after IntRoutine"); 138 goto Start_HSCX; 139 } 140 val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); 141 if (val) { 142 if (cs->debug & L1_DEB_ISAC) 143 debugl1(cs, "ISAC IntStat after IntRoutine"); 144 goto Start_ISAC; 145 } 146 /* Watchdog */ 147 if (cs->hw.saphir.timer.function) 148 mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); 149 else 150 printk(KERN_WARNING "saphir: Spurious timer!\n"); 151 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); 152 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); 153 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); 154 writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); 155 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); 156 writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); 157 spin_unlock_irqrestore(&cs->lock, flags); 158 return IRQ_HANDLED; 159} 160 161static void 162SaphirWatchDog(struct IsdnCardState *cs) 163{ 164 u_long flags; 165 166 spin_lock_irqsave(&cs->lock, flags); 167 /* 5 sec WatchDog, so read at least every 4 sec */ 168 cs->readisac(cs, ISAC_RBCH); 169 spin_unlock_irqrestore(&cs->lock, flags); 170 mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); 171} 172 173static void 174release_io_saphir(struct IsdnCardState *cs) 175{ 176 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); 177 del_timer(&cs->hw.saphir.timer); 178 cs->hw.saphir.timer.function = NULL; 179 if (cs->hw.saphir.cfg_reg) 180 release_region(cs->hw.saphir.cfg_reg, 6); 181} 182 183static int 184saphir_reset(struct IsdnCardState *cs) 185{ 186 u_char irq_val; 187 188 switch (cs->irq) { 189 case 5: irq_val = 0; 190 break; 191 case 3: irq_val = 1; 192 break; 193 case 11: 194 irq_val = 2; 195 break; 196 case 12: 197 irq_val = 3; 198 break; 199 case 15: 200 irq_val = 4; 201 break; 202 default: 203 printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n", 204 cs->irq); 205 return (1); 206 } 207 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); 208 byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); 209 mdelay(10); 210 byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); 211 mdelay(10); 212 byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); 213 byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); 214 return (0); 215} 216 217static int 218saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) 219{ 220 u_long flags; 221 222 switch (mt) { 223 case CARD_RESET: 224 spin_lock_irqsave(&cs->lock, flags); 225 saphir_reset(cs); 226 spin_unlock_irqrestore(&cs->lock, flags); 227 return (0); 228 case CARD_RELEASE: 229 release_io_saphir(cs); 230 return (0); 231 case CARD_INIT: 232 spin_lock_irqsave(&cs->lock, flags); 233 inithscxisac(cs, 3); 234 spin_unlock_irqrestore(&cs->lock, flags); 235 return (0); 236 case CARD_TEST: 237 return (0); 238 } 239 return (0); 240} 241 242 243int __devinit 244setup_saphir(struct IsdnCard *card) 245{ 246 struct IsdnCardState *cs = card->cs; 247 char tmp[64]; 248 249 strcpy(tmp, saphir_rev); 250 printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); 251 if (cs->typ != ISDN_CTYPE_HSTSAPHIR) 252 return (0); 253 254 /* IO-Ports */ 255 cs->hw.saphir.cfg_reg = card->para[1]; 256 cs->hw.saphir.isac = card->para[1] + ISAC_DATA; 257 cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; 258 cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; 259 cs->irq = card->para[0]; 260 if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) { 261 printk(KERN_WARNING 262 "HiSax: HST Saphir config port %x-%x already in use\n", 263 cs->hw.saphir.cfg_reg, 264 cs->hw.saphir.cfg_reg + 5); 265 return (0); 266 } 267 268 printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n", 269 cs->irq, cs->hw.saphir.cfg_reg); 270 271 setup_isac(cs); 272 cs->hw.saphir.timer.function = (void *) SaphirWatchDog; 273 cs->hw.saphir.timer.data = (long) cs; 274 init_timer(&cs->hw.saphir.timer); 275 cs->hw.saphir.timer.expires = jiffies + 4 * HZ; 276 add_timer(&cs->hw.saphir.timer); 277 if (saphir_reset(cs)) { 278 release_io_saphir(cs); 279 return (0); 280 } 281 cs->readisac = &ReadISAC; 282 cs->writeisac = &WriteISAC; 283 cs->readisacfifo = &ReadISACfifo; 284 cs->writeisacfifo = &WriteISACfifo; 285 cs->BC_Read_Reg = &ReadHSCX; 286 cs->BC_Write_Reg = &WriteHSCX; 287 cs->BC_Send_Data = &hscx_fill_fifo; 288 cs->cardmsg = &saphir_card_msg; 289 cs->irq_func = &saphir_interrupt; 290 ISACVersion(cs, "saphir:"); 291 if (HscxVersion(cs, "saphir:")) { 292 printk(KERN_WARNING 293 "saphir: wrong HSCX versions check IO address\n"); 294 release_io_saphir(cs); 295 return (0); 296 } 297 return (1); 298} 299