1/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil 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); 109Start_HSCX: 110 if (val) 111 hscx_int_main(cs, val); 112 val = ReadISAC(cs, ISAC_ISTA); 113Start_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 get_io_range(struct IsdnCardState *cs) 187{ 188 int i, j, adr; 189 190 for (i = 0; i < 64; i++) { 191 adr = cs->hw.spt.cfg_reg + i * 1024; 192 if (!request_region(adr, 8, "sportster")) { 193 printk(KERN_WARNING "HiSax: USR Sportster config port " 194 "%x-%x already in use\n", 195 adr, adr + 8); 196 break; 197 } 198 } 199 if (i == 64) 200 return (1); 201 else { 202 for (j = 0; j < i; j++) { 203 adr = cs->hw.spt.cfg_reg + j * 1024; 204 release_region(adr, 8); 205 } 206 return (0); 207 } 208} 209 210int setup_sportster(struct IsdnCard *card) 211{ 212 struct IsdnCardState *cs = card->cs; 213 char tmp[64]; 214 215 strcpy(tmp, sportster_revision); 216 printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp)); 217 if (cs->typ != ISDN_CTYPE_SPORTSTER) 218 return (0); 219 220 cs->hw.spt.cfg_reg = card->para[1]; 221 cs->irq = card->para[0]; 222 if (!get_io_range(cs)) 223 return (0); 224 cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC; 225 cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA; 226 cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB; 227 228 switch (cs->irq) { 229 case 5: cs->hw.spt.res_irq = 1; 230 break; 231 case 7: cs->hw.spt.res_irq = 2; 232 break; 233 case 10:cs->hw.spt.res_irq = 3; 234 break; 235 case 11:cs->hw.spt.res_irq = 4; 236 break; 237 case 12:cs->hw.spt.res_irq = 5; 238 break; 239 case 14:cs->hw.spt.res_irq = 6; 240 break; 241 case 15:cs->hw.spt.res_irq = 7; 242 break; 243 default:release_io_sportster(cs); 244 printk(KERN_WARNING "Sportster: wrong IRQ\n"); 245 return (0); 246 } 247 printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n", 248 cs->irq, cs->hw.spt.cfg_reg); 249 setup_isac(cs); 250 cs->readisac = &ReadISAC; 251 cs->writeisac = &WriteISAC; 252 cs->readisacfifo = &ReadISACfifo; 253 cs->writeisacfifo = &WriteISACfifo; 254 cs->BC_Read_Reg = &ReadHSCX; 255 cs->BC_Write_Reg = &WriteHSCX; 256 cs->BC_Send_Data = &hscx_fill_fifo; 257 cs->cardmsg = &Sportster_card_msg; 258 cs->irq_func = &sportster_interrupt; 259 ISACVersion(cs, "Sportster:"); 260 if (HscxVersion(cs, "Sportster:")) { 261 printk(KERN_WARNING 262 "Sportster: wrong HSCX versions check IO address\n"); 263 release_io_sportster(cs); 264 return (0); 265 } 266 return (1); 267} 268