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

📄 serproto.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * serial_fd/serproto.h * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/config.h>#include <linux/module.h>#ifndef MODULE#undef GET_USE_COUNT#define GET_USE_COUNT(foo) 1#endif#include <linux/spinlock.h>#include <linux/list.h>#include <linux/init.h>#include <linux/poll.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/fcntl.h>#include <linux/termios.h>#include <linux/tty.h>#include <linux/tty_driver.h>#include <linux/tty_flip.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include <asm/segment.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/system.h>#include "serproto.h"//#define        SERIAL_TTY_MAJOR         222#define        SERIAL_TTY_MAJOR         188	// re-use USB host tty dev number#define        SERIAL_TTY_MINORS         1static int serial_refcount;static struct tty_struct *serial_tty[SERIAL_TTY_MINORS];static struct termios *serial_termios[SERIAL_TTY_MINORS];static struct termios *serial_termios_locked[SERIAL_TTY_MINORS];extern int usb;#define        MIN(a,b) ((a>b) ? b : a)#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endifstruct serproto_dev {	int number;		// serial device number (index in serproto_device_array)	int opencnt;		// number of opens	int connected;		// TRUE if USB has connected.	unsigned int clocal;	struct tq_struct write_wakeup_task;	// task queue for line discipline waking up	struct tty_struct *tty;	// serial tty structure	struct tty_driver tty_driver;	int (*xmit_data) (int, unsigned char *, int);	// callback to send data	int tx_size;		// maximum transmit size	rwlock_t rwlock;	// lock changing this structure	//static DECLARE_MUTEX_LOCKED(busy);// semaphore to wait if busy	unsigned int max_queue_entries;	// maximum queue entries	unsigned int max_queue_bytes;	// maximum queued data	unsigned int queued_entries;	// current queued entries	unsigned int queued_bytes;	// current queued data	int blocked;	int trailer;};int serproto_devices;		// maximum number of interaces static struct serproto_dev **serproto_device_array;	// pointer to active interacesstatic rwlock_t serproto_rwlock = RW_LOCK_UNLOCKED;	// lock for changing global structures/* Debug switches ****************************************************************************** */static int dbgflg_init = 0;static int dbgflg_oc = 0;static int dbgflg_rx = 0;static int dbgflg_tx = 0;static int dbgflg_mgmt = 0;static int dbgflg_loopback = 0;static debug_option dbg_table[] = {	{&dbgflg_init, NULL, "init", "initialization/termination handling"},	{&dbgflg_oc, NULL, "opcl", "open/close handling"},	{&dbgflg_rx, NULL, "rx", "receive (from host)"},	{&dbgflg_tx, NULL, "tx", "transmit (to host)"},	{&dbgflg_mgmt, NULL, "mgmt", "ioctl, termios, etc."},	{&dbgflg_loopback, NULL, "loop", "enable loopback if non-zero"},	{NULL, NULL, NULL, NULL}};#define dbg_init(lvl,fmt,args...) dbgPRINT(dbgflg_init,lvl,fmt,##args)#define dbg_oc(lvl,fmt,args...) dbgPRINT(dbgflg_oc,lvl,fmt,##args)#define dbg_rx(lvl,fmt,args...) dbgPRINT(dbgflg_rx,lvl,fmt,##args)#define dbg_tx(lvl,fmt,args...) dbgPRINT(dbgflg_tx,lvl,fmt,##args)#define dbg_mgmt(lvl,fmt,args...) dbgPRINT(dbgflg_mgmt,lvl,fmt,##args)#define dbg_loop(lvl,fmt,args...) dbgPRINT(dbgflg_loopback,lvl,fmt,##args)debug_option *serproto_get_dbg_table (void){	return (dbg_table);}/* Serial Driver Support Functions ************************************************************* *//* * * serial_open - open serial device * @tty: tty device * @filp: file structure * * Called to open serial device. */static int serial_open (struct tty_struct *tty, struct file *filp){	unsigned long flags;	int n = 0, rc = 0;	struct serproto_dev *device = NULL;	dbg_oc (3, "tty #%p file #%p", tty, filp);	if (NULL == tty || 0 > (n = MINOR (tty->device) - tty->driver.minor_start) ||	    n >= serproto_devices || NULL == (device = serproto_device_array[n])) {		dbg_oc (1, "FAIL ENODEV");		return -ENODEV;	}	MOD_INC_USE_COUNT;	dbg_init (1, "OPEN uc=%d", GET_USE_COUNT (THIS_MODULE));	write_lock_irqsave (&device->rwlock, flags);	if (1 == ++device->opencnt) {		// First open		tty->driver_data = device;		device->tty = tty;		tty->low_latency = 1;		/* force low_latency on so that our tty_push actually forces the data through, 		 * otherwise it is scheduled, and with high data rates (like with OHCI) data		 * can get lost. 		 * */		tty->low_latency = 1;	} else if (tty->driver_data != device || device->tty != tty) {		// Second or later open, different tty/device combo		rc = -EBUSY;	}	// XXX Should extract info from somewhere to see if receive is OK	write_unlock_irqrestore (&device->rwlock, flags);	if (0 != rc) {		if (-EBUSY == rc) {			dbg_oc (1, "2nd, conflict: old dev #%p new #%p, old tty #%p new #%p",				tty->driver_data, device, device->tty, tty);		}		MOD_DEC_USE_COUNT;		dbg_init (0, "OPEN rc=%d uc=%d", rc, GET_USE_COUNT (THIS_MODULE));	}	dbg_oc (3, "->%d n=%d", rc, n);	return (rc);}static void serial_close (struct tty_struct *tty, struct file *filp){	unsigned long flags;	struct serproto_dev *device;	int uc;	uc = GET_USE_COUNT (THIS_MODULE);	dbg_oc (3, "tty #%p file #%p uc=%d", tty, filp, uc);	if ((device = tty->driver_data) != NULL) {		write_lock_irqsave (&device->rwlock, flags);		if (0 >= --device->opencnt) {			// Last (or extra) close			dbg_oc (1, "Last: old tty #%p new #%p oc=%d",				device->tty, tty, device->opencnt);			tty->driver_data = NULL;			device->tty = NULL;			device->opencnt = 0;		}		write_unlock_irqrestore (&device->rwlock, flags);	} else {		dbg_oc (1, "not presently connected");	}	if (uc > 0) {		// Should really check that uc hasn't changed since start of fn...		MOD_DEC_USE_COUNT;		dbg_init (1, "CLOSE uc=%d", GET_USE_COUNT (THIS_MODULE));	}	dbg_oc (3, "OK");	return;}static void serial_flush (struct tty_struct *tty){	dbg_mgmt (1, "tty#%p", tty);}static int serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count){	// Return the number of bytes (out of count) that get written,	// or negative for error.	unsigned long flags;	struct serproto_dev *device;	int cnt = count;	int size;	const unsigned char *currpos = buf;	unsigned char *buffer;	dbg_tx (3, "count=%d", count);	if ((device = tty->driver_data) == NULL) {		dbg_tx (1, "not presently connected -> FAIL");		return -EINVAL;	}	dbgPRINTmem (dbgflg_tx, 4, buf, count);	// loop on data	while (cnt > 0) {		int length;		// send at most tx_size bytes		size = MIN (device->tx_size, cnt);		write_lock_irqsave (&device->rwlock, flags);		// Make sure we can send.		if (!device->connected ||		    (device->max_queue_entries > 0		     && (device->queued_entries >= device->max_queue_entries))		    || (device->queued_bytes >= device->max_queue_bytes)) {			// Can't write any more,			// return the number that we did manage to send.			write_unlock_irqrestore (&device->rwlock, flags);			dbg_tx (2, "->%d/%d", (count - cnt), count);			return (count - cnt);		}		size = MIN ((device->max_queue_bytes - device->queued_bytes), size);		// allocate a buffer		length = (device->blocked ? device->tx_size : size) + 1 + device->trailer;		dbg_tx (1, "------> blocked: %d tx_size: %d size: %d trailer: %d, length: %d",			device->blocked, device->tx_size, size, device->trailer, length);		if ((buffer = kmalloc (length, GFP_KERNEL)) == NULL) {			write_unlock_irqrestore (&device->rwlock, flags);			dbg_tx (2, "->ENOMEM");			return -ENOMEM;		}		memset (buffer, '\0', length);		// copy data		if (from_user) {			copy_from_user ((void *) buffer, currpos, size);		} else {			memcpy ((void *) buffer, currpos, size);		}		currpos += size;		cnt -= size;		device->xmit_data (device->number, buffer, size);		device->queued_entries++;		device->queued_bytes += size;		write_unlock_irqrestore (&device->rwlock, flags);	}	// Everything went out.	dbg_tx (5, "->%d (all)", count);	return count;}static int serial_write_room (struct tty_struct *tty){	/* Return the amount of room for writing. */	unsigned long flags;	struct serproto_dev *device;	int n = 0;	dbg_tx (7, "entered");	if ((device = tty->driver_data) == NULL) {		dbg_tx (1, "not presently connected -> FAIL");		return (-EINVAL);	}	read_lock_irqsave (&device->rwlock, flags);	if (device->connected &&	    (device->queued_bytes < device->max_queue_bytes) &&	    (device->max_queue_entries == 0	     || device->queued_entries < device->max_queue_entries)) {#if 0		if (device->tx_size < (n = device->max_queue_bytes - device->queued_bytes)) {			n = device->tx_size;		}#else		n = device->max_queue_bytes - device->queued_bytes;#endif	}	read_unlock_irqrestore (&device->rwlock, flags);	// Shouldn't really access these outside the lock, but only the dbg msg can go wrong.	dbg_tx (6, "c:%c b=%u/%u e=%u/%u -> %d", (device->connected ? 'T' : 'F'),		device->queued_bytes, device->max_queue_bytes,		device->queued_entries, device->max_queue_entries, n);	return (n);}static intserial_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){	int rc, type;	type = _IOC_TYPE (cmd);	dbg_mgmt (2, "type#%02x cmd#%08x arg#%08lx", type, cmd, arg);	switch (cmd) {	case /* TCSETATTR */ 3:		rc = 0;		break;	default:		rc = -ENOIOCTLCMD;	}	return (rc);}static void serial_set_termios (struct tty_struct *tty, struct termios *old){	struct serproto_dev *device = tty->driver_data;	struct termios *tio = tty->termios;	device->clocal = tio->c_cflag & CLOCAL;	dbg_mgmt (2, "clocal->%c", (device->clocal ? 'T' : 'F'));	return;}static void serial_throttle (struct tty_struct *tty){	dbg_mgmt (1, "entered");	return;}static void serial_unthrottle (struct tty_struct *tty){	dbg_mgmt (1, "entered");	return;}

⌨️ 快捷键说明

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