1/* $Id: ix1_micro.c,v 1.1.1.1 2008/10/15 03:26:33 james26_jang 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#define __NO_VERSION__ 21#include <linux/init.h> 22#include <linux/isapnp.h> 23#include "hisax.h" 24#include "isac.h" 25#include "hscx.h" 26#include "isdnl1.h" 27 28extern const char *CardType[]; 29const char *ix1_revision = "$Revision: 1.1.1.1 $"; 30 31#define byteout(addr,val) outb(val,addr) 32#define bytein(addr) inb(addr) 33 34#define SPECIAL_PORT_OFFSET 3 35 36#define ISAC_COMMAND_OFFSET 2 37#define ISAC_DATA_OFFSET 0 38#define HSCX_COMMAND_OFFSET 2 39#define HSCX_DATA_OFFSET 1 40 41#define TIMEOUT 50 42 43static inline u_char 44readreg(unsigned int ale, unsigned int adr, u_char off) 45{ 46 register u_char ret; 47 long flags; 48 49 save_flags(flags); 50 cli(); 51 byteout(ale, off); 52 ret = bytein(adr); 53 restore_flags(flags); 54 return (ret); 55} 56 57static inline void 58readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 59{ 60 /* fifo read without cli because it's allready done */ 61 62 byteout(ale, off); 63 insb(adr, data, size); 64} 65 66 67static inline void 68writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) 69{ 70 long flags; 71 72 save_flags(flags); 73 cli(); 74 byteout(ale, off); 75 byteout(adr, data); 76 restore_flags(flags); 77} 78 79static inline void 80writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size) 81{ 82 /* fifo write without cli because it's allready done */ 83 byteout(ale, off); 84 outsb(adr, data, size); 85} 86 87/* Interface functions */ 88 89static u_char 90ReadISAC(struct IsdnCardState *cs, u_char offset) 91{ 92 return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); 93} 94 95static void 96WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) 97{ 98 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); 99} 100 101static void 102ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size) 103{ 104 readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); 105} 106 107static void 108WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size) 109{ 110 writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); 111} 112 113static u_char 114ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) 115{ 116 return (readreg(cs->hw.ix1.hscx_ale, 117 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); 118} 119 120static void 121WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) 122{ 123 writereg(cs->hw.ix1.hscx_ale, 124 cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); 125} 126 127#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ 128 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) 129#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ 130 cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) 131 132#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ 133 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) 134 135#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ 136 cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) 137 138#include "hscx_irq.c" 139 140static void 141ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs) 142{ 143 struct IsdnCardState *cs = dev_id; 144 u_char val; 145 146 if (!cs) { 147 printk(KERN_WARNING "IX1: Spurious interrupt!\n"); 148 return; 149 } 150 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); 151 Start_HSCX: 152 if (val) 153 hscx_int_main(cs, val); 154 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); 155 Start_ISAC: 156 if (val) 157 isac_interrupt(cs, val); 158 val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); 159 if (val) { 160 if (cs->debug & L1_DEB_HSCX) 161 debugl1(cs, "HSCX IntStat after IntRoutine"); 162 goto Start_HSCX; 163 } 164 val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); 165 if (val) { 166 if (cs->debug & L1_DEB_ISAC) 167 debugl1(cs, "ISAC IntStat after IntRoutine"); 168 goto Start_ISAC; 169 } 170 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); 171 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); 172 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); 173 writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); 174 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); 175 writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); 176} 177 178void 179release_io_ix1micro(struct IsdnCardState *cs) 180{ 181 if (cs->hw.ix1.cfg_reg) 182 release_region(cs->hw.ix1.cfg_reg, 4); 183} 184 185static void 186ix1_reset(struct IsdnCardState *cs) 187{ 188 long flags; 189 int cnt; 190 191 /* reset isac */ 192 save_flags(flags); 193 cnt = 3 * (HZ / 10) + 1; 194 sti(); 195 while (cnt--) { 196 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1); 197 HZDELAY(1); /* wait >=10 ms */ 198 } 199 byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); 200 restore_flags(flags); 201} 202 203static int 204ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) 205{ 206 switch (mt) { 207 case CARD_RESET: 208 ix1_reset(cs); 209 return(0); 210 case CARD_RELEASE: 211 release_io_ix1micro(cs); 212 return(0); 213 case CARD_INIT: 214 inithscxisac(cs, 3); 215 return(0); 216 case CARD_TEST: 217 return(0); 218 } 219 return(0); 220} 221 222#ifdef __ISAPNP__ 223static struct isapnp_device_id itk_ids[] __initdata = { 224 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 225 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 226 (unsigned long) "ITK micro 2" }, 227 { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 228 ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 229 (unsigned long) "ITK micro 2." }, 230 { 0, } 231}; 232 233static struct isapnp_device_id *idev = &itk_ids[0]; 234static struct pci_bus *pnp_c __devinitdata = NULL; 235#endif 236 237 238int __init 239setup_ix1micro(struct IsdnCard *card) 240{ 241 struct IsdnCardState *cs = card->cs; 242 char tmp[64]; 243 244 strcpy(tmp, ix1_revision); 245 printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); 246 if (cs->typ != ISDN_CTYPE_IX1MICROR2) 247 return (0); 248 249#ifdef __ISAPNP__ 250 if (!card->para[1] && isapnp_present()) { 251 struct pci_bus *pb; 252 struct pci_dev *pd; 253 254 while(idev->card_vendor) { 255 if ((pb = isapnp_find_card(idev->card_vendor, 256 idev->card_device, pnp_c))) { 257 pnp_c = pb; 258 pd = NULL; 259 if ((pd = isapnp_find_dev(pnp_c, 260 idev->vendor, idev->function, pd))) { 261 printk(KERN_INFO "HiSax: %s detected\n", 262 (char *)idev->driver_data); 263 pd->prepare(pd); 264 pd->deactivate(pd); 265 pd->activate(pd); 266 card->para[1] = pd->resource[0].start; 267 card->para[0] = pd->irq_resource[0].start; 268 if (!card->para[0] || !card->para[1]) { 269 printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", 270 card->para[0], card->para[1]); 271 pd->deactivate(pd); 272 return(0); 273 } 274 break; 275 } else { 276 printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); 277 } 278 } 279 idev++; 280 pnp_c=NULL; 281 } 282 if (!idev->card_vendor) { 283 printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); 284 return(0); 285 } 286 } 287#endif 288 /* IO-Ports */ 289 cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; 290 cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; 291 cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; 292 cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; 293 cs->hw.ix1.cfg_reg = card->para[1]; 294 cs->irq = card->para[0]; 295 if (cs->hw.ix1.cfg_reg) { 296 if (check_region((cs->hw.ix1.cfg_reg), 4)) { 297 printk(KERN_WARNING 298 "HiSax: %s config port %x-%x already in use\n", 299 CardType[card->typ], 300 cs->hw.ix1.cfg_reg, 301 cs->hw.ix1.cfg_reg + 4); 302 return (0); 303 } else 304 request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg"); 305 } 306 printk(KERN_INFO 307 "HiSax: %s config irq:%d io:0x%X\n", 308 CardType[cs->typ], cs->irq, 309 cs->hw.ix1.cfg_reg); 310 ix1_reset(cs); 311 cs->readisac = &ReadISAC; 312 cs->writeisac = &WriteISAC; 313 cs->readisacfifo = &ReadISACfifo; 314 cs->writeisacfifo = &WriteISACfifo; 315 cs->BC_Read_Reg = &ReadHSCX; 316 cs->BC_Write_Reg = &WriteHSCX; 317 cs->BC_Send_Data = &hscx_fill_fifo; 318 cs->cardmsg = &ix1_card_msg; 319 cs->irq_func = &ix1micro_interrupt; 320 ISACVersion(cs, "ix1-Micro:"); 321 if (HscxVersion(cs, "ix1-Micro:")) { 322 printk(KERN_WARNING 323 "ix1-Micro: wrong HSCX versions check IO address\n"); 324 release_io_ix1micro(cs); 325 return (0); 326 } 327 return (1); 328} 329