www.pudn.com > 422.rar > proc.c


/* proc.c
* Linux serial-bus device driver.
 * Written by wang song yue--bupt  email:wsy5228@sina.com
 * This software is released under the GPL-License.
 * Version 0.1  28 october 2005
 */ 

#define __NO_VERSION__
#include 

#include 
#if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
#define MODVERSIONS
#endif

#if defined (MODVERSIONS)
#include 
#endif

#include 
#include 
#include 
#include 

#include "../include/main.h"
#include "../include/proc.h"
#include "../include/setup.h"

int add_channel_to_procdir(void);
int remove_channel_from_procdir(void);
int add_object_to_procdir(void);
int remove_object_from_procdir(void);

#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
static int candev_readlink(struct proc_dir_entry *de, char *page);
#endif

static int bc=0; /* static counter for each hardware board */
static int cc=0; /* static counter for each CAN chip */
static int oc=0; /* static counter for each message object */

struct canproc_t can_proc_base;
struct canproc_t *base=&can_proc_base;

/* The following functions are needed only for kernel version 2.2. Kernel
 * version 2.4 already defines them for us.
 */
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
static void can_fill_inode(struct inode *inode, int fill)
{
	if (fill)
		MOD_INC_USE_COUNT;
	else
		MOD_DEC_USE_COUNT;
}

static struct proc_dir_entry * new_can_proc_entry(unsigned short inode,
    const char *name, mode_t mode, nlink_t nlink, struct proc_dir_entry *parent)
{
	struct proc_dir_entry *new_entry = NULL;

	new_entry = (struct proc_dir_entry *) kmalloc(sizeof(struct 
						proc_dir_entry), GFP_KERNEL);
	if (new_entry == NULL)
		return NULL;

	memset(new_entry, 0, sizeof(struct proc_dir_entry));

	new_entry->low_ino = inode;
	new_entry->namelen = strlen(name);
	new_entry->name = name;
	new_entry->mode = mode;
	new_entry->nlink = nlink;
	new_entry->fill_inode = can_fill_inode;
	new_entry->parent = parent;

	proc_register(parent, new_entry);

	return new_entry;
}

int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_entry *parent)
{
	if (del != NULL) {
		proc_unregister(parent, del->low_ino);
		kfree(del);
		del = NULL;
		return 0;
	}
	else return -ENODEV;
}
#endif // Functions required for kernel 2.2

/* can_init_procdir registers the entire CAN directory tree recursively at
 * the proc system.
 */
int can_init_procdir(void)
{
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))                                  //by wangsy
	base->can_proc_entry = new_can_proc_entry(0, "tts", S_IFDIR | S_IRUGO | 
					S_IXUGO, 0, &proc_root);
#else
	base->can_proc_entry = create_proc_entry("tts", S_IFDIR | S_IRUGO | 
					S_IXUGO, &proc_root);
#endif
	if (base->can_proc_entry == NULL)
		return -ENODEV;

	for (bc=0; bcnr_boards; bc++) {
		add_channel_to_procdir();
	} 

	return 0;
}

/* can_delete_procdir removes the entire CAN tree from the proc system */
int can_delete_procdir(void)
{
	if (remove_channel_from_procdir()) 
		return -ENODEV;
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
	if (can_remove_proc_entry(base->can_proc_entry, &proc_root)) 
		return -ENODEV;
#else
	remove_proc_entry("can", &proc_root);
#endif

	return 0;
}

int add_channel_to_procdir(void)
{
	int i=0;

	for (i=0; i nr_16c554_chips; i++) {

		base->channel[cc] = (struct channelproc_t *)
			kmalloc(sizeof(struct channelproc_t), GFP_KERNEL);
		if (base->channel[cc] == NULL)
			return -ENOMEM;
		else if (add_mem_to_list(base->channel[cc]))
			return -ENOMEM;

		sprintf(base->channel[cc]->ch_name, "channel%d",cc);
						
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
		base->channel[cc]->ch_entry = new_can_proc_entry(0, 
						base->channel[cc]->ch_name,
						S_IFDIR | S_IRUGO | S_IXUGO, 0, 
						base->can_proc_entry);
#else
		base->channel[cc]->ch_entry = create_proc_entry(
						base->channel[cc]->ch_name,
						S_IFDIR | S_IRUGO |S_IXUGO,
						base->can_proc_entry);
#endif
		if (base->channel[cc]->ch_entry == NULL)
			return -ENODEV;

		add_object_to_procdir();

		cc++;
	} 

	return 0;
}

int remove_channel_from_procdir(void)
{
	
	while (cc != 0) {
		cc--;
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
		if (can_remove_proc_entry(base->channel[cc]->ch_entry,
							base->can_proc_entry))
			return -ENODEV;
#else
		remove_proc_entry(base->channel[cc]->ch_name,
							base->can_proc_entry);
#endif
		if (remove_object_from_procdir())
			return -ENODEV; 
	}

	return 0;
}


int add_object_to_procdir(void)
{
	int i=0, obj=0;

	if (!strcmp(chips_p[cc]->chip_type,"i82527"))
		obj=15;
	if (!strcmp(chips_p[cc]->chip_type,"16c554"))
		obj=1;

	for (i=0; ichannel[cc]->object[i] = (struct objectproc_t *)
			kmalloc(sizeof(struct objectproc_t),GFP_KERNEL);
				
				
		if (base->channel[cc]->object[i] == NULL)
			return -ENOMEM;
		else if (add_mem_to_list( base->channel[cc]->object[i]))
			return -ENOMEM;

		sprintf(base->channel[cc]->object[i]->obj_name,"object%d",i);
		sprintf(base->channel[cc]->object[i]->lnk_name,"dev");
								
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
		base->channel[cc]->object[i]->obj_entry=new_can_proc_entry(
				0, base->channel[cc]->object[i]->obj_name,
				S_IFDIR | S_IRUGO | S_IXUGO, 0, 
				base->channel[cc]->ch_entry);
		if (base->channel[cc]->object[i]->obj_entry == NULL)
			return -ENODEV;
		base->channel[cc]->object[i]->lnk = new_can_proc_entry(
				0, base->channel[cc]->object[i]->lnk_name, 
				S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO,
				0, base->channel[cc]->object[i]->obj_entry);
		if (base->channel[cc]->object[i]->lnk == NULL)
			return -ENODEV;
		sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/tts");
		base->channel[cc]->object[i]->lnk->readlink_proc =
								candev_readlink;

#else
		base->channel[cc]->object[i]->obj_entry = create_proc_entry(
				base->channel[cc]->object[i]->obj_name,
				S_IFDIR | S_IRUGO | S_IXUGO,
				base->channel[cc]->ch_entry);
		if (base->channel[cc]->object[i]->obj_entry == NULL)
			return -ENODEV;
		sprintf(base->channel[cc]->object[i]->lnk_dev,"/dev/tts%d",               //by wangsy
			chips_p[cc]->msgobj[i]->minor);
		base->channel[cc]->object[i]->lnk = proc_symlink(
				base->channel[cc]->object[i]->lnk_name,
				base->channel[cc]->object[i]->obj_entry,
				base->channel[cc]->object[i]->lnk_dev);
		if (base->channel[cc]->object[i]->lnk == NULL)
			return -ENODEV;
#endif

	}
	return 0;
} 

int remove_object_from_procdir(void)
{
	int i=0, obj=0;

	if (!strcmp(chips_p[cc]->chip_type,"i82527"))
		obj=15;
	if (!strcmp(chips_p[cc]->chip_type,"16c554"))
		obj=1;

	for (i=0; ichannel[cc]->object[i]->lnk,
				base->channel[cc]->object[i]->obj_entry))	
			return -ENODEV;
		if (can_remove_proc_entry(
				base->channel[cc]->object[i]->obj_entry,
				base->channel[cc]->ch_entry))
			return -ENODEV;
#else
		remove_proc_entry(base->channel[cc]->object[i]->lnk_name,
				base->channel[cc]->object[i]->obj_entry);
		remove_proc_entry(base->channel[cc]->object[i]->obj_name,
					base->channel[cc]->ch_entry);
#endif
		
	}
	return 0;
}

#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
static int candev_readlink(struct proc_dir_entry *de, char *page)
{
	int i=0, nchip=0, nobj=0;
	char chip[20], object[20], tmp[6];

	sprintf(chip, de->parent->parent->name+7);
	sprintf(object, de->parent->name+6);

	for (i=0; imsgobj[nobj]->minor );            //by wangsy
}
#endif //End of candev_readlink for kernel 2.2