📄 i2c-core.c
字号:
{ if (client->flags & I2C_CLIENT_ALLOW_USE) { if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) client->usage_count++; else if (client->usage_count > 0) return -EBUSY; else client->usage_count++; } i2c_inc_use_client(client); return 0;}int i2c_release_client(struct i2c_client *client){ if(client->flags & I2C_CLIENT_ALLOW_USE) { if(client->usage_count>0) client->usage_count--; else { printk(KERN_WARNING " i2c-core.o: dec_use_client used one too many times\n"); return -EPERM; } } i2c_dec_use_client(client); return 0;}/* ---------------------------------------------------- * The /proc functions * ---------------------------------------------------- */#ifdef CONFIG_PROC_FS/* This function generates the output for /proc/bus/i2c */static int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, void *private){ int i; int nr = 0; /* Note that it is safe to write a `little' beyond len. Yes, really. */ down(&core_lists); for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) if (adapters[i]) { nr += sprintf(buf+nr, "i2c-%d\t", i); if (adapters[i]->algo->smbus_xfer) { if (adapters[i]->algo->master_xfer) nr += sprintf(buf+nr,"smbus/i2c"); else nr += sprintf(buf+nr,"smbus "); } else if (adapters[i]->algo->master_xfer) nr += sprintf(buf+nr,"i2c "); else nr += sprintf(buf+nr,"dummy "); nr += sprintf(buf+nr,"\t%-32s\t%-32s\n", adapters[i]->name, adapters[i]->algo->name); } up(&core_lists); return nr;}/* This function generates the output for /proc/bus/i2c-? */ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, loff_t *ppos){ struct inode * inode = file->f_dentry->d_inode; char *kbuf; struct i2c_client *client; struct i2c_adapter *adap; int i,j,k,order_nr,len=0; size_t len_total; int order[I2C_CLIENT_MAX];#define OUTPUT_LENGTH_PER_LINE 70 len_total = file->f_pos + count; if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) ) /* adjust to maximum file size */ len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE); down(&core_lists); /* adap = file->private_data; ?? --km */ for (i = 0; i < I2C_ADAP_MAX; i++) { adap = adapters[i]; if (adap && (adap->inode == inode->i_ino)) break; } if ( I2C_ADAP_MAX == i ) { up(&core_lists); return -ENOENT; } /* We need a bit of slack in the kernel buffer; this makes the sprintf safe. */ if (! (kbuf = kmalloc(len_total + OUTPUT_LENGTH_PER_LINE, GFP_KERNEL))) return -ENOMEM; /* Order will hold the indexes of the clients sorted by address */ order_nr=0; I2C_LOCK_LIST(adap); for (j = 0; j < I2C_CLIENT_MAX; j++) { if ((client = adap->clients[j]) && (client->driver->id != I2C_DRIVERID_I2CDEV)) { for(k = order_nr; (k > 0) && adap->clients[order[k-1]]-> addr > client->addr; k--) order[k] = order[k-1]; order[k] = j; order_nr++; } } for (j = 0; (j < order_nr) && (len < len_total); j++) { client = adap->clients[order[j]]; len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", client->addr, client->name, client->driver->name); } I2C_UNLOCK_LIST(adap); up(&core_lists); len = len - file->f_pos; if (len > count) len = count; if (len < 0) len = 0; if (copy_to_user (buf,kbuf+file->f_pos, len)) { kfree(kbuf); return -EFAULT; } file->f_pos += len; kfree(kbuf); return len;}static int i2cproc_register(struct i2c_adapter *adap, int bus){ char name[8]; struct proc_dir_entry *proc_entry; sprintf(name,"i2c-%d", bus); proc_entry = create_proc_entry(name,0,proc_bus); if (! proc_entry) { printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", name); return -ENOENT; } proc_entry->proc_fops = &i2cproc_operations; proc_entry->owner = THIS_MODULE; adap->inode = proc_entry->low_ino; return 0;}static void i2cproc_remove(int bus){ char name[8]; sprintf(name,"i2c-%d", bus); remove_proc_entry(name, proc_bus);}static int __init i2cproc_init(void){ struct proc_dir_entry *proc_bus_i2c; proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); if (!proc_bus_i2c) { printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); return -ENOENT; } proc_bus_i2c->read_proc = &read_bus_i2c; proc_bus_i2c->owner = THIS_MODULE; return 0;}static void __exit i2cproc_cleanup(void){ remove_proc_entry("i2c",proc_bus);}#endif /* def CONFIG_PROC_FS *//* ---------------------------------------------------- * the functional interface to the i2c busses. * ---------------------------------------------------- */int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num){ int ret; if (adap->algo->master_xfer) { if (i2c_debug >= 2) { printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with " "%d msgs\n", adap->name, num); for (ret = 0; ret < num; ret++) { printk(KERN_DEBUG "i2c-core.o: " "master_xfer[%d]: %c, " "addr=0x%02x, len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? 'R' : 'W', msgs[ret].addr, msgs[ret].len); } } down(&adap->bus); ret = adap->algo->master_xfer(adap,msgs,num); up(&adap->bus); return ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", adap->id); return -ENOSYS; }}int i2c_master_send(struct i2c_client *client,const char *buf ,int count){ int ret; struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; if (client->adapter->algo->master_xfer) { msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.len = count; msg.buf = (char *)buf; DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", count,client->adapter->name)); down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); up(&adap->bus); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1 )? count : ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; }}int i2c_master_recv(struct i2c_client *client, char *buf ,int count){ struct i2c_adapter *adap=client->adapter; struct i2c_msg msg; int ret; if (client->adapter->algo->master_xfer) { msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", count,client->adapter->name)); down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); up(&adap->bus); DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n", ret, count, client->addr)); /* if everything went ok (i.e. 1 msg transmitted), return #bytes * transmitted, else error code. */ return (ret == 1 )? count : ret; } else { printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", client->adapter->id); return -ENOSYS; }}int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg){ int ret = 0; struct i2c_adapter *adap = client->adapter; DEB2(printk(KERN_DEBUG "i2c-core.o: i2c ioctl, cmd: 0x%x, arg: %#lx\n", cmd, arg)); switch ( cmd ) { case I2C_RETRIES: adap->retries = arg; break; case I2C_TIMEOUT: adap->timeout = arg; break; default: if (adap->algo->algo_control!=NULL) ret = adap->algo->algo_control(adap,cmd,arg); } return ret;}/* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! * ---------------------------------------------------- */int i2c_probe(struct i2c_adapter *adapter, struct i2c_client_address_data *address_data, i2c_client_found_addr_proc *found_proc){ int addr,i,found,err; int adap_id = i2c_adapter_id(adapter); /* Forget it if we can't probe using SMBUS_QUICK */ if (! i2c_check_functionality(adapter,I2C_FUNC_SMBUS_QUICK)) return -1; for (addr = 0x00; addr <= 0x7f; addr++) { /* Skip if already in use */ if (i2c_check_addr(adapter,addr)) continue; /* If it is in one of the force entries, we don't do any detection at all */ found = 0; for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->force[i]) || (address_data->force[i] == ANY_I2C_BUS)) && (addr == address_data->force[i+1])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n", adap_id,addr)); if ((err = found_proc(adapter,addr,0,0))) return err; found = 1; } } if (found) continue; /* If this address is in one of the ignores, we can forget about it right now */ for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->ignore[i]) || ((address_data->ignore[i] == ANY_I2C_BUS))) && (addr == address_data->ignore[i+1])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, " "addr %04x\n", adap_id ,addr)); found = 1; } } for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { if (((adap_id == address_data->ignore_range[i]) || ((address_data->ignore_range[i]==ANY_I2C_BUS))) && (addr >= address_data->ignore_range[i+1]) && (addr <= address_data->ignore_range[i+2])) { DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); found = 1; } } if (found) continue; /* Now, we will do a detection, but only if it is in the normal or probe entries */ for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { if (addr == address_data->normal_i2c[i]) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c entry for adapter %d, " "addr %02x\n", adap_id, addr)); } } for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { if ((addr >= address_data->normal_i2c_range[i]) && (addr <= address_data->normal_i2c_range[i+1])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found normal i2c_range entry for adapter %d, " "addr %04x\n", adap_id,addr)); } } for (i = 0; !found && (address_data->probe[i] != I2C_CLIENT_END); i += 2) { if (((adap_id == address_data->probe[i]) || ((address_data->probe[i] == ANY_I2C_BUS))) && (addr == address_data->probe[i+1])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found probe parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { if (((adap_id == address_data->probe_range[i]) || (address_data->probe_range[i] == ANY_I2C_BUS)) && (addr >= address_data->probe_range[i+1]) && (addr <= address_data->probe_range[i+2])) { found = 1; DEB2(printk(KERN_DEBUG "i2c-core.o: found probe_range parameter for adapter %d, " "addr %04x\n", adap_id,addr)); } } if (!found) continue; /* OK, so we really should examine this address. First check whether there is some client here at all! */ if (i2c_smbus_xfer(adapter,addr,0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) if ((err = found_proc(adapter,addr,0,-1))) return err; } return 0;}/* * return id number for a specific adapter */int i2c_adapter_id(struct i2c_adapter *adap){ int i; for (i = 0; i < I2C_ADAP_MAX; i++) if (adap == adapters[i]) return i; return -1;}/* The SMBus parts */#define POLY (0x1070U << 3) static u8crc8(u16 data){ int i; for(i = 0; i < 8; i++) { if (data & 0x8000) data = data ^ POLY; data = data << 1; } return (u8)(data >> 8);}/* Incremental CRC8 over count bytes in the array pointed to by p */static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count){ int i; for(i = 0; i < count; i++) crc = crc8((crc ^ p[i]) << 8); return crc;}/* Assume a 7-bit address, which is reasonable for SMBus */static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg){ /* The address will be sent first */ u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); pec = i2c_smbus_pec(pec, &addr, 1); /* The data buffer follows */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -