| | 80 | |
| | 81 | /* --------------------------------------------------- |
| | 82 | * /proc entries |
| | 83 | *---------------------------------------------------- |
| | 84 | */ |
| | 85 | |
| | 86 | static int i2cproc_init(void); |
| | 87 | static int i2cproc_cleanup(void); |
| | 88 | |
| | 89 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) |
| | 90 | static void monitor_bus_i2c(struct inode *inode, int fill); |
| | 91 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ |
| | 92 | |
| | 93 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 94 | |
| | 95 | static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, |
| | 96 | loff_t *ppos); |
| | 97 | static int read_bus_i2c(char *buf, char **start, off_t offset, int len, |
| | 98 | int *eof , void *private); |
| | 99 | |
| | 100 | #else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ |
| | 101 | |
| | 102 | static int i2cproc_bus_read(struct inode * inode, struct file * file, |
| | 103 | char * buf, int count); |
| | 104 | static int read_bus_i2c(char *buf, char **start, off_t offset, int len, |
| | 105 | int unused); |
| | 106 | |
| | 107 | static struct proc_dir_entry proc_bus_dir = |
| | 108 | { |
| | 109 | /* low_ino */ 0, /* Set by proc_register_dynamic */ |
| | 110 | /* namelen */ 3, |
| | 111 | /* name */ "bus", |
| | 112 | /* mode */ S_IRUGO | S_IXUGO | S_IFDIR, |
| | 113 | /* nlink */ 2, /* Corrected by proc_register[_dynamic] */ |
| | 114 | /* uid */ 0, |
| | 115 | /* gid */ 0, |
| | 116 | /* size */ 0, |
| | 117 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,0,36)) |
| | 118 | /* ops */ &proc_dir_inode_operations, |
| | 119 | #endif |
| | 120 | }; |
| | 121 | |
| | 122 | static struct proc_dir_entry proc_bus_i2c_dir = |
| | 123 | { |
| | 124 | /* low_ino */ 0, /* Set by proc_register_dynamic */ |
| | 125 | /* namelen */ 3, |
| | 126 | /* name */ "i2c", |
| | 127 | /* mode */ S_IRUGO | S_IFREG, |
| | 128 | /* nlink */ 1, |
| | 129 | /* uid */ 0, |
| | 130 | /* gid */ 0, |
| | 131 | /* size */ 0, |
| | 132 | /* ops */ NULL, |
| | 133 | /* get_info */ &read_bus_i2c |
| | 134 | }; |
| | 135 | |
| | 136 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 137 | |
| | 138 | /* To implement the dynamic /proc/bus/i2c-? files, we need our own |
| | 139 | implementation of the read hook */ |
| | 140 | static struct file_operations i2cproc_operations = { |
| | 141 | NULL, |
| | 142 | i2cproc_bus_read, |
| | 143 | }; |
| | 144 | |
| | 145 | static struct inode_operations i2cproc_inode_operations = { |
| | 146 | &i2cproc_operations |
| | 147 | }; |
| | 148 | |
| | 149 | static int i2cproc_initialized; |
| | 150 | |
| | 238 | sprintf(name,"i2c-%d", i); |
| | 239 | |
| | 240 | if (i2cproc_initialized) { |
| | 241 | |
| | 242 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 243 | proc_entry = create_proc_entry(name,0,proc_bus); |
| | 244 | if (! proc_entry) { |
| | 245 | printk("i2c-core: Could not create /proc/bus/%s\n", |
| | 246 | name); |
| | 247 | return -ENOENT; |
| | 248 | } |
| | 249 | proc_entry->ops = &i2cproc_inode_operations; |
| | 250 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) |
| | 251 | proc_entry->fill_inode = &monitor_bus_i2c; |
| | 252 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ |
| | 253 | #else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ |
| | 254 | if (!(proc_entry = kmalloc(sizeof(struct proc_dir_entry)+ |
| | 255 | strlen(name)+1, GFP_KERNEL))) { |
| | 256 | printk("i2c-core: Out of memory!\n"); |
| | 257 | return -ENOMEM; |
| | 258 | } |
| | 259 | memset(proc_entry,0,sizeof(struct proc_dir_entry)); |
| | 260 | proc_entry->namelen = strlen(name); |
| | 261 | proc_entry->name = (char *) (proc_entry + 1); |
| | 262 | proc_entry->mode = S_IRUGO | S_IFREG; |
| | 263 | proc_entry->nlink = 1; |
| | 264 | proc_entry->ops = &i2cproc_inode_operations; |
| | 265 | |
| | 266 | /* Nasty stuff to keep GCC satisfied */ |
| | 267 | { |
| | 268 | char *procname; |
| | 269 | (const char *) procname = proc_entry->name; |
| | 270 | strcpy (procname,name); |
| | 271 | } |
| | 272 | |
| | 273 | if ((res = proc_register_dynamic(&proc_bus_dir, proc_entry))) { |
| | 274 | printk("i2c-core: Could not create %s.\n",name); |
| | 275 | kfree(proc_entry); |
| | 276 | return res; |
| | 277 | } |
| | 278 | |
| | 279 | adapters[i]->proc_entry = proc_entry; |
| | 280 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 281 | |
| | 282 | adapters[i]->inode = proc_entry->low_ino; |
| | 283 | } |
| | 284 | |
| | 486 | |
| | 487 | /* ---------------------------------------------------- |
| | 488 | * The /proc functions |
| | 489 | * ---------------------------------------------------- |
| | 490 | */ |
| | 491 | |
| | 492 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) |
| | 493 | /* Monitor access to /proc/bus/i2c*; make unloading i2c-proc impossible |
| | 494 | if some process still uses it or some file in it */ |
| | 495 | void monitor_bus_i2c(struct inode *inode, int fill) |
| | 496 | { |
| | 497 | if (fill) |
| | 498 | MOD_INC_USE_COUNT; |
| | 499 | else |
| | 500 | MOD_DEC_USE_COUNT; |
| | 501 | } |
| | 502 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) */ |
| | 503 | |
| | 504 | /* This function generates the output for /proc/bus/i2c */ |
| | 505 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 506 | int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, |
| | 507 | void *private) |
| | 508 | #else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ |
| | 509 | int read_bus_i2c(char *buf, char **start, off_t offset, int len, int unused) |
| | 510 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 511 | { |
| | 512 | int i; |
| | 513 | int nr = 0; |
| | 514 | /* Note that it is safe to write a `little' beyond len. Yes, really. */ |
| | 515 | for (i = 0; (i < I2C_ADAP_MAX) && (nr < len); i++) |
| | 516 | if (adapters[i]) |
| | 517 | nr += sprintf(buf+nr, "i2c-%d\t", i2c_adapter_id(adapters[i])); |
| | 518 | if (adapters[i]->algo->smbus_xfer) { |
| | 519 | if (adapters[i]->algo->master_xfer) |
| | 520 | nr += sprintf(buf+nr,"smbus/i2c"); |
| | 521 | else |
| | 522 | nr += sprintf(buf+nr,"smbus "); |
| | 523 | } else if (adapters[i]->algo->master_xfer) |
| | 524 | nr += sprintf(buf+nr,"i2c "); |
| | 525 | else |
| | 526 | nr += sprintf(buf+nr,"dummy "); |
| | 527 | nr += sprintf(buf+nr,"\t%-32s\t%-32s\n", |
| | 528 | adapters[i]->name, |
| | 529 | adapters[i]->algo->name); |
| | 530 | return nr; |
| | 531 | } |
| | 532 | |
| | 533 | /* This function generates the output for /proc/bus/i2c-? */ |
| | 534 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 535 | ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, |
| | 536 | loff_t *ppos) |
| | 537 | { |
| | 538 | struct inode * inode = file->f_dentry->d_inode; |
| | 539 | #else (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) |
| | 540 | int i2cproc_bus_read(struct inode * inode, struct file * file,char * buf, |
| | 541 | int count) |
| | 542 | { |
| | 543 | #endif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 544 | char *kbuf; |
| | 545 | struct i2c_client *client; |
| | 546 | int i,j,len=0; |
| | 547 | |
| | 548 | if (count < 0) |
| | 549 | return -EINVAL; |
| | 550 | if (count > 4000) |
| | 551 | count = 4000; |
| | 552 | for (i = 0; i < I2C_ADAP_MAX; i++) |
| | 553 | if (adapters[i]->inode == inode->i_ino) { |
| | 554 | /* We need a bit of slack in the kernel buffer; this makes the |
| | 555 | sprintf safe. */ |
| | 556 | if (! (kbuf = kmalloc(count + 80,GFP_KERNEL))) |
| | 557 | return -ENOMEM; |
| | 558 | for (j = 0; j < I2C_CLIENT_MAX; j++) |
| | 559 | if ((client = adapters[i]->clients[j])) |
| | 560 | /* Filter out dummy clients */ |
| | 561 | if (client->driver->id != I2C_DRIVERID_I2CDEV) |
| | 562 | len += sprintf(kbuf+len,"%x\t%-32s\t%-32s\n", |
| | 563 | client->addr, |
| | 564 | client->name,client->driver->name); |
| | 565 | if (file->f_pos+len > count) |
| | 566 | len = count - file->f_pos; |
| | 567 | len = len - file->f_pos; |
| | 568 | if (len < 0) |
| | 569 | len = 0; |
| | 570 | copy_to_user (buf,kbuf+file->f_pos,len); |
| | 571 | file->f_pos += len; |
| | 572 | kfree(kbuf); |
| | 573 | return len; |
| | 574 | } |
| | 575 | return -ENOENT; |
| | 576 | } |
| | 577 | |
| | 578 | int i2cproc_init(void) |
| | 579 | { |
| | 580 | |
| | 581 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 582 | struct proc_dir_entry *proc_bus_i2c; |
| | 583 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 584 | |
| | 585 | i2cproc_initialized = 0; |
| | 586 | |
| | 587 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 588 | if (! proc_bus) { |
| | 589 | printk("i2c-core: /proc/bus/ does not exist"); |
| | 590 | i2cproc_cleanup(); |
| | 591 | return -ENOENT; |
| | 592 | } |
| | 593 | proc_bus_i2c = create_proc_entry("i2c",0,proc_bus); |
| | 594 | if (!proc_bus_i2c) { |
| | 595 | printk("i2c-core: Could not create /proc/bus/i2c"); |
| | 596 | i2cproc_cleanup(); |
| | 597 | return -ENOENT; |
| | 598 | } |
| | 599 | proc_bus_i2c->read_proc = &read_bus_i2c; |
| | 600 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,58)) |
| | 601 | proc_bus_i2c->fill_inode = &monitor_bus_i2c; |
| | 602 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 603 | i2cproc_initialized += 2; |
| | 604 | #else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ |
| | 605 | /* In Linux 2.0.x, there is no /proc/bus! But I hope no other module |
| | 606 | introduced it, or we are fucked. And 2.0.35 and earlier does not |
| | 607 | export proc_dir_inode_operations, so we grab it from proc_net, |
| | 608 | which also uses it. Not nice. */ |
| | 609 | proc_bus_dir.ops = proc_net.ops; |
| | 610 | if ((res = proc_register_dynamic(&proc_root, &proc_bus_dir))) { |
| | 611 | printk("i2c-core: Could not create /proc/bus/"); |
| | 612 | i2cproc_cleanup(); |
| | 613 | return res; |
| | 614 | } |
| | 615 | i2cproc_initialized ++; |
| | 616 | if ((res = proc_register_dynamic(&proc_bus_dir, &proc_bus_i2c_dir))) { |
| | 617 | printk("i2c-core: Could not create /proc/bus/i2c\n"); |
| | 618 | i2cproc_cleanup(); |
| | 619 | return res; |
| | 620 | } |
| | 621 | i2cproc_initialized ++; |
| | 622 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 623 | return 0; |
| | 624 | } |
| | 625 | |
| | 626 | int i2cproc_cleanup(void) |
| | 627 | { |
| | 628 | |
| | 629 | if (i2cproc_initialized >= 1) { |
| | 630 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) |
| | 631 | remove_proc_entry("i2c",proc_bus); |
| | 632 | i2cproc_initialized -= 2; |
| | 633 | #else /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)) */ |
| | 634 | if (i2cproc_initialized >= 2) { |
| | 635 | if ((res = proc_unregister(&proc_bus_dir, |
| | 636 | proc_bus_i2c_dir.low_ino))) { |
| | 637 | printk("i2c-core: could not delete " |
| | 638 | "/proc/bus/i2c, module not removed."); |
| | 639 | return res; |
| | 640 | } |
| | 641 | i2cproc_initialized --; |
| | 642 | } |
| | 643 | if ((res = proc_unregister(&proc_root,proc_bus_dir.low_ino))) { |
| | 644 | printk("i2c-core: could not delete /proc/bus/, " |
| | 645 | "module not removed."); |
| | 646 | return res; |
| | 647 | } |
| | 648 | i2cproc_initialized --; |
| | 649 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,29)) */ |
| | 650 | } |
| | 651 | return 0; |
| | 652 | } |
| | 653 | |