1/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil 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); 135Start_HSCX: 136 if (val) 137 hscx_int_main(cs, val); 138 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); 139Start_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[] = { 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 = &itk_ids[0]; 223static struct pnp_card *pnp_c = NULL; 224#endif 225 226 227int setup_ix1micro(struct IsdnCard *card) 228{ 229 struct IsdnCardState *cs = card->cs; 230 char tmp[64]; 231 232 strcpy(tmp, ix1_revision); 233 printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); 234 if (cs->typ != ISDN_CTYPE_IX1MICROR2) 235 return (0); 236 237#ifdef __ISAPNP__ 238 if (!card->para[1] && isapnp_present()) { 239 struct pnp_dev *pnp_d; 240 while (ipid->card_vendor) { 241 if ((pnp_c = pnp_find_card(ipid->card_vendor, 242 ipid->card_device, pnp_c))) { 243 pnp_d = NULL; 244 if ((pnp_d = pnp_find_dev(pnp_c, 245 ipid->vendor, ipid->function, pnp_d))) { 246 int err; 247 248 printk(KERN_INFO "HiSax: %s detected\n", 249 (char *)ipid->driver_data); 250 pnp_disable_dev(pnp_d); 251 err = pnp_activate_dev(pnp_d); 252 if (err < 0) { 253 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", 254 __func__, err); 255 return (0); 256 } 257 card->para[1] = pnp_port_start(pnp_d, 0); 258 card->para[0] = pnp_irq(pnp_d, 0); 259 if (!card->para[0] || !card->para[1]) { 260 printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", 261 card->para[0], card->para[1]); 262 pnp_disable_dev(pnp_d); 263 return (0); 264 } 265 break; 266 } else { 267 printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); 268 } 269 } 270 ipid++; 271 pnp_c = NULL; 272 } 273 if (!ipid->card_vendor) { 274 printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); 275 return (0); 276 } 277 } 278#endif 279 /* IO-Ports */ 280 cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; 281 cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; 282 cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; 283 cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; 284 cs->hw.ix1.cfg_reg = card->para[1]; 285 cs->irq = card->para[0]; 286 if (cs->hw.ix1.cfg_reg) { 287 if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { 288 printk(KERN_WARNING 289 "HiSax: ITK ix1-micro Rev.2 config port " 290 "%x-%x already in use\n", 291 cs->hw.ix1.cfg_reg, 292 cs->hw.ix1.cfg_reg + 4); 293 return (0); 294 } 295 } 296 printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n", 297 cs->irq, cs->hw.ix1.cfg_reg); 298 setup_isac(cs); 299 cs->readisac = &ReadISAC; 300 cs->writeisac = &WriteISAC; 301 cs->readisacfifo = &ReadISACfifo; 302 cs->writeisacfifo = &WriteISACfifo; 303 cs->BC_Read_Reg = &ReadHSCX; 304 cs->BC_Write_Reg = &WriteHSCX; 305 cs->BC_Send_Data = &hscx_fill_fifo; 306 cs->cardmsg = &ix1_card_msg; 307 cs->irq_func = &ix1micro_interrupt; 308 ISACVersion(cs, "ix1-Micro:"); 309 if (HscxVersion(cs, "ix1-Micro:")) { 310 printk(KERN_WARNING 311 "ix1-Micro: wrong HSCX versions check IO address\n"); 312 release_io_ix1micro(cs); 313 return (0); 314 } 315 return (1); 316} 317