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

📄 epca.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) 	{ /* A cud device has been opened */		if (ch->asyncflags & ASYNC_NORMAL_ACTIVE)			return -EBUSY;		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&		    (ch->asyncflags & ASYNC_SESSION_LOCKOUT) &&		    (ch->session != current->session))		    return -EBUSY;		if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&		    (ch->asyncflags & ASYNC_PGRP_LOCKOUT) &&		    (ch->pgrp != current->pgrp))		    return -EBUSY; 		ch->asyncflags |= ASYNC_CALLOUT_ACTIVE;		return 0;	} /* End a cud device has been opened */	if (filp->f_flags & O_NONBLOCK) 	{		/* ----------------------------------------------------------------- 	  	 If non-blocking mode is set, then make the check up front	  	 and then exit.		-------------------------------------------------------------------- */		if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE)			return -EBUSY;		ch->asyncflags |= ASYNC_NORMAL_ACTIVE;		return 0;	}	if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) 	{		if (ch->normal_termios.c_cflag & CLOCAL)			do_clocal = 1;	}	else 	{		if (tty->termios->c_cflag & CLOCAL)			do_clocal = 1;	}	   /* Block waiting for the carrier detect and the line to become free */		retval = 0;	add_wait_queue(&ch->open_wait, &wait);	save_flags(flags);	cli();	/* We dec count so that pc_close will know when to free things */	if (!tty_hung_up_p(filp))		ch->count--;	restore_flags(flags);	ch->blocked_open++;	while(1) 	{ /* Begin forever while  */		current->state = TASK_INTERRUPTIBLE;		if (tty_hung_up_p(filp) ||		    !(ch->asyncflags & ASYNC_INITIALIZED)) 		{			if (ch->asyncflags & ASYNC_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;				break;		}		if (!(ch->asyncflags & ASYNC_CLOSING) && 		    !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) &&			  (do_clocal || (ch->imodem & ch->dcd)))			break;		if (signal_pending(current)) 		{			retval = -ERESTARTSYS;			break;		}		/* ---------------------------------------------------------------			Allow someone else to be scheduled.  We will occasionaly go			through this loop until one of the above conditions change.			The below schedule call will allow other processes to enter and			prevent this loop from hogging the cpu.		------------------------------------------------------------------ */		schedule();	} /* End forever while  */	current->state = TASK_RUNNING;	remove_wait_queue(&ch->open_wait, &wait);	cli();	if (!tty_hung_up_p(filp))		ch->count++;	restore_flags(flags);	ch->blocked_open--;	if (retval)		return retval;	ch->asyncflags |= ASYNC_NORMAL_ACTIVE;	return 0;} /* End block_til_ready */	/* ------------------ Begin pc_open  ---------------------- */static int pc_open(struct tty_struct *tty, struct file * filp){ /* Begin pc_open */	struct channel *ch;	unsigned long flags;	int line, retval, boardnum;	volatile struct board_chan *bc;	volatile unsigned int head;	/* Nothing "real" happens in open of control device */	if (tty->driver.subtype == SERIAL_TYPE_INFO) 	{		return (0) ;	}	line = MINOR(tty->device) - tty->driver.minor_start;	if (line < 0 || line >= nbdevs) 	{		printk(KERN_ERR "<Error> - pc_open : line out of range in pc_open\n");		tty->driver_data = NULL;		return(-ENODEV);	}#ifdef MODULE	MOD_INC_USE_COUNT;#endif	ch = &digi_channels[line];	boardnum = ch->boardnum;	/* Check status of board configured in system.  */	/* -----------------------------------------------------------------		I check to see if the epca_setup routine detected an user error.  		It might be better to put this in pc_init, but for the moment it		goes here.	---------------------------------------------------------------------- */	if (invalid_lilo_config)	{		if (setup_error_code & INVALID_BOARD_TYPE)			printk(KERN_ERR "<Error> - pc_open: Invalid board type specified in LILO command\n");		if (setup_error_code & INVALID_NUM_PORTS)			printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");		if (setup_error_code & INVALID_MEM_BASE)			printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");		if (setup_error_code & INVALID_PORT_BASE)			printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");		if (setup_error_code & INVALID_BOARD_STATUS)			printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");		if (setup_error_code & INVALID_ALTPIN)			printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");		tty->driver_data = NULL;   /* Mark this device as 'down' */		return(-ENODEV);	}	if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) 	{		tty->driver_data = NULL;   /* Mark this device as 'down' */		return(-ENODEV);	}		if (( bc = ch->brdchan) == 0) 	{		tty->driver_data = NULL;		return(-ENODEV);	}	/* ------------------------------------------------------------------		Every time a channel is opened, increment a counter.  This is 		necessary because we do not wish to flush and shutdown the channel		until the last app holding the channel open, closes it.	 		--------------------------------------------------------------------- */	ch->count++;	/* ----------------------------------------------------------------		Set a kernel structures pointer to our local channel 		structure.  This way we can get to it when passed only		a tty struct.	------------------------------------------------------------------ */	tty->driver_data = ch;		/* ----------------------------------------------------------------		If this is the first time the channel has been opened, initialize		the tty->termios struct otherwise let pc_close handle it.	-------------------------------------------------------------------- */	/* Should this be here except for SPLIT termios ? */	if (ch->count == 1) 	{		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)			*tty->termios = ch->normal_termios;		else 			*tty->termios = ch->callout_termios;	}	ch->session = current->session;	ch->pgrp = current->pgrp;	save_flags(flags);	cli();	globalwinon(ch);	ch->statusflags = 0;	/* Save boards current modem status */	ch->imodem = bc->mstat;	/* ----------------------------------------------------------------	   Set receive head and tail ptrs to each other.  This indicates	   no data available to read.	----------------------------------------------------------------- */	head = bc->rin;	bc->rout = head;	/* Set the channels associated tty structure */	ch->tty = tty;	/* -----------------------------------------------------------------		The below routine generally sets up parity, baud, flow control 		issues, etc.... It effect both control flags and input flags.	-------------------------------------------------------------------- */	epcaparam(tty,ch);	ch->asyncflags |= ASYNC_INITIALIZED;	memoff(ch);	restore_flags(flags);	retval = block_til_ready(tty, filp, ch);	if (retval)	{		return retval;	}	/* -------------------------------------------------------------		Set this again in case a hangup set it to zero while this 		open() was waiting for the line...	--------------------------------------------------------------- */	ch->tty = tty;	save_flags(flags);	cli();	globalwinon(ch);	/* Enable Digi Data events */	bc->idata = 1;	memoff(ch);	restore_flags(flags);	return 0;} /* End pc_open */#ifdef MODULE/* -------------------- Begin init_module ---------------------- */int init_module(){ /* Begin init_module */	unsigned long	flags;	save_flags(flags);	cli();	pc_init();	restore_flags(flags);	return(0);} /* End init_module */#endif#ifdef MODULE/* -------------------- Begin cleanup_module  ---------------------- */void cleanup_module(){ /* Begin cleanup_module */	int               count, crd;	struct board_info *bd;	struct channel    *ch;	unsigned long     flags;	save_flags(flags);	cli();	timer_table[DIGI_TIMER].fn = 0;	if ((tty_unregister_driver(&pc_driver)) ||  	    (tty_unregister_driver(&pc_callout)))	{		printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");		restore_flags(flags);		return;	}	for (crd = 0; crd < num_cards; crd++) 	{ /* Begin for each card */		bd = &boards[crd];		if (!bd)		{ /* Begin sanity check */			printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");			return;		} /* End sanity check */		ch = card_ptr[crd]; 		for (count = 0; count < bd->numports; count++, ch++) 		{ /* Begin for each port */			if (ch) 			{				if (ch->tty)					tty_hangup(ch->tty);				kfree_s(ch->tmp_buf, ch->txbufsize);			}		} /* End for each port */	} /* End for each card */	restore_flags(flags);} /* End cleanup_module */#endif /* MODULE *//* ------------------ Begin pc_init  ---------------------- */int pc_init(void){ /* Begin pc_init */	/* ----------------------------------------------------------------		pc_init is called by the operating system during boot up prior to		any open calls being made.  In the older versions of Linux (Prior		to 2.0.0) an entry is made into tty_io.c.  A pointer to the last		memory location (from kernel space) used (kmem_start) is passed		to pc_init.  It is pc_inits responsibility to modify this value 		for any memory that the Digi driver might need and then return		this value to the operating system.  For example if the driver		wishes to allocate 1K of kernel memory, pc_init would return 		(kmem_start + 1024).  This memory (Between kmem_start and kmem_start		+ 1024) would then be available for use exclusively by the driver.  		In this case our driver does not allocate any of this kernel 		memory.	------------------------------------------------------------------*/	ulong flags, save_loops_per_sec; 	int crd;	struct board_info *bd;	unsigned char board_id = 0;	#ifdef ENABLE_PCI	int pci_boards_found, pci_count;	pci_count = 0;#endif /* ENABLE_PCI */	/* -----------------------------------------------------------------------		If epca_setup has not been ran by LILO set num_cards to defaults; copy		board structure defined by digiConfig into drivers board structure.		Note : If LILO has ran epca_setup then epca_setup will handle defining		num_cards as well as copying the data into the board structure.	-------------------------------------------------------------------------- */	if (!liloconfig)	{ /* Begin driver has been configured via. epcaconfig */		nbdevs = NBDEVS;		num_cards = NUMCARDS;		memcpy((void *)&boards, (void *)&static_boards,		       (sizeof(struct board_info) * NUMCARDS));	} /* End driver has been configured via. epcaconfig */	/* -----------------------------------------------------------------		Note : If lilo was used to configure the driver and the 		ignore epcaconfig option was choosen (digiepca=2) then 		nbdevs and num_cards will equal 0 at this point.  This is		okay; PCI cards will still be picked up if detected.	--------------------------------------------------------------------- */	/*  -----------------------------------------------------------		Set up interrupt, we will worry about memory allocation in		post_fep_init. 	--------------------------------------------------------------- */	printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);#ifdef ENABLE_PCI	/* ------------------------------------------------------------------		NOTE : This code assumes that the number of ports found in 		       the boards array is correct.  This could be wrong if		       the card in question is PCI (And therefore has no ports 		       entry in the boards structure.)  The rest of the 		       information will be valid for PCI because the begining		       of pc_init scans for PCI and determines i/o and base		       memory addresses.  I am not sure if it is possible to 		       read the number of ports supported by the card prior to		       it being booted (Since that is the state it is in when 

⌨️ 快捷键说明

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