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