?? ul_c510.c
字號:
/******************************************************************* uLan Communication - uL_DRV - multiplatform uLan driver ul_c510.c - chip driver for Intel 82C510 (C) Copyright 1996-2004 by Pavel Pisa - project originator http://cmp.felk.cvut.cz/~pisa (C) Copyright 1996-2004 PiKRON Ltd. http://www.pikron.com (C) Copyright 2002-2004 Petr Smolik The uLan driver project can be used and distributed in compliance with any of next licenses - GPL - GNU Public License See file COPYING for details. - LGPL - Lesser GNU Public License - MPL - Mozilla Public License - and other licenses added by project originator Code can be modified and re-distributed under any combination of the above listed licenses. If contributor does not agree with some of the licenses, he/she can delete appropriate line. WARNING: if you delete all lines, you are not allowed to distribute code or sources in any form. *******************************************************************//*******************************************************************//* Chip driver for 82510 */#if 1 /* this enables use of shadow 82510 bank switch */ /* be !!! carefull !!!, use U510_SBANK_FINI at begin of every */ /* function containing u510_outb, u510_inb */ /* such function must not call another such function */ #define _U510_SBANK_SHADOW_VAR sbank_sv #define U510_SBANK_FINI int sbank_sv=-1;#else #define U510_SBANK_FINI#endif#include "ul_82510.h"/*** Test interrupt request state ***/int u510_pool(ul_drv *udrv){ return u510_pool_gir(udrv->port);};/*** Receive character into char_buff ***/int u510_recch(ul_drv *udrv, int ret_code){ U510_SBANK_FINI uchar uc; udrv->char_buff=0; if(u510_inb(udrv->port,U510_MCR)&U510_MCR_OEQ) { /* direction switch necessary */ if(!(u510_inb(udrv->port,U510_GSR)&U510_GER_TM)) { /* wait to end of previous transfer */ u510_outb(udrv->port,U510_GER, U510_GER_TM); return UL_RC_WIRQ; } u510_outb(udrv->port,U510_MCR, U510_MCR_IE); u510_outb(udrv->port,U510_RCM, U510_RCM_FLUSH); }; u510_outb(udrv->port,U510_GER,U510_GER_RI); uc=u510_inb(udrv->port,U510_RST); if(!(uc&0x01)) return UL_RC_WIRQ; uc=u510_inb(udrv->port,U510_RXF); udrv->char_buff=u510_inb(udrv->port,U510_RXD); if(uc&0x08) { /* store last ctrl for connect line busy/ready */ udrv->char_buff|=0x100; /* controll char */ udrv->last_ctrl=udrv->char_buff; } else udrv->last_ctrl&=0x7F; udrv->xor_sum^=udrv->char_buff;udrv->xor_sum++; UL_FRET; if(uc&0x02) { LOG_CHIO(" ER:%03X",udrv->char_buff); return UL_RC_EFRAME; /* frame error */ }; LOG_CHIO(" R:%03X",udrv->char_buff); return UL_RC_PROC;};/*-- Helper functions for sndchar --*/int u510_sndch(ul_drv *udrv, int ret_code);int u510_sndch_w2(ul_drv *udrv, int ret_code){ U510_SBANK_FINI u510_outb(udrv->port,U510_MCR, U510_MCR_OE); UL_FNEXT(u510_sndch); return UL_RC_PROC;}int u510_sndch_w1(ul_drv *udrv, int ret_code){ U510_SBANK_FINI unsigned u; u=udrv->baud_div*11*16; u510_outb(udrv->port,U510_TMCR,0); u510_inb(udrv->port,U510_TMST); u510_outb(udrv->port,U510_GER,U510_GER_TIE); u510_outb(udrv->port,U510_LCR,U510_LCR_C|U510_LCR_DLAB); u510_outb(udrv->port,U510_BBL,(uchar)u); u510_outb(udrv->port,U510_BBH,(uchar)(u>>8)); u510_outb(udrv->port,U510_LCR,U510_LCR_C); u510_outb(udrv->port,U510_TMIE,2); u510_outb(udrv->port,U510_TMCR,0x22); UL_FNEXT(u510_sndch_w2); return UL_RC_WIRQ;}/*** Send character from char_buff ***/int u510_sndch(ul_drv *udrv, int ret_code){ U510_SBANK_FINI if(!(u510_inb(udrv->port,U510_MCR)&U510_MCR_OEQ)) { /* direction switch necessary */ UL_FNEXT(u510_sndch_w1); if(!(u510_inb(udrv->port,U510_GSR)&U510_GER_TM)) { /* wait to end of previous transfer */ u510_outb(udrv->port,U510_GER, U510_GER_TM); return UL_RC_WIRQ; } return UL_RC_PROC; }; u510_outb(udrv->port,U510_GER,U510_GER_TI); if(!(u510_inb(udrv->port,U510_LSR)&U510_LSR_TRE)) return UL_RC_WIRQ; if(udrv->char_buff&0x100) { /* store last ctrl for connect line busy/ready */ udrv->last_ctrl=udrv->char_buff; u510_outb(udrv->port,U510_TXF, 0x80); /* controll char */ } else u510_outb(udrv->port,U510_TXF, 0x00); /* regular char */; u510_outb(udrv->port,U510_TXD,(uchar)udrv->char_buff); /* char code */ udrv->xor_sum^=udrv->char_buff;udrv->xor_sum++; LOG_CHIO(" T:%03X",udrv->char_buff); UL_FRET; return UL_RC_PROC;};/*-- Helper functions for wait --*/int u510_wait(ul_drv *udrv, int ret_code);int u510_wait_1(ul_drv *udrv, int ret_code){ U510_SBANK_FINI if(u510_inb(udrv->port,U510_RST)&1) { UL_FNEXT(u510_recch); return UL_RC_PROC; }; if(!udrv->wait_time--) { LOG_CHIO(" Timeout!"); UL_FRET; return UL_RC_ETIMEOUT; }; u510_outb(udrv->port,U510_TMCR,0); u510_inb(udrv->port,U510_TMST); u510_outb(udrv->port,U510_LCR,U510_LCR_C|U510_LCR_DLAB); u510_outb(udrv->port,U510_BBL,0xFF); u510_outb(udrv->port,U510_BBH,0xFF); u510_outb(udrv->port,U510_LCR,U510_LCR_C); u510_outb(udrv->port,U510_TMIE,2); u510_outb(udrv->port,U510_TMCR,0x22); return UL_RC_WIRQ;};/*** Wait for time or received character ***/int u510_wait(ul_drv *udrv, int ret_code){ U510_SBANK_FINI unsigned u; udrv->char_buff=0; if(!(u510_inb(udrv->port,U510_GSR)&U510_GER_TM)) { /* wait to end of previous transfer */ u510_outb(udrv->port,U510_GER, U510_GER_TM); return UL_RC_WIRQ; }; if(u510_inb(udrv->port,U510_MCR)&U510_MCR_OEQ) { /* direction switch necessary */ u510_outb(udrv->port,U510_MCR, U510_MCR_IE); u510_outb(udrv->port,U510_RCM, U510_RCM_FLUSH); }; UL_FNEXT(u510_wait_1); u=udrv->wait_time*11*16*udrv->baud_div; udrv->wait_time=u>>16; u510_outb(udrv->port,U510_TMCR,0); u510_inb(udrv->port,U510_TMST); u510_outb(udrv->port,U510_GER,U510_GER_TIE+U510_GER_RI); if((u&0xFFFF)<=2) return UL_RC_PROC; u510_outb(udrv->port,U510_LCR,U510_LCR_C|U510_LCR_DLAB); u510_outb(udrv->port,U510_BBL,(uchar)u); u510_outb(udrv->port,U510_BBH,(uchar)(u>>8)); u510_outb(udrv->port,U510_LCR,U510_LCR_C); u510_outb(udrv->port,U510_TMIE,2); u510_outb(udrv->port,U510_TMCR,0x22); return UL_RC_WIRQ;};/*-- Helper functions for connect --*/int u510_connect_1(ul_drv *udrv, int ret_code);int u510_connect_2(ul_drv *udrv, int ret_code){ U510_SBANK_FINI u510_inb(udrv->port,U510_GSR); u510_outb(udrv->port,U510_LCR,U510_LCR_C); u510_outb(udrv->port,U510_MCR,U510_MCR_IE); u510_outb(udrv->port,U510_RCM, U510_RCM_FLUSH); u510_inb(udrv->port,U510_RST); if(udrv->chip_temp==1) {LOG_CHIO(" Connected"); UL_FRET; }else{ udrv->wait_time=(udrv->chip_temp&3)+1; udrv->chip_temp>>=2; UL_FCALL2(*udrv->fnc_wait,u510_connect_1); }; return UL_RC_PROC;};int u510_connect_1(ul_drv *udrv, int ret_code){ U510_SBANK_FINI if(ret_code!=UL_RC_ETIMEOUT) { UL_FRET; return UL_RC_EARBIT;}; if((u510_inb(udrv->port,U510_MSR)&U510_MSR_RxD)|| (u510_inb(udrv->port,U510_RST)&1)) { UL_FRET; LOG_CHIO(" EARBIT!"); return UL_RC_EARBIT; }; u510_outb(udrv->port,U510_LCR,U510_LCR_C|U510_LCR_B); u510_outb(udrv->port,U510_MCR,U510_MCR_OE); UL_FNEXT(u510_connect_2); /* wait to end of transfer */ u510_inb(udrv->port,U510_GSR); u510_outb(udrv->port,U510_GER, U510_GER_TM); u510_outb(udrv->port,U510_TXF, 0x00); u510_outb(udrv->port,U510_TXD, 0x00); return UL_RC_WIRQ;};/*** Connect to RS485 bus ***/int u510_connect(ul_drv *udrv, int ret_code){ unsigned u; u=udrv->last_ctrl; udrv->wait_time=((udrv->my_adr-u-1)&0xF)+4; if(((u&0x180)!=0x180)|| (u==0x1FF)) udrv->wait_time+=0x10; udrv->last_ctrl=0; udrv->char_buff=0; udrv->chip_temp=(udrv->my_adr&0x3F)|0x40; UL_FCALL2(*udrv->fnc_wait,u510_connect_1); return UL_RC_PROC;};/* UL_FNEXT(u510_recch); UL_FCALL(u510_recch); UL_FCALL2(u510_recch,u510_recch); UL_FRET;*/static char *u510_port_name="ulan_u510";/*** 82510 initialize ports ***/int u510_pinit(ul_drv *udrv){ U510_SBANK_FINI unsigned u; int baud=udrv->baud_val; if (UL_REQ_IOS(udrv->port,8,u510_port_name)<0) { LOG_FATAL(KERN_CRIT "uLan u510_pinit : cannot reguest ports !\n"); return UL_RC_EPORT; }; for(u=0;u<0x80;u+=0x20) { ul_outb(udrv->port+U510_GIR,u); if((ul_inb(udrv->port+U510_GIR)^u)&0x60) { ul_outb(udrv->port+U510_GIR,0); UL_REL_IOS(udrv->port,8); return UL_RC_EPORT; }; }; if (!baud) baud=19200; u=(udrv->baud_base+baud/2)/baud; if (u>0xFFFF) u=0xFFFF; udrv->baud_div=u; u510_outb(udrv->port,U510_ICM, 0x10); u510_outb(udrv->port,U510_GER, 0); u510_outb(udrv->port,U510_LCR, U510_LCR_C); u510_outb(udrv->port,U510_IMD, 0xB); u510_outb(udrv->port,U510_TMD, 0); /* 0x18 -> RTS */ u510_outb(udrv->port,U510_FMD, 0); u510_outb(udrv->port,U510_RMD, 0x40); /* Addresss opens RxFIFO */ u510_outb(udrv->port,U510_CLCF,0x50); /* RxC a TxC are 16x from BRGA */ u510_outb(udrv->port,U510_BACF,0x04); /* Baud gen system clock */ u510_outb(udrv->port,U510_BBCF,0x00); /* Timer system clock */ u510_outb(udrv->port,U510_PMD, 0x7C); /* Configure pins */ u510_outb(udrv->port,U510_LCR, U510_LCR_C|U510_LCR_DLAB); u510_outb(udrv->port,U510_BAL, (uchar)udrv->baud_div); u510_outb(udrv->port,U510_BAH, (uchar)(udrv->baud_div>>8)); u510_outb(udrv->port,U510_LCR, U510_LCR_C); u510_outb(udrv->port,U510_LCR, U510_LCR_C|U510_LCR_C); u510_outb(udrv->port,U510_LCR, U510_LCR_C); u510_outb(udrv->port,U510_GER, U510_GER_MI); return UL_RC_PROC;};/*** 82510 deinitialize ports ***/int u510_pdone(ul_drv *udrv){ U510_SBANK_FINI u510_outb(udrv->port,U510_GER, 0); /* disable interrupts */ u510_outb(udrv->port,U510_MCR, U510_MCR_IE); /* transmitter off */ u510_outb(udrv->port,U510_GIR, U510_GIR_NO_INT); /* flush irq */ UL_REL_IOS(udrv->port,8); return UL_RC_PROC;};/*** 82510 generate irq for irq_probe */int u510_genirq(ul_drv *udrv,int param){ U510_SBANK_FINI if(param) { u510_outb(udrv->port,U510_MCR, U510_MCR_IE); /* transmitter off */ u510_outb(udrv->port,U510_GER, U510_GER_TI); /* enable interrupts */ u510_outb(udrv->port,U510_TXD, 0xFF); /* trig TxFIFO int */ }else{ u510_outb(udrv->port,U510_GER, 0); /* disable interrupts */ u510_outb(udrv->port,U510_MCR, U510_MCR_IE); /* transmitter off */ u510_outb(udrv->port,U510_GIR, U510_GIR_NO_INT); /* flush irq */ }; return UL_RC_PROC;};/* support for hardware tests */int u510_hwtest(ul_drv *udrv,int param){ unsigned u; U510_SBANK_FINI switch(param) { case 0x10: case 0x11: u510_outb(udrv->port,U510_GER, 0); /* disable interrupts */ u510_outb(udrv->port,U510_MCR, U510_MCR_OE); /* transmitter on */ u510_outb(udrv->port,U510_LCR, param&1? U510_LCR_C:U510_LCR_B); /* set TD lines */ case 0x12: u=u510_inb(udrv->port,U510_MSR); return u510_inb(udrv->port,U510_LSR)|(u<<8)| (u&U510_MSR_TxD?0:0x100000)| (u&U510_MSR_RxD?0:0x10000); case 0x13: u510_outb(udrv->port,U510_MCR, U510_MCR_IE); /* transmitter off */ u=u510_inb(udrv->port,U510_MSR); return u510_inb(udrv->port,U510_LSR)|(u<<8)| (u&U510_MSR_TxD?0:0x100000)| (u&U510_MSR_RxD?0:0x10000); } return UL_RC_ENOFNC;};/*** Control functions of chip driver ***/int u510_cctrl(ul_drv *udrv, int ctrl_fnc, int param){ U510_SBANK_FINI switch (ctrl_fnc) { case UL_CC_DIN: /* switch off line transmitter */ { u510_outb(udrv->port,U510_MCR, U510_MCR_IE); return UL_RC_PROC; }; case UL_CC_DOUT: /* switch on line transmitter */ { u510_outb(udrv->port,U510_MCR, U510_MCR_OE); return UL_RC_PROC; }; case UL_CC_PINIT: /* initialize ports (parameter baud)*/ { return u510_pinit(udrv); }; case UL_CC_PDONE: /* deinitialize ports */ { return u510_pdone(udrv); }; case UL_CC_GENIRQ: /* generate irq for irq_probe */ {return u510_genirq(udrv,param); }; case UL_CC_HWTEST: /* support for hardware testing */ {return u510_hwtest(udrv,param); }; }; return UL_RC_ENOFNC;};/*** 82510 chip driver initialize ***/int u510_init(ul_drv *udrv, int port, int irq, int baud, long baudbase, int options){ unsigned u; if (UL_REQ_IOS(port,8,u510_port_name)<0) { LOG_FATAL(KERN_CRIT "uLan u510_init : cannot reguest ports !\n"); return UL_RC_EPORT; }; for(u=0;u<0x80;u+=0x20) { ul_outb(port+U510_GIR,u); if((ul_inb(port+U510_GIR)^u)&0x60) { ul_outb(port+U510_GIR,0); UL_REL_IOS(port,8); return UL_RC_EPORT; }; }; udrv->chip_options=options; if(!baudbase) baudbase=0x8CA00; udrv->baud_base=baudbase; if(!baud) baud=19200; udrv->baud_val=baud; u=(udrv->baud_base+baud/2)/baud; if (u>0xFFFF) u=0xFFFF; udrv->baud_div=u; udrv->port=port; udrv->irq=irq; udrv->fnc_recch=&u510_recch; udrv->fnc_sndch=&u510_sndch; udrv->fnc_wait=&u510_wait; udrv->fnc_pool=&u510_pool; udrv->fnc_connect=&u510_connect; udrv->fnc_cctrl=&u510_cctrl; UL_REL_IOS(port,8); return 0;};
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -