⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lx_acb.c

📁 liunx 5536 accessBus
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/kernel.h>#include <linux/module.h>#include <linux/config.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/i2c.h>#include <linux/smp_lock.h>#include <linux/pci.h>#include <asm/io.h>#include "build_num.h"MODULE_AUTHOR("William Morrow (william.morrow@amd.com)");MODULE_DESCRIPTION("AMD LX ACCESS.bus Driver");MODULE_LICENSE("GPL");#define NAME "lx_acb"#define LENGTH(n) (sizeof(n)/sizeof(n[0]))#define ACBSDA  (dev->io+0)#define ACBST   (dev->io+1)#define    ACBST_SDAST          0x40 /* SDA Status */#define    ACBST_BER            0x20 #define    ACBST_NEGACK         0x10 /* Negative Acknowledge */#define    ACBST_STASTR         0x08 /* Stall After Start */#define    ACBST_MASTER         0x02#define    ACBST_XMIT           0x01#define ACBCST  (dev->io+2)#define    ACBCST_BB            0x02#define    ACBCST_TSDA          0x10#define    ACBCST_TGSCL         0x20#define ACBCTL1 (dev->io+3)#define    ACBCTL1_STASTRE      0x80#define    ACBCTL1_NMINTE       0x40#define    ACBCTL1_ACK          0x10#define    ACBCTL1_INTEN        0x04#define    ACBCTL1_STOP         0x02#define    ACBCTL1_START        0x01#define ACBADDR (dev->io+4)#define ACBCTL2 (dev->io+5)#define    ACBCTL2_CLK          0x70#define    ACBCTL2_ENABLE       0x01#define MAX_DEVICES 4static int debug = 0;MODULE_PARM(debug,"i");#define DEBUG(n,s...) do { if( debug >= (n) ) printk(KERN_INFO NAME ":" s); } while(0)#define POLLED_MODE 1#define POLL_TIMEOUT (HZ)enum amd_acb_state {        state_idle,        state_address,        state_read,        state_write,        state_next,        state_stop,        state_error,};#define STATE_ACTIVE ((1<<state_address)|(1<<state_read)|(1<<state_write)|(1<<state_stop))struct acb_dev {   unsigned long io;   int index;   int retries;   struct semaphore sem;   struct i2c_algorithm algo;   struct i2c_adapter adp;   enum amd_acb_state state;   unsigned short flags;   unsigned char addr;   unsigned char last;   int count;   int msgn;   int result;   int len;   unsigned char *bp;};struct amd_acb_driver {   struct pci_dev *pci;   spinlock_t lock;   int model;   int n_dev;   struct acb_dev dev[MAX_DEVICES];} *s;static unsigned charinz(unsigned short p){   unsigned char ch = inb(p);   udelay(5);   return ch;}static voidoutz(unsigned char ch,unsigned short p){   outb(ch,p);   udelay(5);}static voidacb_dump(struct acb_dev *dev){   DEBUG(3,"ACB%d DUMP ST=%02x CST=%02x CTL1=%02x CTL2=%02x\n",      dev->index, inz(ACBST), inz(ACBCST), inz(ACBCTL1), inz(ACBCTL2));}static voidacb_start(struct acb_dev *dev){   DEBUG(3,"ACB%d START\n",dev->index);   outz( (inz(ACBCTL1) | ACBCTL1_START), ACBCTL1 );}static voidacb_stop(struct acb_dev *dev){   DEBUG(3,"ACB%d STOP\n",dev->index);   outz( (inz(ACBCTL1) | ACBCTL1_STOP), ACBCTL1 );}static voidacb_snak(struct acb_dev *dev){   DEBUG(3,"ACB%d SNAK\n",dev->index);   outz( inz(ACBCTL1) | ACBCTL1_ACK, ACBCTL1 );}static voidacb_bbusy(struct acb_dev *dev){   int retries = 100;   while( (inz(ACBCST)&ACBCST_BB) != 0 && --retries >= 0 ) {      if( (inz(ACBST) & ACBST_MASTER) != 0 )         outz( ACBCTL1_STOP, ACBCTL1 );      else if( (inz(ACBCST) & (ACBCST_TSDA|ACBCST_TGSCL)) == 0 )         outz( ACBCST_TGSCL, ACBCST );      udelay(1000);   }   if( retries < 0 ) {      DEBUG(0,"ACB%d BUS BUSY\n",dev->index);      acb_dump(dev);   }}static voidacb_reenable(struct acb_dev *dev){   DEBUG(3,"ACB%d REENABLE\n",dev->index);   outz( (ACBCTL2_CLK & ~ACBCTL2_ENABLE), ACBCTL2 );   // Configure no interrupt mode (polling) and   // Disable global call address   outz( 0x00, ACBCTL1 );   // Disable slave address   outz( 0x00, ACBADDR );   // Enable the ACCESS.bus device   outz( inz(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);}static voidacb_reset(struct acb_dev *dev){   DEBUG(3,"ACB%d RESET\n",dev->index);   // Clear NEGACK, STASTR and BER bits   outz( ACBST_BER|ACBST_NEGACK|ACBST_STASTR, ACBST );   outz( 0, ACBST ); // Status Reg bug workaround   // Clear BB (BUS BUSY) bit   acb_bbusy(dev);   // toggle enable ACB   acb_reenable(dev);}static intacb_probe(struct acb_dev *dev){   DEBUG(0,"%s\n",AMD_VERSION);   DEBUG(3,"ACB%d PROBE\n",dev->index);   acb_reset(dev);   //probe with reset   outz( (ACBCTL2_CLK & ~ACBCTL2_ENABLE), ACBCTL2 );   if( inz(ACBCTL2) != (ACBCTL2_CLK & ~ACBCTL2_ENABLE)) {       DEBUG(2,"ACB%d readback failed\n",dev->index);       return -ENXIO;   }   outz( 0x00, ACBCTL1 );   outz( 0x00, ACBADDR );   outz( inz(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2 );   if( inz(ACBCTL1) ) {      DEBUG(2,"ACB%d disabled, but ACBCTL1!=0\n",dev->index);      return -ENXIO;   }   outz( ACBST_BER|ACBST_NEGACK|ACBST_STASTR, ACBST );   outz( 0, ACBST ); // Status Reg bug workaround   acb_bbusy(dev);   return 0;}static intamd_acb_machine(struct acb_dev *dev,int status){   unsigned char addr, ch;   unsigned short flags;   if( (status&ACBST_MASTER) == 0 ) {      DEBUG(1,"ACB%d NOT MASTER\n",dev->index);      dev->state = state_error;   }   if( (status&ACBST_BER) != 0 ) {      DEBUG(1,"ACB%d BUS ERROR\n",dev->index);      outz( ACBST_BER, ACBST );      outz( 0, ACBST ); // Status Reg bug workaround      dev->state = state_error;   }   if( (status&ACBST_STASTR) != 0 ) {      DEBUG(5,"ACB%d STALLED\n",dev->index);      outz( ACBST_STASTR,  ACBST );      outz( 0, ACBST ); // Status Reg bug workaround      return 0;   }   switch( dev->state ) {   case state_error:      break;   case state_address:      addr = dev->addr << 1;      flags = dev->flags;      if( dev->len > 0 ) {         if( (flags&I2C_M_RD) != 0 ) {            addr |= 1;            dev->state = state_read;            if( dev->len == 1 )               acb_snak(dev);         }         else            dev->state = state_write;      }      else         dev->state = state_next;      if( (flags&I2C_M_REV_DIR_ADDR) != 0 )         addr ^= 1;      DEBUG(5,"ACB%d SEND ADDR %02x\n",dev->index,addr);      outz( addr, ACBSDA );      break;   case state_read:      if( (status&ACBST_XMIT) !=  0 ) {         acb_dump(dev);         return 0;      }      if( --dev->len <= 0 ) {         if( dev->last == 0 ) {            acb_start(dev);            dev->state = state_next;         }         else {            acb_stop(dev);            dev->state = state_idle;         }      }      else if( dev->len == 1 )         acb_snak(dev);      ch = inz(ACBSDA);      DEBUG(5,"ACB%d RECV DATA %02x %d\n",dev->index,ch,dev->len);      *dev->bp++ = ch;      break;   case state_write:      if( (status&ACBST_XMIT) ==  0 ) {         acb_dump(dev);         return 0;      }      if( (status&ACBST_NEGACK) != 0 ) {         DEBUG(5,"ACB%d NAK\n",dev->index);         if( dev->last == 0 )            acb_start(dev);         outz( ACBST_NEGACK, ACBST );         outz( 0, ACBST ); // Status Reg bug workaround         dev->state = state_next;         break;      }      if( dev->len <= 0 ) {         dev->state = state_next;         break;      }      ch = *dev->bp++;      DEBUG(5,"ACB%d SEND DATA %02x %d\n",dev->index,ch,dev->len);      outz( ch, ACBSDA );      if( --dev->len <= 0 ) {         if( dev->last == 0 )            acb_start(dev);      }      break;   case state_stop:      acb_stop(dev);      dev->state = state_idle;      break;   default:      DEBUG(0,"ACB%d, Interrupt in state %d\n",dev->index,dev->state);      return 0;   }   if( dev->state == state_next && dev->last != 0 )      dev->state = state_stop;   return 1;}#ifdef POLLED_MODEstatic void

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -