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

📄 brlvger.c

📁 ep9315平台下USB驱动的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		err("Error %d while submitting URB", ret);		goto error;	}	/* Set voltage */	if(brlvger_set_display_voltage(priv, raw_voltage) <0) {		err("Unable to set voltage");		goto error;	}	/* Turn display on */	if((ret = brlvger_set_display_on_off(priv, 1)) <0) {		err("Error %d while turning display on", ret);		goto error;	}	/* Mark as opened, so disconnect cannot free priv. */	priv->opened = 1;	file->private_data = priv;	ret = 0;	goto out; error:	MOD_DEC_USE_COUNT; out:	up(&priv->open_sem);	return ret;}static intbrlvger_release(struct inode *inode, struct file *file){	struct brlvger_priv *priv = file->private_data;	int r;	/* Turn display off. Safe even if disconnected. */	brlvger_set_display_on_off(priv, 0);	/* mutex with disconnect and with open */	down(&priv->open_sem);	if(!priv->dev) {		dbg("Releasing disconnected device %d", priv->subminor);		/* no up(&priv->open_sem) */		kfree(priv);	}else{		dbg("Closing display %d", priv->subminor);		/* Disable interrupts */		if((r = usb_unlink_urb(priv->intr_urb)) <0)			err("usb_unlink_urb returns %d", r);		usb_free_urb(priv->intr_urb);		priv->opened = 0;		up(&priv->open_sem);	}	MOD_DEC_USE_COUNT;	return 0;}static ssize_tbrlvger_write(struct file *file, const char *buffer,	      size_t count, loff_t *pos){	struct brlvger_priv *priv = file->private_data;	char buf[MAX_BRLVGER_CELLS];	int ret;	size_t rs;	loff_t off;	__u16 written;	if(!priv->dev)		return -ENOLINK;	off = *pos;	if(off > priv->plength)		return -ESPIPE;;	rs = priv->plength - off;	if(count > rs)		count = rs;	written = count;	if (copy_from_user (buf, buffer, count ) )		return -EFAULT;	memset(priv->obuf, 0xaa, sizeof(priv->obuf));	/* Firmware supports multiples of 8cells, so some cells are absent	   and for some reason there actually are holes! euurkkk! */	if( priv->plength == 44 ) {		/* Two ghost cells at the beginning of the display, plus		   two more after the sixth physical cell. */		if(off > 5) {			off +=4;			memcpy(priv->obuf, buf, count);		}else{			int firstpart = 6 - off;			#ifdef WRITE_DEBUG			dbg3("off: %d, rs: %d, count: %d, firstpart: %d",			     off, rs, count, firstpart);#endif			firstpart = (firstpart < count) ? firstpart : count;#ifdef WRITE_DEBUG			dbg3("off: %d", off);			dbg3("firstpart: %d", firstpart);#endif			memcpy(priv->obuf, buf, firstpart);			if(firstpart != count) {				int secondpart = count - firstpart;#ifdef WRITE_DEBUG				dbg3("secondpart: %d", secondpart);#endif				memcpy(priv->obuf+(firstpart+2),				       buf+firstpart, secondpart);				written +=2;			}			off +=2;#ifdef WRITE_DEBUG			dbg3("off: %d, rs: %d, count: %d, firstpart: %d, "				"written: %d", 	off, rs, count, firstpart, written);#endif		}	}else{		/* Two ghost cells at the beginningg of the display. */		memcpy(priv->obuf, buf, count);		off += 2;	}	{		int repeat = write_repeats;		/* Dirty hack: sometimes some of the dots are wrong and somehow		   right themselves if the command is repeated. */		while(repeat--) {			ret = sndcontrolmsg(priv,				BRLVGER_SEND_BRAILLE, BRLVGER_WRITE_REQ, 0,				off, priv->obuf, written);			if(ret <0)				return ret;		}	}	return count;}static intread_index(struct brlvger_priv *priv){	int intr_idx, read_idx;	read_idx = atomic_read(&priv->read_idx);	read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;	intr_idx = atomic_read(&priv->intr_idx);	return(read_idx == intr_idx ? -1 : read_idx);}static ssize_tbrlvger_read(struct file *file, char *buffer,	     size_t count, loff_t *unused_pos){	struct brlvger_priv *priv = file->private_data;	int read_idx;	if(count != MAX_INTERRUPT_DATA)		return -EINVAL;	if(!priv->dev)		return -ENOLINK;	if((read_idx = read_index(priv)) == -1) {		/* queue empty */		if (file->f_flags & O_NONBLOCK)			return -EAGAIN;		else{			int r = wait_event_interruptible(priv->read_wait,							 (!priv->dev || (read_idx = read_index(priv)) != -1));			if(!priv->dev)				return -ENOLINK;			if(r)				return r;			if(read_idx == -1)				/* should not happen */				return 0;		}	}	if (copy_to_user (buffer, priv->event_queue[read_idx], count) )		return( -EFAULT);	atomic_set(&priv->read_idx, read_idx);	/* Multiple opens are not allowed. Yet on SMP, two processes could	   read at the same time (on a shared file descriptor); then it is not	   deterministic whether or not they will get duplicates of a key	   event. */	return MAX_INTERRUPT_DATA;}static intbrlvger_ioctl(struct inode *inode, struct file *file,	      unsigned cmd, unsigned long arg){	struct brlvger_priv *priv = file->private_data;	if(!priv->dev)		return -ENOLINK;	switch(cmd) {	case BRLVGER_GET_INFO: {		struct brlvger_info vi;		strncpy(vi.driver_version, DRIVER_VERSION,			sizeof(vi.driver_version));		vi.driver_version[sizeof(vi.driver_version)-1] = 0;		strncpy(vi.driver_banner, longbanner,			sizeof(vi.driver_banner));		vi.driver_banner[sizeof(vi.driver_banner)-1] = 0;		vi.display_length = priv->plength;				memcpy(&vi.hwver, priv->hwver, BRLVGER_HWVER_SIZE);		memcpy(&vi.fwver, priv->fwver, BRLVGER_FWVER_SIZE);		memcpy(&vi.serialnum, priv->serialnum, BRLVGER_SERIAL_SIZE);		if(copy_to_user((void *)arg, &vi, sizeof(vi)))			return -EFAULT;		return 0;	}	case BRLVGER_DISPLAY_ON:		return brlvger_set_display_on_off(priv, 1);	case BRLVGER_DISPLAY_OFF:		return brlvger_set_display_on_off(priv, 0);	case BRLVGER_BUZZ: {		__u16 duration;		if(get_user(duration, (__u16 *)arg))			return -EFAULT;		return brlvger_beep(priv, duration);	}#if 0 /* Underlying commands don't seem to work for some reason; not clear if	 we'd want to export these anyway. */	case BRLVGER_SET_VOLTAGE: {		__u16 voltage;		if(get_user(voltage, (__u16 *)arg))			return -EFAULT;		return brlvger_set_display_voltage(priv, voltage);	}	case BRLVGER_GET_VOLTAGE: {		__u8 voltage;		int r = brlvger_get_display_voltage(priv);		if(r <0)			return r;		voltage = r;		if(put_user(voltage, (__u8 *)arg))			return -EFAULT;		return 0;	}#endif	default:		return -EINVAL;	};}static loff_tbrlvger_llseek(struct file *file, loff_t offset, int orig){	struct brlvger_priv *priv = file->private_data;	if(!priv->dev)		return -ENOLINK;	switch (orig) {		case 0:			/*  nothing to do */			break;		case 1:			offset +=file->f_pos;			break;		case 2:			offset += priv->plength;		default:			return -EINVAL;	}	if((offset >= priv->plength) || (offset < 0))		return -EINVAL;	return (file->f_pos = offset);}static unsignedbrlvger_poll(struct file *file, poll_table *wait) {	struct brlvger_priv *priv = file->private_data;	if(!priv->dev)		return POLLERR | POLLHUP;	poll_wait(file, &priv->read_wait, wait);	if(!priv->dev)		return POLLERR | POLLHUP;	if(read_index(priv) != -1)		return POLLIN | POLLRDNORM;	return 0;}static voidintr_callback(struct urb *urb){	struct brlvger_priv *priv = urb->context;	int intr_idx, read_idx;	if( urb->status ) {		if(urb->status == -ETIMEDOUT)			dbg2("Status -ETIMEDOUT, "			     "probably disconnected");		else if(urb->status != -ENOENT)			err("Status: %d", urb->status);		return;	}	read_idx = atomic_read(&priv->read_idx);	spin_lock(&priv->intr_idx_lock);	intr_idx = atomic_read(&priv->intr_idx);	if(read_idx == intr_idx) {		dbg2("Queue full, dropping braille display input");		spin_unlock(&priv->intr_idx_lock);		return;	/* queue full */	}	memcpy(priv->event_queue[intr_idx], urb->transfer_buffer,	       MAX_INTERRUPT_DATA);	intr_idx = (++intr_idx == MAX_INTERRUPT_BUFFER)? 0 : intr_idx;	atomic_set(&priv->intr_idx, intr_idx);	spin_unlock(&priv->intr_idx_lock);	wake_up_interruptible(&priv->read_wait);}/* ----------------------------------------------------------------------- *//* Hardware access functions */static intmycontrolmsg(const char *funcname,	     struct brlvger_priv *priv, unsigned pipe_dir,	     __u8 request, __u8 requesttype, __u16 value,	     __u16 index, void *data, __u16 size){	int ret=0, tries = stall_tries;	/* Make sure the device was not disconnected */	if(down_interruptible(&priv->dev_sem))		return -ERESTARTSYS;	if(!priv->dev) {		up(&priv->dev_sem);		return -ENOLINK;	}	/* Dirty hack for retransmission: stalls and fails all the time	   without this on the hardware we tested. */	while(tries--) {		ret = usb_control_msg(priv->dev,		    usb_sndctrlpipe(priv->dev,0) |pipe_dir,		    request, requesttype, value,		    index, data, size,		    HZ);		if(ret != -EPIPE)			break;		dbg2("Stalled, remaining %d tries", tries);	}	up(&priv->dev_sem);	if(ret <0) {		err("%s: usb_control_msg returns %d",				funcname, ret);		return -EIO;	}	return 0;}static intbrlvger_get_hw_version(struct brlvger_priv *priv, unsigned char *verbuf){	return rcvcontrolmsg(priv,	    BRLVGER_GET_HWVERSION, BRLVGER_READ_REQ, 0,	    0, verbuf, BRLVGER_HWVER_SIZE);	/* verbuf should be 2 bytes */}static intbrlvger_get_fw_version(struct brlvger_priv *priv, unsigned char *buf){	unsigned char rawbuf[(BRLVGER_FWVER_SIZE-1)*2+2];	int i, len;	int r = rcvcontrolmsg(priv,			      BRLVGER_GET_FWVERSION, BRLVGER_READ_REQ, 0,			      0, rawbuf, sizeof(rawbuf));	if(r<0)		return r;	/* If I guess correctly: succession of 16bit words, the string is           formed of the first byte of each of these words. First byte in           buffer indicates total length of data; not sure what second byte is           for. */	len = rawbuf[0]-2;	if(len<0)		len = 0;	else if(len+1 > BRLVGER_FWVER_SIZE)		len = BRLVGER_FWVER_SIZE-1;	for(i=0; i<len; i++)		buf[i] = rawbuf[2+2*i];	buf[i] = 0;	return 0;}static intbrlvger_get_serial(struct brlvger_priv *priv, unsigned char *buf){	unsigned char rawserial[BRLVGER_SERIAL_BIN_SIZE];	int i;	int r = rcvcontrolmsg(priv,			      BRLVGER_GET_SERIAL, BRLVGER_READ_REQ, 0,			      0, rawserial, sizeof(rawserial));	if(r<0)		return r;	for(i=0; i<BRLVGER_SERIAL_BIN_SIZE; i++) {#define NUM_TO_HEX(n) (((n)>9) ? (n)+'A' : (n)+'0')		buf[2*i] = NUM_TO_HEX(rawserial[i] >>4);		buf[2*i+1] = NUM_TO_HEX(rawserial[i] &0xf);	}	buf[2*i] = 0;	return 0;}static intbrlvger_get_display_length(struct brlvger_priv *priv){	unsigned char data[2];	int ret = rcvcontrolmsg(priv,	    BRLVGER_GET_LENGTH, BRLVGER_READ_REQ, 0,	    0, data, 2);	if(ret<0)		return ret;	return data[1];}static intbrlvger_beep(struct brlvger_priv *priv, __u16 duration){	return sndcontrolmsg(priv,	    BRLVGER_BEEP, BRLVGER_WRITE_REQ, duration,	    0, NULL, 0);}static intbrlvger_set_display_on_off(struct brlvger_priv *priv, __u16 on){	dbg2("Turning display %s", ((on) ? "on" : "off"));	return sndcontrolmsg(priv,	    BRLVGER_SET_DISPLAY_ON,	BRLVGER_WRITE_REQ, on,	    0, NULL, 0);}static intbrlvger_set_display_voltage(struct brlvger_priv *priv, __u16 voltage){	dbg("SET_DISPLAY_VOLTAGE to %u", voltage);        return sndcontrolmsg(priv,	     BRLVGER_SET_DISPLAY_VOLTAGE, BRLVGER_WRITE_REQ, voltage,	     0, NULL, 0);}#if 0 /* Had problems testing these commands. Not particularly useful anyway.*/static intbrlvger_get_display_voltage(struct brlvger_priv *priv){	__u8 voltage = 0;	int ret = rcvcontrolmsg(priv,	    BRLVGER_GET_DISPLAY_VOLTAGE, BRLVGER_READ_REQ, 0,	    0, &voltage, 1);	if(ret<0)		return ret;	return voltage;}static intbrlvger_get_current(struct brlvger_priv *priv){	unsigned char data;	int ret = rcvcontrolmsg(priv,	    BRLVGER_GET_CURRENT,	BRLVGER_READ_REQ,	0,	    0, &data, 1);	if(ret<0)		return ret;	return data;}#endif

⌨️ 快捷键说明

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