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

📄 comx-hw-mixcom.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
}static int MIXCOM_open(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw = ch->HW_privdata;	struct proc_dir_entry *procfile = ch->procdir->subdir;	unsigned long flags; 	int ret = -ENODEV;	if (!dev->base_addr || !dev->irq)		goto err_ret;	if(hw->channel==1) {		if(!TWIN(dev) || !(COMX_CHANNEL(TWIN(dev))->init_status & 		    IRQ_ALLOCATED)) {			printk(KERN_ERR "%s: channel 0 not yet initialized\n",dev->name);			ret = -EAGAIN;			goto err_ret;		}	}	/* Is our hw present at all ? Not checking for channel 0 if it is already 	   open */	if(hw->channel!=0 || !(ch->init_status & IRQ_ALLOCATED)) {		if (!request_region(dev->base_addr, MIXCOM_IO_EXTENT, dev->name)) {			ret = -EAGAIN;			goto err_ret;		}		if (mixcom_probe(dev)) {			ret = -ENODEV;			goto err_release_region;		}	}	if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {		if (request_irq(dev->irq, MIXCOM_interrupt, 0, 		    dev->name, (void *)dev)) {			printk(KERN_ERR "MIXCOM: unable to obtain irq %d\n", dev->irq);			ret = -EAGAIN;			goto err_release_region;		}	}	save_flags(flags); cli();	if(hw->channel==0 && !(ch->init_status & IRQ_ALLOCATED)) {		ch->init_status|=IRQ_ALLOCATED;		mixcom_board_on(dev);	}	mixcom_on(dev);	hw->status=inb(MIXCOM_BOARD_BASE(dev) + MIXCOM_STATUS_OFFSET);	if(hw->status != 0xff) {		printk(KERN_DEBUG "%s: board has status register, good\n", dev->name);		hw->card_has_status=1;	}	hw->txbusy = 0;	ch->init_status |= HW_OPEN;		if (rd_hscx(dev, HSCX_STAR) & HSCX_CTS) {		ch->line_status |= LINE_UP;	} else {		ch->line_status &= ~LINE_UP;	}	restore_flags(flags);	ch->LINE_status(dev, ch->line_status);	for (; procfile ; procfile = procfile->next) {		if (strcmp(procfile->name, FILENAME_IO) == 0 ||		    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||		    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||		    strcmp(procfile->name, FILENAME_IRQ) == 0) {			procfile->mode = S_IFREG |  0444;		}	}	return 0;	err_release_region:	release_region(dev->base_addr, MIXCOM_IO_EXTENT);err_ret:	return ret;}static int MIXCOM_close(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw = ch->HW_privdata;	struct proc_dir_entry *procfile = ch->procdir->subdir;	unsigned long flags;	save_flags(flags); cli();	mixcom_off(dev);	/* This is channel 0, twin is not open, we can safely turn off everything */	if(hw->channel==0 && (!(TWIN(dev)) || 	    !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN))) {		mixcom_board_off(dev);		free_irq(dev->irq, dev);		release_region(dev->base_addr, MIXCOM_IO_EXTENT);		ch->init_status &= ~IRQ_ALLOCATED;	}	/* This is channel 1, channel 0 has already been shutdown, we can release	   this one too */	if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) {		if(COMX_CHANNEL(TWIN(dev))->init_status & IRQ_ALLOCATED) {			mixcom_board_off(TWIN(dev));			free_irq(TWIN(dev)->irq, TWIN(dev));			release_region(TWIN(dev)->base_addr, MIXCOM_IO_EXTENT);			COMX_CHANNEL(TWIN(dev))->init_status &= ~IRQ_ALLOCATED;		}	}	/* the ioports for channel 1 can be safely released */	if(hw->channel==1) {		release_region(dev->base_addr, MIXCOM_IO_EXTENT);	}	restore_flags(flags);	/* If we don't hold any hardware open */	if(!(ch->init_status & IRQ_ALLOCATED)) {		for (; procfile ; procfile = procfile->next) {			if (strcmp(procfile->name, FILENAME_IO) == 0 ||			    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||			    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||			    strcmp(procfile->name, FILENAME_IRQ) == 0) {				procfile->mode = S_IFREG |  0644;			}		}	}	/* channel 0 was only waiting for us to close channel 1 	   close it completely */   	if(hw->channel==1 && !(COMX_CHANNEL(TWIN(dev))->init_status & HW_OPEN)) {		for (procfile=COMX_CHANNEL(TWIN(dev))->procdir->subdir; 		    procfile ; procfile = procfile->next) {			if (strcmp(procfile->name, FILENAME_IO) == 0 ||			    strcmp(procfile->name, FILENAME_CHANNEL) == 0 ||			    strcmp(procfile->name, FILENAME_CLOCK) == 0 ||			    strcmp(procfile->name, FILENAME_IRQ) == 0) {				procfile->mode = S_IFREG |  0644;			}		}	}		ch->init_status &= ~HW_OPEN;	return 0;}static int MIXCOM_statistics(struct net_device *dev,char *page){	struct comx_channel *ch = dev->priv;	// struct mixcom_privdata *hw = ch->HW_privdata;	int len = 0;	if(ch->init_status && IRQ_ALLOCATED) {		len += sprintf(page + len, "Mixcom board: hardware open\n");	}	return len;}static int MIXCOM_dump(struct net_device *dev) {	return 0;}static int mixcom_read_proc(char *page, char **start, off_t off, int count,	int *eof, void *data){	struct proc_dir_entry *file = (struct proc_dir_entry *)data;	struct net_device *dev = file->parent->data;	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw = ch->HW_privdata;	int len = 0;	if (strcmp(file->name, FILENAME_IO) == 0) {		len = sprintf(page, "0x%x\n", 			(unsigned int)MIXCOM_BOARD_BASE(dev));	} else if (strcmp(file->name, FILENAME_IRQ) == 0) {		len = sprintf(page, "%d\n", (unsigned int)dev->irq);	} else if (strcmp(file->name, FILENAME_CLOCK) == 0) {		if (hw->clock) len = sprintf(page, "%d\n", hw->clock);			else len = sprintf(page, "external\n");	} else if (strcmp(file->name, FILENAME_CHANNEL) == 0) {		len = sprintf(page, "%01d\n", hw->channel);	} else if (strcmp(file->name, FILENAME_TWIN) == 0) {		if (ch->twin) {			len = sprintf(page, "%s\n",ch->twin->name);		} else {			len = sprintf(page, "none\n");		}	} else {		printk(KERN_ERR "mixcom_read_proc: internal error, filename %s\n", file->name);		return -EBADF;	}	if (off >= len) {		*eof = 1;		return 0;	}	*start = page + off;	if (count >= len - off) *eof = 1;	return min_t(int, count, len - off);}static struct net_device *mixcom_twin_check(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct proc_dir_entry *procfile = ch->procdir->parent->subdir;	struct mixcom_privdata *hw = ch->HW_privdata;	struct net_device *twin;	struct comx_channel *ch_twin;	struct mixcom_privdata *hw_twin;	for ( ; procfile ; procfile = procfile->next) {		if(!S_ISDIR(procfile->mode)) continue;                        	twin = procfile->data;	        ch_twin = twin->priv;        	hw_twin = ch_twin->HW_privdata;	        if (twin != dev && dev->irq && dev->base_addr &&         	    dev->irq == twin->irq &&         	    ch->hardware == ch_twin->hardware &&		    dev->base_addr == twin->base_addr + 		    (1-2*hw->channel)*MIXCOM_CHANNEL_OFFSET &&		    hw->channel == (1 - hw_twin->channel)) {	        	if  (!TWIN(twin) || TWIN(twin)==dev) {	        		return twin;	        	}		}        }	return NULL;}static void setup_twin(struct net_device* dev) {	if(TWIN(dev) && TWIN(TWIN(dev))) {		TWIN(TWIN(dev))=NULL;	}	if ((TWIN(dev) = mixcom_twin_check(dev)) != NULL) {		if (TWIN(TWIN(dev)) && TWIN(TWIN(dev)) != dev) {			TWIN(dev)=NULL;		} else {			TWIN(TWIN(dev))=dev;		}	}	}static int mixcom_write_proc(struct file *file, const char *buffer,	u_long count, void *data){	struct proc_dir_entry *entry = (struct proc_dir_entry *)data;	struct net_device *dev = (struct net_device *)entry->parent->data;	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw = ch->HW_privdata;	char *page;	int value;	if (!(page = (char *)__get_free_page(GFP_KERNEL))) {		return -ENOMEM;	}	copy_from_user(page, buffer, count = min_t(unsigned long, count, PAGE_SIZE));	if (*(page + count - 1) == '\n') {		*(page + count - 1) = 0;	}	if (strcmp(entry->name, FILENAME_IO) == 0) {		value = simple_strtoul(page, NULL, 0);		if (value != 0x180 && value != 0x280 && value != 0x380) {			printk(KERN_ERR "MIXCOM: incorrect io address!\n");		} else {			dev->base_addr = MIXCOM_DEV_BASE(value,hw->channel);		}	} else if (strcmp(entry->name, FILENAME_IRQ) == 0) {		value = simple_strtoul(page, NULL, 0); 		if (value < 0 || value > 15 || mixcom_set_irq[value]==0xFF) {			printk(KERN_ERR "MIXCOM: incorrect irq value!\n");		} else {			dev->irq = value;			}	} else if (strcmp(entry->name, FILENAME_CLOCK) == 0) {		if (strncmp("ext", page, 3) == 0) {			hw->clock = 0;		} else {			int kbps;			kbps = simple_strtoul(page, NULL, 0);			if (!kbps) {				hw->clock = 0;			} else {				hw->clock = kbps;			}			if (hw->clock < 32 || hw->clock > 2000) {				hw->clock = 0;				printk(KERN_ERR "MIXCOM: invalid clock rate!\n");			}		}		if (ch->init_status & HW_OPEN && ch->HW_set_clock) {			ch->HW_set_clock(dev);		}	} else if (strcmp(entry->name, FILENAME_CHANNEL) == 0) {		value = simple_strtoul(page, NULL, 0);        	if (value > 2) {                	printk(KERN_ERR "Invalid channel number\n");	        } else {        		dev->base_addr+=(hw->channel - value) * MIXCOM_CHANNEL_OFFSET;	        	hw->channel = value;		}	        	} else {		printk(KERN_ERR "hw_read_proc: internal error, filename %s\n", 			entry->name);		return -EBADF;	}	setup_twin(dev);	free_page((unsigned long)page);	return count;}static int MIXCOM_init(struct net_device *dev) {	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw;	struct proc_dir_entry *new_file;	if ((ch->HW_privdata = kmalloc(sizeof(struct mixcom_privdata), 	    GFP_KERNEL)) == NULL) {	    	return -ENOMEM;	}	memset(hw = ch->HW_privdata, 0, sizeof(struct mixcom_privdata));	if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, 	    ch->procdir)) == NULL) {		goto cleanup_HW_privdata;	}	new_file->data = (void *)new_file;	new_file->read_proc = &mixcom_read_proc;	new_file->write_proc = &mixcom_write_proc;	new_file->nlink = 1;	if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, 	    ch->procdir)) == NULL) {	    	goto cleanup_filename_io;	}	new_file->data = (void *)new_file;	new_file->read_proc = &mixcom_read_proc;	new_file->write_proc = &mixcom_write_proc;	new_file->nlink = 1;#if 0	if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, 	    ch->procdir)) == NULL) {	    	return -EIO;	}	new_file->data = (void *)new_file;	new_file->read_proc = &mixcom_read_proc;	new_file->write_proc = &mixcom_write_proc;	new_file->nlink = 1;#endif	if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, 	    ch->procdir)) == NULL) {	    	goto cleanup_filename_irq;	}	new_file->data = (void *)new_file;	new_file->read_proc = &mixcom_read_proc;	new_file->write_proc = &mixcom_write_proc;	new_file->nlink = 1;	if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, 	    ch->procdir)) == NULL) {	    	goto cleanup_filename_channel;	}	new_file->data = (void *)new_file;	new_file->read_proc = &mixcom_read_proc;	new_file->write_proc = &mixcom_write_proc;	new_file->nlink = 1;	setup_twin(dev);	/* Fill in ch_struct hw specific pointers */	ch->HW_access_board = NULL;	ch->HW_release_board = NULL;	ch->HW_txe = MIXCOM_txe;	ch->HW_open = MIXCOM_open;	ch->HW_close = MIXCOM_close;	ch->HW_send_packet = MIXCOM_send_packet;	ch->HW_statistics = MIXCOM_statistics;	ch->HW_set_clock = NULL;	dev->base_addr = MIXCOM_DEV_BASE(MIXCOM_DEFAULT_IO,0);	dev->irq = MIXCOM_DEFAULT_IRQ;	MOD_INC_USE_COUNT;	return 0;cleanup_filename_channel:	remove_proc_entry(FILENAME_CHANNEL, ch->procdir);cleanup_filename_irq:	remove_proc_entry(FILENAME_IRQ, ch->procdir);cleanup_filename_io:	remove_proc_entry(FILENAME_IO, ch->procdir);cleanup_HW_privdata:	kfree(ch->HW_privdata);	return -EIO;}static int MIXCOM_exit(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct mixcom_privdata *hw = ch->HW_privdata;	if(hw->channel==0 && TWIN(dev)) {		return -EBUSY;	}	if(hw->channel==1 && TWIN(dev)) {		TWIN(TWIN(dev))=NULL;	}	kfree(ch->HW_privdata);	remove_proc_entry(FILENAME_IO, ch->procdir);	remove_proc_entry(FILENAME_IRQ, ch->procdir);#if 0	remove_proc_entry(FILENAME_CLOCK, ch->procdir);#endif	remove_proc_entry(FILENAME_CHANNEL, ch->procdir);	remove_proc_entry(FILENAME_TWIN, ch->procdir);	MOD_DEC_USE_COUNT;	return 0;}static struct comx_hardware mixcomhw = {	"mixcom",	VERSION,	MIXCOM_init, 	MIXCOM_exit,	MIXCOM_dump,	NULL};	/* Module management */#ifdef MODULE#define comx_hw_mixcom_init init_module#endifint __init comx_hw_mixcom_init(void){	return(comx_register_hardware(&mixcomhw));}#ifdef MODULEvoidcleanup_module(void){	comx_unregister_hardware("mixcom");}#endif

⌨️ 快捷键说明

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