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

📄 chandev.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  drivers/s390/misc/chandev.c * *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) *  *  Generic channel device initialisation support.  */#define TRUE 1#define FALSE 0#define __KERNEL_SYSCALLS__#include <linux/module.h>#include <linux/config.h>#include <linux/types.h>#include <linux/ctype.h>#include <asm/uaccess.h>#include <linux/slab.h>#include <asm/irq.h>#include <linux/init.h>#include <linux/unistd.h>#include <asm/chandev.h>#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <asm/s390dyn.h>#include <asm/queue.h>#include <linux/kmod.h>#ifndef MIN#define MIN(a,b) ((a<b)?a:b)#endif#ifndef MAX#define MAX(a,b) ((a>b)?a:b)#endiftypedef struct chandev_model_info chandev_model_info;struct chandev_model_info{	struct chandev_model_info *next;	chandev_type chan_type;	s32 cu_type;      /* control unit type  -1 = don't care */	s16 cu_model;     /* control unit model -1 = don't care */	s32 dev_type;     /* device type -1 = don't care */	s16 dev_model;    /* device model -1 = don't care */	u8  max_port_no;	int auto_msck_recovery;	u8  default_checksum_received_ip_pkts;	u8  default_use_hw_stats; /* where available e.g. lcs */	devreg_t drinfo;};typedef struct chandev chandev;struct chandev{	struct chandev *next;	chandev_model_info *model_info;	chandev_subchannel_info sch;	int owned;};typedef struct chandev_noauto_range chandev_noauto_range;struct chandev_noauto_range{	struct chandev_noauto_range *next;	u16     lo_devno;	u16     hi_devno;};typedef struct chandev_force chandev_force;struct chandev_force{	struct chandev_force *next;	chandev_type chan_type;	s32     devif_num; /* -1 don't care, -2 we are forcing a range e.g. tr0 implies 0 */        u16     read_lo_devno;	u16     write_hi_devno;	u16     data_devno; /* only used by gigabit ethernet */	s32     memory_usage_in_k;        s16     port_protocol_no; /* where available e.g. lcs,-1 don't care */	u8      checksum_received_ip_pkts;	u8      use_hw_stats; /* where available e.g. lcs */	/* claw specific stuff */	chandev_claw_info  claw;};typedef struct chandev_probelist chandev_probelist;struct chandev_probelist{	struct chandev_probelist            *next;	chandev_probefunc                   probefunc;	chandev_shutdownfunc                shutdownfunc;	chandev_msck_notification_func      msck_notfunc;	chandev_type                        chan_type;	int                                 devices_found;};#define default_msck_bits ((1<<(chandev_status_not_oper-1))|(1<<(chandev_status_no_path-1))|(1<<(chandev_status_revalidate-1))|(1<<(chandev_status_gone-1)))static char *msck_status_strs[]={	"good",	"not_operational",	"no_path",	"revalidate",	"device_gone"};typedef struct chandev_msck_range chandev_msck_range;struct chandev_msck_range{	struct chandev_msck_range *next;	u16     lo_devno;	u16     hi_devno;	int      auto_msck_recovery;};static chandev_msck_range *chandev_msck_range_head=NULL;typedef struct chandev_irqinfo chandev_irqinfo;struct chandev_irqinfo{	chandev_irqinfo         *next;	chandev_subchannel_info sch;	chandev_msck_status     msck_status;	void                    (*handler)(int, void *, struct pt_regs *);	unsigned long           irqflags;	void                    *dev_id;	char                    devname[0];};chandev_irqinfo *chandev_irqinfo_head=NULL;typedef struct chandev_parms chandev_parms;struct chandev_parms{	chandev_parms      *next;	chandev_type       chan_type;	u16                lo_devno;	u16                hi_devno;	char               parmstr[0];};static chandev_type chandev_persistent=0; chandev_parms *chandev_parms_head=NULL;typedef struct chandev_activelist chandev_activelist;struct chandev_activelist{	struct chandev_activelist        *next;	chandev_irqinfo                  *read_irqinfo;	chandev_irqinfo                  *write_irqinfo;	chandev_irqinfo                  *data_irqinfo;	chandev_probefunc                probefunc;	chandev_shutdownfunc             shutdownfunc;	chandev_msck_notification_func   msck_notfunc;	chandev_unregfunc                unreg_dev;	chandev_type                     chan_type;	u8                               port_no;	chandev_category                 category;	s32                              memory_usage_in_k;	void                             *dev_ptr;	char                             devname[0];};static chandev_model_info *chandev_models_head=NULL;/* The only reason chandev_head is a queue is so that net devices *//* will be by default named in the order of their irqs */static qheader chandev_head={NULL,NULL};static chandev_noauto_range *chandev_noauto_head=NULL;static chandev_force *chandev_force_head=NULL;static chandev_probelist *chandev_probelist_head=NULL;static chandev_activelist *chandev_activelist_head=NULL;#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)int chandev_use_devno_names=FALSE;#endifstatic int chandev_cautious_auto_detect=TRUE;static atomic_t chandev_conf_read=ATOMIC_INIT(FALSE);static atomic_t chandev_initialised=ATOMIC_INIT(FALSE);static unsigned long chandev_last_machine_check;static struct tq_struct chandev_msck_task_tq;static atomic_t chandev_msck_thread_lock;static atomic_t chandev_new_msck;static unsigned long chandev_last_startmsck_list_update;typedef enum{	chandev_start,	chandev_first_tag=chandev_start,	chandev_msck,	chandev_num_notify_tags} chandev_userland_notify_tag;static char *userland_notify_strs[]={	"start",	"machine_check"};typedef struct chandev_userland_notify_list chandev_userland_notify_list;struct chandev_userland_notify_list{	chandev_userland_notify_list    *next;	chandev_userland_notify_tag      tag;	chandev_msck_status              prev_status;	chandev_msck_status              curr_status;	char                      devname[0];};static chandev_userland_notify_list *chandev_userland_notify_head=NULL;static void chandev_read_conf_if_necessary(void);static void chandev_read_conf(void);#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)typedef struct net_device  net_device;#elsetypedef struct device  net_device;static inline void init_waitqueue_head(wait_queue_head_t *q){	*q=NULL;}#endif#if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,45)static __inline__ void netif_stop_queue(net_device *dev){	dev->tbusy=1;}static __inline__ void netif_start_queue(net_device *dev){	dev->tbusy=0;}#endif#define CHANDEV_INVALID_LOCK_OWNER            -1static long                 chandev_lock_owner;static int                  chandev_lock_cnt; static spinlock_t           chandev_spinlock;#define CHANDEV_LOCK_DEBUG 0#if CHANDEV_LOCK_DEBUG && !defined(CONFIG_ARCH_S390X)#define CHANDEV_BACKTRACE_LOOPCNT 10void                        *chandev_first_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],	                    *chandev_last_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],	                    *chandev_last_unlock_addr[CHANDEV_BACKTRACE_LOOPCNT];#define CHANDEV_BACKTRACE(variable) \memset((variable),0,sizeof(void *)*CHANDEV_BACKTRACE_LOOPCNT); \(variable)[0]=__builtin_return_address(0); \if(((long)variable[0])&0x80000000)         \{                                          \(variable)[1]=__builtin_return_address(1); \if(((long)variable[1])&0x80000000)         \{                                          \(variable)[2]=__builtin_return_address(2); \if(((long)variable[2])&0x80000000)         \{                                          \(variable)[3]=__builtin_return_address(3); \if(((long)variable[3])&0x80000000)         \{                                          \(variable)[4]=__builtin_return_address(4); \if(((long)variable[4])&0x80000000)         \{                                          \(variable)[5]=__builtin_return_address(5); \if(((long)variable[5])&0x80000000)         \{                                          \(variable)[6]=__builtin_return_address(6); \if(((long)variable[6])&0x80000000)         \{                                          \(variable)[7]=__builtin_return_address(7); \if(((long)variable[7])&0x80000000)         \{                                          \(variable)[8]=__builtin_return_address(8); \if(((long)variable[8])&0x80000000)         \{                                          \(variable)[9]=__builtin_return_address(9); \} \} \} \} \} \} \} \} \}#else#define CHANDEV_BACKTRACE(variable)#endiftypedef struct chandev_not_oper_struct chandev_not_oper_struct;struct  chandev_not_oper_struct{	chandev_not_oper_struct *next;	int irq;	int status;};/* May as well try to keep machine checks in the order they happen so * we use qheader for chandev_not_oper_head instead of list. */static qheader chandev_not_oper_head={NULL,NULL};static spinlock_t           chandev_not_oper_spinlock;#define chandev_interrupt_check() \if(in_interrupt())                \     printk(KERN_WARNING __FUNCTION__ " called under interrupt this shouldn't happen\n")#define for_each(variable,head) \for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)#define for_each_allow_delete(variable,nextmember,head) \for((variable)=(head),(nextmember)=((head) ? (head)->next:NULL); \(variable)!=NULL; (variable)=(nextmember),(nextmember)=((nextmember) ? (nextmember->next) : NULL))#define for_each_allow_delete2(variable,nextmember,head) \for((variable)=(head);(variable)!=NULL;(variable)=(nextmember))static void chandev_lock(void){	eieio();	chandev_interrupt_check();	if(chandev_lock_owner!=(long)current)	{		while(!spin_trylock(&chandev_spinlock))			schedule();		chandev_lock_cnt=1;		chandev_lock_owner=(long)current;		CHANDEV_BACKTRACE(chandev_first_lock_addr)	}	else	{		chandev_lock_cnt++;		CHANDEV_BACKTRACE(chandev_last_lock_addr)	}	if(chandev_lock_cnt<0||chandev_lock_cnt>100)	{		printk("odd lock_cnt %d lcs_chan_lock",chandev_lock_cnt);		chandev_lock_cnt=1;	}}static int chandev_full_unlock(void){	int ret_lock_cnt=chandev_lock_cnt;	chandev_lock_cnt=0;	chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;	spin_unlock(&chandev_spinlock);	return(ret_lock_cnt);}static void chandev_unlock(void){	if(chandev_lock_owner!=(long)current)		printk("chandev_unlock: current=%lx"		      " chandev_lock_owner=%lx chandev_lock_cnt=%d\n",		      (long)current,		      chandev_lock_owner,		      chandev_lock_cnt);	CHANDEV_BACKTRACE(chandev_last_unlock_addr)	if(--chandev_lock_cnt==0)	{		chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;		spin_unlock(&chandev_spinlock);	}	if(chandev_lock_cnt<0)	{		printk("odd lock_cnt=%d in chan_unlock",chandev_lock_cnt);		chandev_full_unlock();	}}void *chandev_alloc(size_t size){	void *mem=kmalloc(size,GFP_ATOMIC);	if(mem)		memset(mem,0,size);	return(mem);}static void chandev_add_to_list(list **listhead,void *member){	chandev_lock();	add_to_list(listhead,member);	chandev_unlock();}static void chandev_queuemember(qheader *qhead,void *member){	chandev_lock();	enqueue_tail(qhead,(queue *)member);	chandev_unlock();}static int chandev_remove_from_list(list **listhead,list *member){	int retval;	chandev_lock();	retval=remove_from_list(listhead,member);	chandev_unlock();	return(retval);}static int chandev_remove_from_queue(qheader *qhead,queue *member){	int retval;		chandev_lock();	retval=remove_from_queue(qhead,member);	chandev_unlock();	return(retval);}void chandev_free_listmember(list **listhead,list *member){	chandev_lock();	if(member)	{		if(chandev_remove_from_list(listhead,member))			kfree(member);		else			printk(KERN_CRIT"chandev_free_listmember detected nonexistant"			       "listmember listhead=%p member %p\n",listhead,member);	}	chandev_unlock();}void chandev_free_queuemember(qheader *qhead,queue *member){	chandev_lock();	if(member)	{		if(chandev_remove_from_queue(qhead,member))			kfree(member);		else			printk(KERN_CRIT"chandev_free_queuemember detected nonexistant"			       "queuemember qhead=%p member %p\n",qhead,member);	}	chandev_unlock();}void chandev_free_all_list(list **listhead){	list *head;	chandev_lock();	while((head=remove_listhead(listhead)))		kfree(head);	chandev_unlock();}void chandev_free_all_queue(qheader *qhead){	chandev_lock();	while(qhead->head)		chandev_free_queuemember(qhead,qhead->head);	chandev_unlock();}

⌨️ 快捷键说明

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