📄 lx_acb.c
字号:
amd_acb_poll(struct acb_dev *dev){ int status, ret; unsigned long tmo; for(;;) { tmo = jiffies + POLL_TIMEOUT; while( jiffies < tmo ) { status = inz(ACBST); while( (status&(ACBST_BER|ACBST_SDAST|ACBST_NEGACK)) != 0 ) { ret = amd_acb_machine(dev, status); if( ret == 0 ) break; return; } yield(); } acb_reset(dev); if( dev->msgn != 0 || dev->state != state_address ) break; if( --dev->retries < 0 ) break; DEBUG(3,"ACB%d RETRY %d\n",dev->index,dev->retries); acb_start(dev); } DEBUG(0,"ACB%d TIMEOUT\n",dev->index); dev->state = state_error;}#endif /* POLLED_MODE */static intamd_acb_master_xfer(struct i2c_adapter *adp, struct i2c_msg *msg, int num){ struct acb_dev *dev = adp->algo_data; DEBUG(2,"ACB%d XFER %d MSGS\n",dev->index,num); if( num <= 0 ) return 0; down(&dev->sem); acb_start(dev); dev->last = 0; dev->result = 0; dev->state = state_address; dev->count = num; dev->msgn = 0; for(;;) { if( (dev->msgn+1) >= dev->count ) dev->last = 1; dev->flags = msg->flags; if( (dev->flags & I2C_M_TEN) != 0 ) { DEBUG(0,"ACB%d ten bit addresses not supported\n",dev->index); dev->result = -EIO; break; } dev->bp = msg->buf; dev->len = msg->len; dev->addr = msg->addr; dev->retries = adp->retries; dev->state = state_address; DEBUG(2,"ACB%d MSG %d %s %d bytes\n",dev->index,dev->msgn, (dev->flags&I2C_M_RD)!=0 ? "rd" : "wr", dev->len);#ifdef POLLED_MODE while( ((1<<dev->state) & STATE_ACTIVE) != 0 ) { amd_acb_poll(dev); }#else /* POLLED_MODE */#error Interrupt driven mode not implemented#endif /* POLLED_MODE */ if( dev->state == state_idle ) break; if( dev->state != state_next ) { if( dev->result == 0 ) dev->result = -EIO; acb_dump(dev); acb_reset(dev); break; } ++dev->msgn; ++msg; } up(&dev->sem); return dev->result != 0 ? dev->result : num;}#ifdef MOD_INC_USE_COUNTvoidamd_acb_inc_use(struct i2c_adapter *adapter){#ifdef MODULE MOD_INC_USE_COUNT;#endif}#endif#ifdef MOD_DEC_USE_COUNTvoidamd_acb_dec_use(struct i2c_adapter *adapter){#ifdef MODULE MOD_DEC_USE_COUNT;#endif}#endifstatic u32amd_acb_functionality(struct i2c_adapter *adp){ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;}#ifdef IO_SIOCFG_IN_10#define CFG_INDEX 0x002E#define CFG_DATA 0x002F#else#define CFG_INDEX 0x015C /* Cygnus/Krill... */#define CFG_DATA 0x015D#endif#define CFG_IDX_LDN 7#define CFG_IDX_ACBH 60#define CFG_IDX_ACBL 61#define LDN_ACB1 5 /* ACB1 (LDN 5) */#define LDN_ACB2 6 /* ACB2 (LDN 6) */static intdetect_addr_ldn(struct amd_acb_driver *s){ int i, addr, ldn, io[MAX_DEVICES]; unsigned long flags; ldn = LDN_ACB1; s->n_dev = 2; /* probe addresses */ spin_lock_irqsave(&s->lock, flags); for( i=0; i<s->n_dev; ++i ) { outz(CFG_IDX_LDN,CFG_INDEX); outz(ldn,CFG_DATA); outz(CFG_IDX_ACBH,CFG_INDEX); addr = inz(CFG_DATA) << 8; outz(CFG_IDX_ACBL,CFG_INDEX); addr |= inz(CFG_DATA); if( addr == 0 ) break; io[i] = addr; ++ldn; } spin_unlock_irqrestore(&s->lock, flags); /* check addresses */ for( i=0; i<s->n_dev; ++i ) { DEBUG(1,"bus %d addr %04x\n",i,io[i]); if( io[i] == 0 ) return -ENODEV; } /* load algo_data */ for( i=0; i<s->n_dev; ++i ) { struct acb_dev *dev = &s->dev[i]; dev->io = io[i]; } return 0;}static intdetect_addr_bar(struct amd_acb_driver *s){ unsigned long addr; struct acb_dev *dev; /* check addresses */ if( s->pci == NULL ) return -ENODEV; addr = pci_resource_start(s->pci,0); if( addr == 0 ) return -ENODEV; s->n_dev = 1; /* load algo_data */ dev = &s->dev[0]; dev->io = addr; DEBUG(1,"bus addr %04lx\n",addr); return 0;}/* pci vendor and device id for pci to isa bridge */#define PCI_DEVICE_ID_CYRIX_SC1400_BRIDGE 0x0405 #define PCI_DEVICE_ID_NS_SC1200_BRIDGE 0x0505 #define PCI_DEVICE_ID_NS_LX_BRIDGE 0x002b #define PCI_DEVICE_ID_AMD_LX_BRIDGE 0x2090#ifndef I2C_HW_ACB_SC1200 #define I2C_HW_ACB_SC1200 (I2C_ALGO_ACB | 0)#endif#ifndef I2C_HW_ACB_SC1400 #define I2C_HW_ACB_SC1400 (I2C_ALGO_ACB | 1)#endif#ifndef I2C_HW_ACB_LX #define I2C_HW_ACB_LX (I2C_ALGO_ACB | 2)#endif#define MODEL(vendor,name,model,probe,n) { \ #name, I2C_HW_ACB_##name, 0x##model, detect_addr_##probe, n, \ PCI_VENDOR_ID_##vendor, PCI_DEVICE_ID_##vendor##_##name##_BRIDGE }static struct pci_id { char *name; int id; int model; int (*probe)(struct amd_acb_driver *s); int n_dev; int vendor; int devid;} pci_isa_devids[] = { MODEL(AMD , LX , 5536, bar, 1), MODEL(NS , LX , 5535, bar, 1), MODEL(NS , SC1200, 1200, ldn, 2), MODEL(CYRIX, SC1400, 1400, ldn, 1),};static intdetect_addr(struct amd_acb_driver *s){ int i, rc; struct acb_dev *dev; struct i2c_adapter *adp; struct i2c_algorithm *algo; struct pci_dev *dp; struct pci_id *idp = &pci_isa_devids[0]; rc = 0; for( i=LENGTH(pci_isa_devids); --i>=0; ++idp ) { dp = pci_find_device(idp->vendor,idp->devid,NULL); if( dp != NULL ) break; } if( i < 0 ) { rc = -ENODEV; goto xit; } if( (rc=pci_request_region(dp,0,"amd_acb")) != 0 ) goto xit; s->pci = dp; s->model = idp->model; DEBUG(0,"model %04x/id %08x\n",idp->model,idp->id); rc = idp->probe(s); if( rc != 0 ) goto xit; s->n_dev = idp->n_dev; spin_lock_init(&s->lock); for( i=0; i<s->n_dev; ++i ) { dev = &s->dev[i]; dev->index = i; init_MUTEX(&dev->sem); algo = &dev->algo; strcpy(&algo->name[0],"ACCESS.bus (ACB) algorithm"); algo->id = I2C_ALGO_ACB; algo->master_xfer = amd_acb_master_xfer; algo->functionality = amd_acb_functionality; adp = &dev->adp; sprintf(&adp->name[0],"%s (ACB%d)",idp->name,i+1); adp->id = idp->id; adp->algo = algo; adp->algo_data = dev;#ifdef MOD_IEC_USE_COUNT adp->inc_use = amd_acb_inc_use;#endif#ifdef MOD_DEC_USE_COUNT adp->dec_use = amd_acb_dec_use;#endif DEBUG(3,"ACB%d ADD %08lx\n",dev->index,(unsigned long)adp); rc = i2c_add_adapter(adp); if( rc != 0 ) { DEBUG(0,"Adapter %d registration failed: %d\n",i+1,rc); rc = -ENODEV; goto xit; } rc = acb_probe(dev); if( rc != 0 ) goto xit; } return 0;xit: if( s->pci != NULL ) pci_release_region(s->pci,0); return rc;}static int __initamd_acb_init(void){ int rc; DEBUG(0,"AMD ACCESS.bus Driver\n"); s = kmalloc(sizeof(*s),GFP_KERNEL); if( s == NULL ) return -ENOMEM; memset(s,0,sizeof(*s)); rc = detect_addr(s); if( rc != 0 ) { kfree(s); s = NULL; } return rc;}static void __exitamd_acb_cleanup(void){ int i; struct acb_dev *dev; struct i2c_adapter *adp; DEBUG(0,"removing ACCESS.bus Driver\n"); if( s == NULL ) return; for( i=0; i<s->n_dev; ++i ) { dev = &s->dev[i]; adp = &dev->adp; DEBUG(3,"ACB%d DELETE %08lx\n",dev->index,(unsigned long)adp); i2c_del_adapter(adp); pci_release_region(s->pci,0); } kfree(s); s = NULL;}#ifdef EXPORT_NO_SYMBOLSEXPORT_NO_SYMBOLS;#endifmodule_init(amd_acb_init);module_exit(amd_acb_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -