📄 chandev.c
字号:
/* * drivers/s390/misc/chandev.c * common channel device layer * * S390 version * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) */#define __KERNEL_SYSCALLS__#include <linux/config.h>#include <linux/types.h>#include <linux/ctype.h>#include <asm/queue.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>static chandev_model_info *chandev_models_head=NULL;static chandev *chandev_head=NULL;static chandev_noauto_range *chandev_noauto_head=NULL;static chandev_force *chandev_force_head=NULL;static chandev_probelist *chandev_probelist_head=NULL;static int use_devno_names=FALSE;static int chandev_conf_read=FALSE;static void *chandev_alloc_listmember(list **listhead,size_t size){ void *newmember=kmalloc(size, GFP_KERNEL); if(newmember) add_to_list(listhead,newmember); return(newmember);}void chandev_free_listmember(list **listhead,list *member){ if(remove_from_list(listhead,member)) kfree(member); else printk(KERN_CRIT"chandev_free_listmember detected nonexistant" "listmember listhead=%p member %p\n",listhead,member);}void chandev_free_all(list **listhead){ while(*listhead) chandev_free_listmember(listhead,*listhead);}void chandev_add_model(chandev_type chan_type,u16 cu_type,u8 cu_model,u8 max_port_no){ chandev_model_info *newmodel; if((newmodel=chandev_alloc_listmember( (list **)&chandev_models_head,sizeof(chandev_model_info)))) { newmodel->chan_type=chan_type; newmodel->cu_type=cu_type; newmodel->cu_model=cu_model; newmodel->max_port_no=max_port_no; }}void chandev_remove(chandev *member){ chandev_free_listmember((list **)&chandev_head,(list *)member);}void chandev_remove_all(void){ chandev_free_all((list **)&chandev_head);}void chandev_remove_model(chandev_model_info *model){ chandev *curr_chandev; for(curr_chandev=chandev_head;curr_chandev!=NULL; curr_chandev=curr_chandev->next) if(curr_chandev->model_info==model) chandev_remove(curr_chandev); chandev_free_listmember((list **)&chandev_models_head,(list *)model);}void chandev_remove_all_models(void){ while(chandev_models_head) chandev_remove_model(chandev_models_head);}void chandev_del_model(u16 cu_type,u8 cu_model){ chandev_model_info *curr_model; for(curr_model=chandev_models_head;curr_model!=NULL; curr_model=curr_model->next) if(curr_model->cu_type==cu_type&&curr_model->cu_model==cu_model) chandev_remove_model(curr_model); }static void chandev_init_default_models(void){ /* P390/Planter 3172 emulation assume maximum 16 to be safe. */ chandev_add_model(lcs,0x3088,0x1,15); /* 3172/2216 Paralell the 2216 allows 16 ports per card the */ /* the original 3172 only allows 4 we will assume the max of 16 */ chandev_add_model(lcs|ctc,0x3088,0x8,15); /* 3172/2216 Escon serial the 2216 allows 16 ports per card the */ /* the original 3172 only allows 4 we will assume the max of 16 */ chandev_add_model(lcs|escon,0x3088,0x1F,15); /* Only 2 ports allowed on OSA2 cards model 0x60 */ chandev_add_model(lcs,0x3088,0x60,1); /* Osa-D we currently aren't too emotionally involved with this */ chandev_add_model(osad,0x3088,0x62,0);}void chandev_add(dev_info_t *newdevinfo,chandev_model_info *newmodelinfo){ chandev *new_chandev; if((new_chandev=chandev_alloc_listmember( (list **)&chandev_head,sizeof(chandev)))) { new_chandev->model_info=newmodelinfo; new_chandev->devno=newdevinfo->devno; new_chandev->irq=newdevinfo->irq; }}void chandev_collect_devices(void){ int curr_irq,loopcnt=0,err; dev_info_t curr_devinfo; chandev_model_info *curr_model; for(curr_irq=get_irq_first();curr_irq>=0; curr_irq=get_irq_next(curr_irq)) { /* check read chandev * we had to do the cu_model check also because ctc devices * have the same cutype & after asking some people * the model numbers are given out pseudo randomly so * we can't just take a range of them also the dev_type & models are 0 */ loopcnt++; if(loopcnt>0x10000) { printk(KERN_ERR"chandev_collect_devices detected infinite loop bug in get_irq_next\n"); break; } if((err=get_dev_info_by_irq(curr_irq,&curr_devinfo))) { printk("chandev_collect_devices get_dev_info_by_irq reported err=%X on irq %d\n" "should not happen\n",err,curr_irq); continue; } for(curr_model=chandev_models_head;curr_model!=NULL; curr_model=curr_model->next) { if((curr_model->cu_type==curr_devinfo.sid_data.cu_type)&& (curr_model->cu_model==curr_devinfo.sid_data.cu_model) &&((curr_devinfo.status&DEVSTAT_DEVICE_OWNED)==0)) chandev_add(&curr_devinfo,curr_model); } }}void chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_devno,u16 write_devno,s16 port_no,u8 do_ip_checksumming,u8 use_hw_stats){ chandev_force *new_chandev_force; if((new_chandev_force=chandev_alloc_listmember( (list **)&chandev_force_head,sizeof(chandev_force)))) { new_chandev_force->chan_type=chan_type; new_chandev_force->devif_num=devif_num; new_chandev_force->read_devno=read_devno; new_chandev_force->write_devno=write_devno; new_chandev_force->port_no=port_no; new_chandev_force->do_ip_checksumming=do_ip_checksumming; new_chandev_force->use_hw_stats=use_hw_stats; }}void chandev_del_force(u16 read_devno){ chandev_force *curr_force; for(curr_force=chandev_force_head;curr_force!=NULL; curr_force=curr_force->next) { if(curr_force->read_devno==read_devno) chandev_free_listmember((list **)&chandev_force_head, (list *)curr_force); }}void chandev_pack_args(char *str){ char *newstr=str; while(*str) { if(isspace(*str)) str++; else *newstr++=*str++; } *newstr=0;}typedef enum{ isnull=0, isstr=1, isnum=2, iscomma=4,} chandev_strval;chandev_strval chandev_strcmp(char *teststr,char **str,long *endlong){ char *cur=*str; chandev_strval retval=isnull; int len=strlen(teststr); if(strncmp(teststr,*str,len)==0) { *str+=len; retval=isstr; *endlong=simple_strtol(cur,str,0); if(cur!=*str) retval|=isnum; if(**str==',') retval|=iscomma; } return(retval);}static char *argstrs[]={ "noauto", "lcs", "ctc", "escon", "del_force", "use_devno_names" "dont_use_devno_names", "add_model" "del_model" "del_all_models"};typedef enum{ stridx_mult=16, first_stridx=0, noauto_stridx=first_stridx, lcs_stridx, ctc_stridx, escon_stridx, del_force_stridx, use_devno_names_stridx, dont_use_devno_names_stridx, add_model_stridx, del_model_stridx, del_all_models_stridx, last_stridx,} chandev_str_enum;void chandev_add_noauto(u16 lo_devno,u16 hi_devno){ chandev_noauto_range *new_range; if((new_range=chandev_alloc_listmember( (list **)&chandev_noauto_head,sizeof(chandev_noauto_range)))) { new_range->lo_devno=lo_devno; new_range->hi_devno=hi_devno; }}static char chandev_keydescript[]="chan_type key bitfield\nctc=0x1,escon=0x2,lcs=0x4,lcs=0x4,osad=0x8,claw=0x16\n";static void chandev_print_args(void){ printk("valid chandev arguments are" "<> indicate optional parameters | indicate a choice.\n"); printk("noauto,<lo_devno>,<hi_devno>\n" "don't probe a range of device numbers for channel devices\n"); printk("lcs|ctc|escon<devif_num>,read_devno,write_devno,<port_no>," "<do_ip_checksumming>,<use_hw_stats>\n"); printk("e.g. ctc0,0x7c00,0x7c01,-1,0,0\n"); printk(" tells the channel layer to force ctc0 if detected to use\n" " cuu's 7c00 & 7c01 port ( rel adapter no ) is invalid for\n" " ctc's so use -1 don't do checksumming on received ip\n" " packets & as ctc doesn't have hardware stats ignore this\n" " parameter\n\n"); printk("del_force read_devno\n" "delete a forced channel device from force list.\n"); printk("use_devno_names, tells the channel layer to assign device\n" "names based on the read channel cuu number\n" "e.g. a token ring read channel 0x7c00 would have an interface" "called tr0x7c00 this avoids name collisions on devices."); printk("add_model chan_type cu_model max_port no\n" "tells the channel layer to probe for the device described\n"); printk("%s use max_port_no of 0 for devices where this field " "is invalid.\n",chandev_keydescript); printk("del_model cu_type cu_model\n"); printk("del_all_models\n");}static int chandev_setup(char *str){ chandev_strval val=isnull; chandev_str_enum stridx; long endlong; chandev_type chan_type;#define CHANDEV_MAX_EXTRA_INTS 5 int ints[CHANDEV_MAX_EXTRA_INTS+1]; memset(ints,0,sizeof(ints)); chandev_pack_args(str); for(stridx=first_stridx;stridx<last_stridx;stridx++) if((val=chandev_strcmp(argstrs[stridx],&str,&endlong))) break; if(val) { if(val&iscomma) get_options(str,CHANDEV_MAX_EXTRA_INTS,ints); else ints[0]=0; val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr); switch(val) { case noauto_stridx*stridx_mult: case (noauto_stridx*stridx_mult)|iscomma: switch(ints[0]) { case 0: chandev_free_all((list **)&chandev_noauto_head); chandev_add_noauto(0,0xffff); break; case 1: ints[2]=ints[1]; case 2: chandev_add_noauto(ints[1],ints[2]); } break; case (ctc_stridx*stridx_mult)|isnum|iscomma: case (escon_stridx*stridx_mult)|isnum|iscomma: case (lcs_stridx*stridx_mult)|isnum|iscomma: switch(val) { case (ctc_stridx*stridx_mult)|isnum|iscomma: chan_type=ctc; break; case (escon_stridx*stridx_mult)|isnum|iscomma: chan_type=escon; break; case (lcs_stridx*stridx_mult)|isnum|iscomma: chan_type=lcs; break; default: goto BadArgs; } chandev_add_force(chan_type,endlong,ints[1],ints[2], ints[3],ints[4],ints[5]); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -