1/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 Exp $ 2 * 3 * low level stuff for USR Sportster internal TA 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 Christian "naddy" Weisgerber (3Com, US Robotics) for documentation 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 const char *sportster_revision = "$Revision: 1.16.2.4 $"; 22 23#define byteout(addr,val) outb(val,addr) 24#define bytein(addr) inb(addr) 25 26#define SPORTSTER_ISAC 0xC000 27#define SPORTSTER_HSCXA 0x0000 28#define SPORTSTER_HSCXB 0x4000 29#define SPORTSTER_RES_IRQ 0x8000 30#define SPORTSTER_RESET 0x80 31#define SPORTSTER_INTE 0x40 32 33static inline int 34calc_off(unsigned int base, unsigned int off) 35{ 36 return(base + ((off & 0xfc)<<8) + ((off & 3)<<1)); 37} 38 39static inline void 40read_fifo(unsigned int adr, u_char * data, int size) 41{ 42 insb(adr, data, size); 43} 44 45static void 46write_fifo(unsigned int adr, u_char * data, int size) 47{ 48 outsb(adr, data, size); 49} 50 51/* Interface functions */ 52 53static u_char 54ReadISAC(struct IsdnCardState *cs, u_char offset) 55{ 56 return (bytein(calc_off(cs->hw.spt.isac, offset))); 57} 58 59static void 60WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 61{ 62 byteout(calc_off(cs->hw.spt.isac, offset), value); 63} 64 65static void 66ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 67{ 68 read_fifo(cs->hw.spt.isac, data, size); 69} 70 71static void 72WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 73{ 74 write_fifo(cs->hw.spt.isac, data, size); 75} 76 77static u_char 78ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 79{ 80 return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset))); 81} 82 83static void 84WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 85{ 86 byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value); 87} 88 89/* 90 * fast interrupt HSCX stuff goes here 91 */ 92 93#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg)) 94#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data) 95#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt) 96#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt) 97 98#include "hscx_irq.c" 99 100static irqreturn_t 101sportster_interrupt(int intno, void *dev_id) 102{ 103 struct IsdnCardState *cs = dev_id; 104 u_char val; 105 u_long flags; 106 107 spin_lock_irqsave(&cs->lock, flags); 108 val = READHSCX(cs, 1, HSCX_ISTA); 109 Start_HSCX: 110 if (val) 111 hscx_int_main(cs, val); 112 val = ReadISAC(cs, ISAC_ISTA); 113 Start_ISAC: 114 if (val) 115 isac_interrupt(cs, val); 116 val = READHSCX(cs, 1, HSCX_ISTA); 117 if (val) { 118 if (cs->debug & L1_DEB_HSCX) 119 debugl1(cs, "HSCX IntStat after IntRoutine"); 120 goto Start_HSCX; 121 } 122 val = ReadISAC(cs, ISAC_ISTA); 123 if (val) { 124 if (cs->debug & L1_DEB_ISAC) 125 debugl1(cs, "ISAC IntStat after IntRoutine"); 126 goto Start_ISAC; 127 } 128 /* get a new irq impulse if there any pending */ 129 bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ +1); 130 spin_unlock_irqrestore(&cs->lock, flags); 131 return IRQ_HANDLED; 132} 133 134static void 135release_io_sportster(struct IsdnCardState *cs) 136{ 137 int i, adr; 138 139 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0); 140 for (i=0; i<64; i++) { 141 adr = cs->hw.spt.cfg_reg + i *1024; 142 release_region(adr, 8); 143 } 144} 145 146static void 147reset_sportster(struct IsdnCardState *cs) 148{ 149 cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */ 150 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); 151 mdelay(10); 152 cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ 153 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); 154 mdelay(10); 155} 156 157static int 158Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) 159{ 160 u_long flags; 161 162 switch (mt) { 163 case CARD_RESET: 164 spin_lock_irqsave(&cs->lock, flags); 165 reset_sportster(cs); 166 spin_unlock_irqrestore(&cs->lock, flags); 167 return(0); 168 case CARD_RELEASE: 169 release_io_sportster(cs); 170 return(0); 171 case CARD_INIT: 172 spin_lock_irqsave(&cs->lock, flags); 173 reset_sportster(cs); 174 inithscxisac(cs, 1); 175 cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ 176 byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); 177 inithscxisac(cs, 2); 178 spin_unlock_irqrestore(&cs->lock, flags); 179 return(0); 180 case CARD_TEST: 181 return(0); 182 } 183 return(0); 184} 185 186static int __devinit 187get_io_range(struct IsdnCardState *cs) 188{ 189 int i, j, adr; 190 191 for (i=0;i<64;i++) { 192 adr = cs->hw.spt.cfg_reg + i *1024; 193 if (!request_region(adr, 8, "sportster")) { 194 printk(KERN_WARNING "HiSax: USR Sportster config port " 195 "%x-%x already in use\n", 196 adr, adr + 8); 197 break; 198 } 199 } 200 if (i==64) 201 return(1); 202 else { 203 for (j=0; j<i; j++) { 204 adr = cs->hw.spt.cfg_reg + j *1024; 205 release_region(adr, 8); 206 } 207 return(0); 208 } 209} 210 211int __devinit 212setup_sportster(struct IsdnCard *card) 213{ 214 struct IsdnCardState *cs = card->cs; 215 char tmp[64]; 216 217 strcpy(tmp, sportster_revision); 218 printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp)); 219 if (cs->typ != ISDN_CTYPE_SPORTSTER) 220 return (0); 221 222 cs->hw.spt.cfg_reg = card->para[1]; 223 cs->irq = card->para[0]; 224 if (!get_io_range(cs)) 225 return (0); 226 cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC; 227 cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA; 228 cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB; 229 230 switch(cs->irq) { 231 case 5: cs->hw.spt.res_irq = 1; 232 break; 233 case 7: cs->hw.spt.res_irq = 2; 234 break; 235 case 10:cs->hw.spt.res_irq = 3; 236 break; 237 case 11:cs->hw.spt.res_irq = 4; 238 break; 239 case 12:cs->hw.spt.res_irq = 5; 240 break; 241 case 14:cs->hw.spt.res_irq = 6; 242 break; 243 case 15:cs->hw.spt.res_irq = 7; 244 break; 245 default:release_io_sportster(cs); 246 printk(KERN_WARNING "Sportster: wrong IRQ\n"); 247 return(0); 248 } 249 printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n", 250 cs->irq, cs->hw.spt.cfg_reg); 251 setup_isac(cs); 252 cs->readisac = &ReadISAC; 253 cs->writeisac = &WriteISAC; 254 cs->readisacfifo = &ReadISACfifo; 255 cs->writeisacfifo = &WriteISACfifo; 256 cs->BC_Read_Reg = &ReadHSCX; 257 cs->BC_Write_Reg = &WriteHSCX; 258 cs->BC_Send_Data = &hscx_fill_fifo; 259 cs->cardmsg = &Sportster_card_msg; 260 cs->irq_func = &sportster_interrupt; 261 ISACVersion(cs, "Sportster:"); 262 if (HscxVersion(cs, "Sportster:")) { 263 printk(KERN_WARNING 264 "Sportster: wrong HSCX versions check IO address\n"); 265 release_io_sportster(cs); 266 return (0); 267 } 268 return (1); 269} 270