1/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 Exp $ 2 * 3 * low level stuff for ITK ix1-micro Rev.2 isdn cards 4 * derived from the original file teles3.c from Karsten Keil 5 * 6 * Author Klaus-Peter Nischke 7 * Copyright by Klaus-Peter Nischke, ITK AG 8 * <klaus@nischke.do.eunet.de> 9 * by Karsten Keil <keil@isdn4linux.de> 10 * 11 * This software may be used and distributed according to the terms 12 * of the GNU General Public License, incorporated herein by reference. 13 * 14 * Klaus-Peter Nischke 15 * Deusener Str. 287 16 * 44369 Dortmund 17 * Germany 18 */ 19 20#include <linux/init.h> 21#include <linux/isapnp.h> 22#include "hisax.h" 23#include "isac.h" 24#include "hscx.h" 25#include "isdnl1.h" 26 27static const char *ix1_revision = "$Revision: 2.12.2.4 $"; 28 29#define byteout(addr,val) outb(val,addr) 30#define bytein(addr) inb(addr) 31 32#define SPECIAL_PORT_OFFSET 3 33 34#define ISAC_COMMAND_OFFSET 2 35#define ISAC_DATA_OFFSET 0 36#define HSCX_COMMAND_OFFSET 2 37#define HSCX_DATA_OFFSET 1 38 39#define TIMEOUT 50 40 41static inline u_char 42readreg(unsigned int ale, unsigned int adr, u_char off) 43{ 44 register u_char ret; 45 46 byteout(ale, off); 47 ret = bytein(adr); 48 return (ret); 49} 50 51static inline void 52readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 53{ 54 byteout(ale, off); 55 insb(adr, data, size); 56} 57 58 59static inline void 60writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) 61{ 62 byteout(ale, off); 63 byteout(adr, data); 64} 65 66static inline void 67writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 68{ 69 byteout(ale, off); 70 outsb(adr, data, size); 71} 72 73/* Interface functions */ 74 75static u_char 76ReadISAC(struct IsdnCardState *cs, u_char offset) 77{ 78 return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); 79} 80 81static void 82WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 83{ 84 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); 85} 86 87static void 88ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 89{ 90 readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); 91} 92 93static void 94WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 95{ 96 writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); 97} 98 99static u_char 100ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 101{ 102 return (readreg(cs->hw.ix1.hscx_ale, 103 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); 104} 105 106static void 107WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 108{ 109 writereg(cs->hw.ix1.hscx_ale, 110 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); 111} 112 113#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ 114 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) 115#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ 116 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) 117 118#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ 119 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) 120 121#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ 122 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) 123 124#include "hscx_irq.c" 125 126static irqreturn_t 127ix1micro_interrupt(int intno, void *dev_id) 128{ 129 struct IsdnCardState *cs = dev_id; 130 u_char val; 131 u_long flags; 132 133 spin_lock_irqsave(&cs->lock, flags); 134 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); 135 Start_HSCX: 136 if (val) 137 hscx_int_main(cs, val); 138 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); 139 Start_ISAC: 140 if (val) 141 isac_interrupt(cs, val); 142 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); 143 if (val) { 144 if (cs->debug & L1_DEB_HSCX) 145 debugl1(cs, "HSCX IntStat after IntRoutine"); 146 goto Start_HSCX; 147 } 148 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); 149 if (val) { 150 if (cs->debug & L1_DEB_ISAC) 151 debugl1(cs, "ISAC IntStat after IntRoutine"); 152 goto Start_ISAC; 153 } 154 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); 155 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); 156 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); 157 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); 158 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); 159 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); 160 spin_unlock_irqrestore(&cs->lock, flags); 161 return IRQ_HANDLED; 162} 163 164static void 165release_io_ix1micro(struct IsdnCardState *cs) 166{ 167 if (cs->hw.ix1.cfg_reg) 168 release_region(cs->hw.ix1.cfg_reg, 4); 169} 170 171static void 172ix1_reset(struct IsdnCardState *cs) 173{ 174 int cnt; 175 176 /* reset isac */ 177 cnt = 3 * (HZ / 10) + 1; 178 while (cnt--) { 179 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1); 180 HZDELAY(1); /* wait >=10 ms */ 181 } 182 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); 183} 184 185static int 186ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) 187{ 188 u_long flags; 189 190 switch (mt) { 191 case CARD_RESET: 192 spin_lock_irqsave(&cs->lock, flags); 193 ix1_reset(cs); 194 spin_unlock_irqrestore(&cs->lock, flags); 195 return(0); 196 case CARD_RELEASE: 197 release_io_ix1micro(cs); 198 return(0); 199 case CARD_INIT: 200 spin_lock_irqsave(&cs->lock, flags); 201 ix1_reset(cs); 202 inithscxisac(cs, 3); 203 spin_unlock_irqrestore(&cs->lock, flags); 204 return(0); 205 case CARD_TEST: 206 return(0); 207 } 208 return(0); 209} 210 211#ifdef __ISAPNP__ 212static struct isapnp_device_id itk_ids[] __devinitdata = { 213 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 214 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 215 (unsigned long) "ITK micro 2" }, 216 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 217 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 218 (unsigned long) "ITK micro 2." }, 219 { 0, } 220}; 221 222static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0]; 223static struct pnp_card *pnp_c __devinitdata = NULL; 224#endif 225 226 227int __devinit 228setup_ix1micro(struct IsdnCard *card) 229{ 230 struct IsdnCardState *cs = card->cs; 231 char tmp[64]; 232 233 strcpy(tmp, ix1_revision); 234 printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); 235 if (cs->typ != ISDN_CTYPE_IX1MICROR2) 236 return (0); 237 238#ifdef __ISAPNP__ 239 if (!card->para[1] && isapnp_present()) { 240 struct pnp_dev *pnp_d; 241 while(ipid->card_vendor) { 242 if ((pnp_c = pnp_find_card(ipid->card_vendor, 243 ipid->card_device, pnp_c))) { 244 pnp_d = NULL; 245 if ((pnp_d = pnp_find_dev(pnp_c, 246 ipid->vendor, ipid->function, pnp_d))) { 247 int err; 248 249 printk(KERN_INFO "HiSax: %s detected\n", 250 (char *)ipid->driver_data); 251 pnp_disable_dev(pnp_d); 252 err = pnp_activate_dev(pnp_d); 253 if (err<0) { 254 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", 255 __func__, err); 256 return(0); 257 } 258 card->para[1] = pnp_port_start(pnp_d, 0); 259 card->para[0] = pnp_irq(pnp_d, 0); 260 if (!card->para[0] || !card->para[1]) { 261 printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", 262 card->para[0], card->para[1]); 263 pnp_disable_dev(pnp_d); 264 return(0); 265 } 266 break; 267 } else { 268 printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); 269 } 270 } 271 ipid++; 272 pnp_c = NULL; 273 } 274 if (!ipid->card_vendor) { 275 printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); 276 return(0); 277 } 278 } 279#endif 280 /* IO-Ports */ 281 cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; 282 cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; 283 cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; 284 cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; 285 cs->hw.ix1.cfg_reg = card->para[1]; 286 cs->irq = card->para[0]; 287 if (cs->hw.ix1.cfg_reg) { 288 if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { 289 printk(KERN_WARNING 290 "HiSax: ITK ix1-micro Rev.2 config port " 291 "%x-%x already in use\n", 292 cs->hw.ix1.cfg_reg, 293 cs->hw.ix1.cfg_reg + 4); 294 return (0); 295 } 296 } 297 printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n", 298 cs->irq, cs->hw.ix1.cfg_reg); 299 setup_isac(cs); 300 cs->readisac = &ReadISAC; 301 cs->writeisac = &WriteISAC; 302 cs->readisacfifo = &ReadISACfifo; 303 cs->writeisacfifo = &WriteISACfifo; 304 cs->BC_Read_Reg = &ReadHSCX; 305 cs->BC_Write_Reg = &WriteHSCX; 306 cs->BC_Send_Data = &hscx_fill_fifo; 307 cs->cardmsg = &ix1_card_msg; 308 cs->irq_func = &ix1micro_interrupt; 309 ISACVersion(cs, "ix1-Micro:"); 310 if (HscxVersion(cs, "ix1-Micro:")) { 311 printk(KERN_WARNING 312 "ix1-Micro: wrong HSCX versions check IO address\n"); 313 release_io_ix1micro(cs); 314 return (0); 315 } 316 return (1); 317} 318