1/* $Id: hfcscard.c,v 1.1.1.1 2007/08/03 18:52:35 Exp $ 2 * 3 * low level stuff for hfcs based cards (Teles3c, ACER P10) 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 */ 12 13#include <linux/init.h> 14#include <linux/isapnp.h> 15#include "hisax.h" 16#include "hfc_2bds0.h" 17#include "isdnl1.h" 18 19extern const char *CardType[]; 20 21static const char *hfcs_revision = "$Revision: 1.1.1.1 $"; 22 23static irqreturn_t 24hfcs_interrupt(int intno, void *dev_id) 25{ 26 struct IsdnCardState *cs = dev_id; 27 u_char val, stat; 28 u_long flags; 29 30 spin_lock_irqsave(&cs->lock, flags); 31 if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & 32 (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { 33 val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); 34 if (cs->debug & L1_DEB_ISAC) 35 debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); 36 hfc2bds0_interrupt(cs, val); 37 } else { 38 if (cs->debug & L1_DEB_ISAC) 39 debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); 40 } 41 spin_unlock_irqrestore(&cs->lock, flags); 42 return IRQ_HANDLED; 43} 44 45static void 46hfcs_Timer(struct IsdnCardState *cs) 47{ 48 cs->hw.hfcD.timer.expires = jiffies + 75; 49 /* WD RESET */ 50/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); 51 add_timer(&cs->hw.hfcD.timer); 52*/ 53} 54 55static void 56release_io_hfcs(struct IsdnCardState *cs) 57{ 58 release2bds0(cs); 59 del_timer(&cs->hw.hfcD.timer); 60 if (cs->hw.hfcD.addr) 61 release_region(cs->hw.hfcD.addr, 2); 62} 63 64static void 65reset_hfcs(struct IsdnCardState *cs) 66{ 67 printk(KERN_INFO "HFCS: resetting card\n"); 68 cs->hw.hfcD.cirm = HFCD_RESET; 69 if (cs->typ == ISDN_CTYPE_TELES3C) 70 cs->hw.hfcD.cirm |= HFCD_MEM8K; 71 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ 72 mdelay(10); 73 cs->hw.hfcD.cirm = 0; 74 if (cs->typ == ISDN_CTYPE_TELES3C) 75 cs->hw.hfcD.cirm |= HFCD_MEM8K; 76 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ 77 mdelay(10); 78 if (cs->typ == ISDN_CTYPE_TELES3C) 79 cs->hw.hfcD.cirm |= HFCD_INTB; 80 else if (cs->typ == ISDN_CTYPE_ACERP10) 81 cs->hw.hfcD.cirm |= HFCD_INTA; 82 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); 83 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); 84 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ 85 cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; 86 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 87 cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; 88 cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | 89 HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | 90 HFCD_INTS_DREC | HFCD_INTS_L1STATE; 91 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); 92 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); 93 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ 94 udelay(10); 95 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ 96 cs->hw.hfcD.mst_m = HFCD_MASTER; 97 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ 98 cs->hw.hfcD.sctrl = 0; 99 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); 100} 101 102static int 103hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) 104{ 105 u_long flags; 106 int delay; 107 108 if (cs->debug & L1_DEB_ISAC) 109 debugl1(cs, "HFCS: card_msg %x", mt); 110 switch (mt) { 111 case CARD_RESET: 112 spin_lock_irqsave(&cs->lock, flags); 113 reset_hfcs(cs); 114 spin_unlock_irqrestore(&cs->lock, flags); 115 return(0); 116 case CARD_RELEASE: 117 release_io_hfcs(cs); 118 return(0); 119 case CARD_INIT: 120 delay = (75*HZ)/100 +1; 121 cs->hw.hfcD.timer.expires = jiffies + delay; 122 add_timer(&cs->hw.hfcD.timer); 123 spin_lock_irqsave(&cs->lock, flags); 124 reset_hfcs(cs); 125 init2bds0(cs); 126 spin_unlock_irqrestore(&cs->lock, flags); 127 delay = (80*HZ)/1000 +1; 128 msleep(80); 129 spin_lock_irqsave(&cs->lock, flags); 130 cs->hw.hfcD.ctmt |= HFCD_TIM800; 131 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 132 cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); 133 spin_unlock_irqrestore(&cs->lock, flags); 134 return(0); 135 case CARD_TEST: 136 return(0); 137 } 138 return(0); 139} 140 141#ifdef __ISAPNP__ 142static struct isapnp_device_id hfc_ids[] __devinitdata = { 143 { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 144 ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 145 (unsigned long) "Acer P10" }, 146 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 147 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 148 (unsigned long) "Billion 2" }, 149 { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 150 ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 151 (unsigned long) "Billion 1" }, 152 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 153 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 154 (unsigned long) "IStar PnP" }, 155 { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 156 ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 157 (unsigned long) "Teles 16.3c" }, 158 { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 159 ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 160 (unsigned long) "Tornado Tipa C" }, 161 { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 162 ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 163 (unsigned long) "Genius Speed Surfer" }, 164 { 0, } 165}; 166 167static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0]; 168static struct pnp_card *pnp_c __devinitdata = NULL; 169#endif 170 171int __devinit 172setup_hfcs(struct IsdnCard *card) 173{ 174 struct IsdnCardState *cs = card->cs; 175 char tmp[64]; 176 177 strcpy(tmp, hfcs_revision); 178 printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); 179 180#ifdef __ISAPNP__ 181 if (!card->para[1] && isapnp_present()) { 182 struct pnp_dev *pnp_d; 183 while(ipid->card_vendor) { 184 if ((pnp_c = pnp_find_card(ipid->card_vendor, 185 ipid->card_device, pnp_c))) { 186 pnp_d = NULL; 187 if ((pnp_d = pnp_find_dev(pnp_c, 188 ipid->vendor, ipid->function, pnp_d))) { 189 int err; 190 191 printk(KERN_INFO "HiSax: %s detected\n", 192 (char *)ipid->driver_data); 193 pnp_disable_dev(pnp_d); 194 err = pnp_activate_dev(pnp_d); 195 if (err<0) { 196 printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", 197 __FUNCTION__, err); 198 return(0); 199 } 200 card->para[1] = pnp_port_start(pnp_d, 0); 201 card->para[0] = pnp_irq(pnp_d, 0); 202 if (!card->para[0] || !card->para[1]) { 203 printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", 204 card->para[0], card->para[1]); 205 pnp_disable_dev(pnp_d); 206 return(0); 207 } 208 break; 209 } else { 210 printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); 211 } 212 } 213 ipid++; 214 pnp_c = NULL; 215 } 216 if (!ipid->card_vendor) { 217 printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); 218 return(0); 219 } 220 } 221#endif 222 cs->hw.hfcD.addr = card->para[1] & 0xfffe; 223 cs->irq = card->para[0]; 224 cs->hw.hfcD.cip = 0; 225 cs->hw.hfcD.int_s1 = 0; 226 cs->hw.hfcD.send = NULL; 227 cs->bcs[0].hw.hfc.send = NULL; 228 cs->bcs[1].hw.hfc.send = NULL; 229 cs->hw.hfcD.dfifosize = 512; 230 cs->dc.hfcd.ph_state = 0; 231 cs->hw.hfcD.fifo = 255; 232 if (cs->typ == ISDN_CTYPE_TELES3C) { 233 cs->hw.hfcD.bfifosize = 1024 + 512; 234 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 235 cs->hw.hfcD.bfifosize = 7*1024 + 512; 236 } else 237 return (0); 238 if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { 239 printk(KERN_WARNING 240 "HiSax: %s config port %x-%x already in use\n", 241 CardType[card->typ], 242 cs->hw.hfcD.addr, 243 cs->hw.hfcD.addr + 2); 244 return (0); 245 } 246 printk(KERN_INFO 247 "HFCS: defined at 0x%x IRQ %d HZ %d\n", 248 cs->hw.hfcD.addr, 249 cs->irq, HZ); 250 if (cs->typ == ISDN_CTYPE_TELES3C) { 251 /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ 252 outb(0x00, cs->hw.hfcD.addr); 253 outb(0x56, cs->hw.hfcD.addr | 1); 254 } else if (cs->typ == ISDN_CTYPE_ACERP10) { 255 /* Acer P10 IO ADR is 0x300 */ 256 outb(0x00, cs->hw.hfcD.addr); 257 outb(0x57, cs->hw.hfcD.addr | 1); 258 } 259 set_cs_func(cs); 260 cs->hw.hfcD.timer.function = (void *) hfcs_Timer; 261 cs->hw.hfcD.timer.data = (long) cs; 262 init_timer(&cs->hw.hfcD.timer); 263 cs->cardmsg = &hfcs_card_msg; 264 cs->irq_func = &hfcs_interrupt; 265 return (1); 266} 267