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

📄 uss720.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************//* *	uss720.c  --  USS720 USB Parport Cable. * *	Copyright (C) 1999, 2005 *	    Thomas Sailer (t.sailer@alumni.ethz.ch) * *	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. * *  Based on parport_pc.c * *  History: *   0.1  04.08.1999  Created *   0.2  07.08.1999  Some fixes mainly suggested by Tim Waugh *		      Interrupt handling currently disabled because *		      usb_request_irq crashes somewhere within ohci.c *		      for no apparent reason (that is for me, anyway) *		      ECP currently untested *   0.3  10.08.1999  fixing merge errors *   0.4  13.08.1999  Added Vendor/Product ID of Brad Hard's cable *   0.5  20.09.1999  usb_control_msg wrapper used *        Nov01.2000  usb_device_table support by Adam J. Richter *        08.04.2001  Identify version on module load.  gb *   0.6  02.09.2005  Fix "scheduling in interrupt" problem by making save/restore *                    context asynchronous * *//*****************************************************************************/#include <linux/module.h>#include <linux/socket.h>#include <linux/parport.h>#include <linux/init.h>#include <linux/usb.h>#include <linux/delay.h>#include <linux/completion.h>#include <linux/kref.h>/* * Version Information */#define DRIVER_VERSION "v0.6"#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"/* --------------------------------------------------------------------- */struct parport_uss720_private {	struct usb_device *usbdev;	struct parport *pp;	struct kref ref_count;	__u8 reg[7];  /* USB registers */	struct list_head asynclist;	spinlock_t asynclock;};struct uss720_async_request {	struct parport_uss720_private *priv;	struct kref ref_count;	struct list_head asynclist;	struct completion compl;	struct urb *urb;	struct usb_ctrlrequest dr;	__u8 reg[7];};/* --------------------------------------------------------------------- */static void destroy_priv(struct kref *kref){	struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);	usb_put_dev(priv->usbdev);	kfree(priv);	dbg("destroying priv datastructure");}static void destroy_async(struct kref *kref){	struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count);	struct parport_uss720_private *priv = rq->priv;	unsigned long flags;	if (likely(rq->urb))		usb_free_urb(rq->urb);	spin_lock_irqsave(&priv->asynclock, flags);	list_del_init(&rq->asynclist);	spin_unlock_irqrestore(&priv->asynclock, flags);	kfree(rq);	kref_put(&priv->ref_count, destroy_priv);}/* --------------------------------------------------------------------- */static void async_complete(struct urb *urb, struct pt_regs *ptregs){	struct uss720_async_request *rq;	struct parport *pp;	struct parport_uss720_private *priv;	rq = urb->context;	priv = rq->priv;	pp = priv->pp;	if (urb->status) {		err("async_complete: urb error %d", urb->status);	} else if (rq->dr.bRequest == 3) {		memcpy(priv->reg, rq->reg, sizeof(priv->reg));#if 0		dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",		    (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],		    (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],		    (unsigned int)priv->reg[6]);#endif		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */		if (rq->reg[2] & rq->reg[1] & 0x10 && pp)			parport_generic_irq(0, pp, NULL);	}	complete(&rq->compl);	kref_put(&rq->ref_count, destroy_async);}static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv,							 __u8 request, __u8 requesttype, __u16 value, __u16 index,							 gfp_t mem_flags){	struct usb_device *usbdev;	struct uss720_async_request *rq;	unsigned long flags;	int ret;	if (!priv)		return NULL;	usbdev = priv->usbdev;	if (!usbdev)		return NULL;	rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);	if (!rq) {		err("submit_async_request out of memory");		return NULL;	}	kref_init(&rq->ref_count);	INIT_LIST_HEAD(&rq->asynclist);	init_completion(&rq->compl);	kref_get(&priv->ref_count);	rq->priv = priv;	rq->urb = usb_alloc_urb(0, mem_flags);	if (!rq->urb) {		kref_put(&rq->ref_count, destroy_async);		err("submit_async_request out of memory");		return NULL;	}	rq->dr.bRequestType = requesttype;	rq->dr.bRequest = request;	rq->dr.wValue = cpu_to_le16(value);	rq->dr.wIndex = cpu_to_le16(index);	rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);	usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),			     (unsigned char *)&rq->dr,			     (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);	/* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */	spin_lock_irqsave(&priv->asynclock, flags);	list_add_tail(&rq->asynclist, &priv->asynclist);	spin_unlock_irqrestore(&priv->asynclock, flags);	ret = usb_submit_urb(rq->urb, mem_flags);	if (!ret) {		kref_get(&rq->ref_count);		return rq;	}	kref_put(&rq->ref_count, destroy_async);	err("submit_async_request submit_urb failed with %d", ret);	return NULL;}static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv){	struct uss720_async_request *rq;	unsigned long flags;	unsigned int ret = 0;	spin_lock_irqsave(&priv->asynclock, flags);	list_for_each_entry(rq, &priv->asynclist, asynclist) {		usb_unlink_urb(rq->urb);		ret++;	}	spin_unlock_irqrestore(&priv->asynclock, flags);	return ret;}/* --------------------------------------------------------------------- */static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags){	struct parport_uss720_private *priv;	struct uss720_async_request *rq;	static const unsigned char regindex[9] = {		4, 0, 1, 5, 5, 0, 2, 3, 6	};	int ret;	if (!pp)		return -EIO;	priv = pp->private_data;	rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);	if (!rq) {		err("get_1284_register(%u) failed", (unsigned int)reg);		return -EIO;	}	if (!val) {		kref_put(&rq->ref_count, destroy_async);		return 0;	}	if (wait_for_completion_timeout(&rq->compl, HZ)) {		ret = rq->urb->status;		*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];		if (ret)			warn("get_1284_register: usb error %d", ret);		kref_put(&rq->ref_count, destroy_async);		return ret;	}	warn("get_1284_register timeout");	kill_all_async_requests_priv(priv);	return -EIO;}static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags){	struct parport_uss720_private *priv;	struct uss720_async_request *rq;	if (!pp)		return -EIO;	priv = pp->private_data;	rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);	if (!rq) {		err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);		return -EIO;	}	kref_put(&rq->ref_count, destroy_async);	return 0;}/* --------------------------------------------------------------------- *//* ECR modes */#define ECR_SPP 00#define ECR_PS2 01#define ECR_PPF 02#define ECR_ECP 03#define ECR_EPP 04/* Safely change the mode bits in the ECR */static int change_mode(struct parport *pp, int m){	struct parport_uss720_private *priv = pp->private_data;	int mode;	__u8 reg;	if (get_1284_register(pp, 6, &reg, GFP_KERNEL))		return -EIO;	/* Bits <7:5> contain the mode. */	mode = (priv->reg[2] >> 5) & 0x7;	if (mode == m)		return 0;	/* We have to go through mode 000 or 001 */	if (mode > ECR_PS2 && m > ECR_PS2)		if (change_mode(pp, ECR_PS2))			return -EIO;	if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {		/* This mode resets the FIFO, so we may		 * have to wait for it to drain first. */		unsigned long expire = jiffies + pp->physport->cad->timeout;		switch (mode) {		case ECR_PPF: /* Parallel Port FIFO mode */		case ECR_ECP: /* ECP Parallel Port mode */			/* Poll slowly. */			for (;;) {				if (get_1284_register(pp, 6, &reg, GFP_KERNEL))					return -EIO;				if (priv->reg[2] & 0x01)					break;				if (time_after_eq (jiffies, expire))					/* The FIFO is stuck. */					return -EBUSY;				msleep_interruptible(10);				if (signal_pending (current))					break;			}		}	}	/* Set the mode. */	if (set_1284_register(pp, 6, m << 5, GFP_KERNEL))		return -EIO;	if (get_1284_register(pp, 6, &reg, GFP_KERNEL))		return -EIO;	return 0;}/* * Clear TIMEOUT BIT in EPP MODE */static int clear_epp_timeout(struct parport *pp){	unsigned char stat;	if (get_1284_register(pp, 1, &stat, GFP_KERNEL))		return 1;	return stat & 1;}/* * Access functions. */#if 0static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id){	struct parport *pp = (struct parport *)dev_id;	struct parport_uss720_private *priv = pp->private_data;		if (usbstatus != 0 || len < 4 || !buffer)		return 1;	memcpy(priv->reg, buffer, 4);	/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */	if (priv->reg[2] & priv->reg[1] & 0x10)		parport_generic_irq(0, pp, NULL);	return 1;}#endifstatic void parport_uss720_write_data(struct parport *pp, unsigned char d){	set_1284_register(pp, 0, d, GFP_KERNEL);}static unsigned char parport_uss720_read_data(struct parport *pp){	unsigned char ret;	if (get_1284_register(pp, 0, &ret, GFP_KERNEL))		return 0;	return ret;}static void parport_uss720_write_control(struct parport *pp, unsigned char d){	struct parport_uss720_private *priv = pp->private_data;		d = (d & 0xf) | (priv->reg[1] & 0xf0);	if (set_1284_register(pp, 2, d, GFP_KERNEL))		return;	priv->reg[1] = d;}static unsigned char parport_uss720_read_control(struct parport *pp){	struct parport_uss720_private *priv = pp->private_data;		return priv->reg[1] & 0xf; /* Use soft copy */}static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val){	struct parport_uss720_private *priv = pp->private_data;		unsigned char d;	mask &= 0x0f;	val &= 0x0f;	d = (priv->reg[1] & (~mask)) ^ val;	if (set_1284_register(pp, 2, d, GFP_KERNEL))		return 0;	priv->reg[1] = d;	return d & 0xf;}static unsigned char parport_uss720_read_status(struct parport *pp){	unsigned char ret;	if (get_1284_register(pp, 1, &ret, GFP_KERNEL))		return 0;	return ret & 0xf8;}static void parport_uss720_disable_irq(struct parport *pp){	struct parport_uss720_private *priv = pp->private_data;		unsigned char d;	d = priv->reg[1] & ~0x10;	if (set_1284_register(pp, 2, d, GFP_KERNEL))		return;	priv->reg[1] = d;}static void parport_uss720_enable_irq(struct parport *pp){	struct parport_uss720_private *priv = pp->private_data;	

⌨️ 快捷键说明

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