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

📄 brlvger.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *      Tieman Voyager braille display USB driver. * *      Copyright 2001-2002 Stephane Dalton <sdalton@videotron.ca> *                      and St閜hane Doyon  <s.doyon@videotron.ca> *            Maintained by St閜hane Doyon  <s.doyon@videotron.ca>. *//* *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *//* History: * 0.8 April 2002: Integration into the kernel tree. * 0.7 October 2001: First public release as a module, distributed with *     the BRLTTY package (beta versions around 2.99y). */#define DRIVER_VERSION "v0.8"#define DATE "April 2002"#define DRIVER_AUTHOR \	"Stephane Dalton <sdalton@videotron.ca> " \	"and St閜hane Doyon <s.doyon@videotron.ca>"#define DRIVER_DESC "Tieman Voyager braille display USB driver for Linux 2.4"#define DRIVER_SHORTDESC "Voyager"#define BANNER \	KERN_INFO DRIVER_SHORTDESC " " DRIVER_VERSION " (" DATE ")\n" \	KERN_INFO "   by " DRIVER_AUTHOR "\n"static const char longbanner[] = {	DRIVER_DESC ", " DRIVER_VERSION " (" DATE "), by " DRIVER_AUTHOR};#include <linux/module.h>#include <linux/usb.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/sched.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <linux/poll.h>#include <linux/devfs_fs_kernel.h>#include <linux/brlvger.h>MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");/* Module parameters */static int debug = 1;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "Debug level, 0-3");static int write_repeats = 2;MODULE_PARM(write_repeats, "i");MODULE_PARM_DESC(write_repeats, "Hack: repetitions for command to "		 "display braille pattern");		 /* to get rid of weird extra dots (perhaps only on		    early hardware versions?) */static int stall_tries = 3;MODULE_PARM(stall_tries, "i");MODULE_PARM_DESC(stall_tries, "Hack: retransmits of stalled USB "		 "control messages");                 /* broken early hardware versions? */#define BRLVGER_RAW_VOLTAGE 89/* from 0->300V to 255->200V, we are told 265V is normal operating voltage,   but we don't know the scale. Assuming it is linear. */static int raw_voltage = BRLVGER_RAW_VOLTAGE;MODULE_PARM(raw_voltage, "i");MODULE_PARM_DESC(raw_voltage, "Parameter for the call to SET_DISPLAY_VOLTAGE");/* protocol and display type defines */#define MAX_BRLVGER_CELLS 72#define MAX_INTERRUPT_DATA 8/* control message request types */#define BRLVGER_READ_REQ 0xC2#define BRLVGER_WRITE_REQ 0x42/* control message request codes */#define BRLVGER_SET_DISPLAY_ON 0#define BRLVGER_SET_DISPLAY_VOLTAGE 1#define BRLVGER_GET_SERIAL 3#define BRLVGER_GET_HWVERSION 4#define BRLVGER_GET_FWVERSION 5#define BRLVGER_GET_LENGTH 6#define BRLVGER_SEND_BRAILLE 7#define BRLVGER_BEEP 9#if 0 /* not used and not sure they're working */#define BRLVGER_GET_DISPLAY_VOLTAGE 2#define BRLVGER_GET_CURRENT 8#endif/* Prototypes */static void *brlvger_probe (struct usb_device *dev, unsigned ifnum,			    const struct usb_device_id *id);static void brlvger_disconnect(struct usb_device *dev, void *ptr);static int brlvger_open(struct inode *inode, struct file *file);static int brlvger_release(struct inode *inode, struct file *file);static ssize_t brlvger_write(struct file *file, const char *buffer,			     size_t count, loff_t *pos);static ssize_t brlvger_read(struct file *file, char *buffer,			    size_t count, loff_t *unused_pos);static int brlvger_ioctl(struct inode *inode, struct file *file,			 unsigned cmd, unsigned long arg);static unsigned brlvger_poll(struct file *file, poll_table *wait);static loff_t brlvger_llseek(struct file * file, loff_t offset, int orig);static void intr_callback(struct urb *urb);struct brlvger_priv;static int brlvger_get_hw_version(struct brlvger_priv *priv,				  unsigned char *verbuf);static int brlvger_get_fw_version(struct brlvger_priv *priv,				  unsigned char *buf);static int brlvger_get_serial(struct brlvger_priv *priv,			      unsigned char *buf);static int brlvger_get_display_length(struct brlvger_priv *priv);static int brlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on);static int brlvger_beep(struct brlvger_priv *priv, __u16 duration);static int brlvger_set_display_voltage(struct brlvger_priv *priv,				       __u16 voltage);static int mycontrolmsg(const char *funcname,                        struct brlvger_priv *priv, unsigned pipe_dir,                        __u8 request, __u8 requesttype, __u16 value,                        __u16 index, void *data, __u16 size);#define controlmsg(priv,pipe_dir,a,b,c,d,e,f) \     mycontrolmsg(__FUNCTION__, priv, pipe_dir, \                  a,b,c,d,e,f)#define sndcontrolmsg(priv,a,b,c,d,e,f) \    controlmsg(priv, 0, a,b,c,d,e,f)#define rcvcontrolmsg(priv,a,b,c,d,e,f) \    controlmsg(priv, USB_DIR_IN, a,b,c,d,e,f)extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. *//* ----------------------------------------------------------------------- *//* Data *//* key event queue size */#define MAX_INTERRUPT_BUFFER 10/* private state */struct brlvger_priv {	struct usb_device   *dev; /* USB device handle */	struct usb_endpoint_descriptor *in_interrupt;	struct urb *intr_urb;	devfs_handle_t devfs;	int subminor; /* which minor dev #? */	unsigned char hwver[BRLVGER_HWVER_SIZE]; /* hardware version */	unsigned char fwver[BRLVGER_FWVER_SIZE]; /* firmware version */	unsigned char serialnum[BRLVGER_SERIAL_SIZE];	int llength; /* logical length */	int plength; /* physical length */	__u8 obuf[MAX_BRLVGER_CELLS];	__u8 intr_buff[MAX_INTERRUPT_DATA];	__u8 event_queue[MAX_INTERRUPT_BUFFER][MAX_INTERRUPT_DATA];	atomic_t intr_idx, read_idx;	spinlock_t intr_idx_lock; /* protects intr_idx */	wait_queue_head_t read_wait;	int opened;	struct semaphore open_sem; /* protects ->opened */	struct semaphore dev_sem; /* protects ->dev */};/* Globals *//* Table of connected devices, a different minor for each. */static struct brlvger_priv *display_table[ MAX_NR_BRLVGER_DEVS ];/* Mutex for the operation of removing a device from display_table */static DECLARE_MUTEX(disconnect_sem);/* For blocking open */static DECLARE_WAIT_QUEUE_HEAD(open_wait);/* Some print macros */#ifdef dbg#undef dbg#endif#ifdef info#undef info#endif#ifdef err#undef err#endif#define info(args...) \    ({ printk(KERN_INFO "Voyager: " args); \       printk("\n"); })#define err(args...) \    ({ printk(KERN_ERR "Voyager: " args); \       printk("\n"); })#define dbgprint(fmt, args...) \    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \       printk("\n"); })#define dbg(args...) \    ({ if(debug >= 1) dbgprint(args); })#define dbg2(args...) \    ({ if(debug >= 2) dbgprint(args); })#define dbg3(args...) \    ({ if(debug >= 3) dbgprint(args); })/* ----------------------------------------------------------------------- *//* Driver registration */static struct usb_device_id brlvger_ids [] = {	{ USB_DEVICE(0x0798, 0x0001) },	{ }                     /* Terminating entry */};MODULE_DEVICE_TABLE (usb, brlvger_ids);static struct file_operations brlvger_fops ={	owner:		THIS_MODULE,	llseek:		brlvger_llseek,	read:		brlvger_read,	write:		brlvger_write,	ioctl:		brlvger_ioctl,	open:		brlvger_open,	release:	brlvger_release,	poll:		brlvger_poll,};static struct usb_driver brlvger_driver ={	name:		"brlvger",	probe:		brlvger_probe,	disconnect:	brlvger_disconnect,	fops:		&brlvger_fops,	minor:		BRLVGER_MINOR,	id_table:	brlvger_ids,};static int__init brlvger_init (void){	printk(BANNER);	if(stall_tries < 1 || write_repeats < 1)	  return -EINVAL;	memset(display_table, 0, sizeof(display_table));	if (usb_register(&brlvger_driver)) {		err("USB registration failed");		return -ENOSYS;	}	return 0;}static void__exit brlvger_cleanup (void){	usb_deregister (&brlvger_driver);	dbg("Driver unregistered");}module_init (brlvger_init);module_exit (brlvger_cleanup);/* ----------------------------------------------------------------------- *//* Probe and disconnect functions */static void *brlvger_probe (struct usb_device *dev, unsigned ifnum,	       const struct usb_device_id *id){	struct brlvger_priv *priv = NULL;	int i;	struct usb_endpoint_descriptor *endpoint;	struct usb_interface_descriptor *actifsettings;	/* protects against reentrance: once we've found a free slot	   we reserve it.*/	static DECLARE_MUTEX(reserve_sem);        char devfs_name[16];	actifsettings = dev->actconfig->interface->altsetting;	if( dev->descriptor.bNumConfigurations != 1			|| dev->config->bNumInterfaces != 1 			|| actifsettings->bNumEndpoints != 1 ) {		err ("Bogus braille display config info");		return NULL;	}	endpoint = actifsettings->endpoint;	if (!(endpoint->bEndpointAddress & 0x80) ||		((endpoint->bmAttributes & 3) != 0x03)) {		err ("Bogus braille display config info, wrong endpoints");		return NULL;	}	down(&reserve_sem);	for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )		if( display_table[i] == NULL )			break;	if( i == MAX_NR_BRLVGER_DEVS ) {		err( "This driver cannot handle more than %d "				"braille displays", MAX_NR_BRLVGER_DEVS);		goto error;	}	if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){		err("No more memory");		goto error;	}	memset(priv, 0, sizeof(*priv));	atomic_set(&priv->intr_idx, 0);	atomic_set(&priv->read_idx, MAX_INTERRUPT_BUFFER-1);	spin_lock_init(&priv->intr_idx_lock);	init_waitqueue_head(&priv->read_wait);	/* opened is memset'ed to 0 */	init_MUTEX(&priv->open_sem);	init_MUTEX(&priv->dev_sem);	priv->subminor = i;	/* we found a interrupt in endpoint */	priv->in_interrupt = endpoint;	priv->dev = dev;	if(brlvger_get_hw_version(priv, priv->hwver) <0) {		err("Unable to get hardware version");		goto error;	}	dbg("Hw ver %d.%d", priv->hwver[0], priv->hwver[1]);	if(brlvger_get_fw_version(priv, priv->fwver) <0) {		err("Unable to get firmware version");		goto error;	}	dbg("Fw ver: %s", priv->fwver);	if(brlvger_get_serial(priv, priv->serialnum) <0) {		err("Unable to get serial number");		goto error;	}	dbg("Serial number: %s", priv->serialnum);	if( (priv->llength = brlvger_get_display_length(priv)) <0 ){		err("Unable to get display length");		goto error;	}	switch(priv->llength) {	case 48:		priv->plength = 44;		break;	case 72:		priv->plength = 70;		break;	default:		err("Unsupported display length: %d", priv->llength);		goto error;	};	dbg("Display length: %d", priv->plength);	sprintf(devfs_name, "brlvger%d", priv->subminor);	priv->devfs = devfs_register(usb_devfs_handle, devfs_name,				     DEVFS_FL_DEFAULT, USB_MAJOR,				     BRLVGER_MINOR+priv->subminor,				     S_IFCHR |S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP,				     &brlvger_fops, NULL);	if (!priv->devfs) {#ifdef CONFIG_DEVFS_FS		err("devfs node registration failed");#endif	}	display_table[i] = priv;	info( "Braille display %d is device major %d minor %d",				i, USB_MAJOR, BRLVGER_MINOR + i);	/* Tell anyone waiting on a blocking open */	wake_up_interruptible(&open_wait);	goto out; error:	if(priv) {		kfree( priv );		priv = NULL;	} out:	up(&reserve_sem);	return priv;}static voidbrlvger_disconnect(struct usb_device *dev, void *ptr){	struct brlvger_priv *priv = (struct brlvger_priv *)ptr;	int r;	if(priv){		info("Display %d disconnecting", priv->subminor);		devfs_unregister(priv->devfs);				down(&disconnect_sem);		display_table[priv->subminor] = NULL;		up(&disconnect_sem);		down(&priv->open_sem);		down(&priv->dev_sem);		if(priv->opened) {			/* Disable interrupts */			if((r = usb_unlink_urb(priv->intr_urb)) <0)				err("usb_unlink_urb returns %d", r);			usb_free_urb(priv->intr_urb);			/* mark device as dead and prevent control			   messages to it */			priv->dev = NULL;			/* Tell anyone hung up on a read that it			   won't be coming */			wake_up_interruptible(&priv->read_wait);			up(&priv->dev_sem);			up(&priv->open_sem);		}else			/* no corresponding up()s */			kfree(priv);	}}/* ----------------------------------------------------------------------- *//* fops implementation */static intbrlvger_open(struct inode *inode, struct file *file){	int devnum = MINOR (inode->i_rdev);	struct brlvger_priv *priv;	int n, ret;	if (devnum < BRLVGER_MINOR	    || devnum >= (BRLVGER_MINOR + MAX_NR_BRLVGER_DEVS))		return -ENXIO;	n = devnum - BRLVGER_MINOR;	MOD_INC_USE_COUNT;	do {		down(&disconnect_sem);		priv = display_table[n];				if(!priv) {			up(&disconnect_sem);			if (file->f_flags & O_NONBLOCK) {				dbg3("Failing non-blocking open: "				     "device %d not connected", n);				MOD_DEC_USE_COUNT;				return -EAGAIN;			}			/* Blocking open. One global wait queue will			   suffice. We wait until a device for the selected			   minor is connected. */			dbg2("Waiting for device %d to be connected", n);			ret = wait_event_interruptible(open_wait,						       display_table[n]						       != NULL);			if(ret) {				dbg2("Interrupted wait for device %d", n);				MOD_DEC_USE_COUNT;				return ret;			}		}	} while(!priv);	/* We grabbed an existing device. */	if(down_interruptible(&priv->open_sem))		return -ERESTARTSYS;	up(&disconnect_sem);	/* Only one process can open each device, no sharing. */	ret = -EBUSY;	if(priv->opened)		goto error;	dbg("Opening display %d", priv->subminor);	/* Setup interrupt handler for receiving key input */	priv->intr_urb = usb_alloc_urb(0);	if(!priv->intr_urb) {		err("Unable to allocate URB");		goto error;	}	FILL_INT_URB( priv->intr_urb, priv->dev,			usb_rcvintpipe(priv->dev,				       priv->in_interrupt->bEndpointAddress),			priv->intr_buff, sizeof(priv->intr_buff),			intr_callback, priv, priv->in_interrupt->bInterval);	if((ret = usb_submit_urb(priv->intr_urb)) <0){

⌨️ 快捷键说明

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