xref: /openbmc/linux/drivers/usb/misc/uss720.c (revision 57904291176fa16a981cefca5cbe1a0b50196792)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*****************************************************************************/
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds /*
51da177e4SLinus Torvalds  *	uss720.c  --  USS720 USB Parport Cable.
61da177e4SLinus Torvalds  *
7ecc1624aSThomas Sailer  *	Copyright (C) 1999, 2005, 2010
80f36163dSThomas Sailer  *	    Thomas Sailer (t.sailer@alumni.ethz.ch)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *  Based on parport_pc.c
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  History:
130f36163dSThomas Sailer  *   0.1  04.08.1999  Created
140f36163dSThomas Sailer  *   0.2  07.08.1999  Some fixes mainly suggested by Tim Waugh
151da177e4SLinus Torvalds  *		      Interrupt handling currently disabled because
161da177e4SLinus Torvalds  *		      usb_request_irq crashes somewhere within ohci.c
171da177e4SLinus Torvalds  *		      for no apparent reason (that is for me, anyway)
181da177e4SLinus Torvalds  *		      ECP currently untested
190f36163dSThomas Sailer  *   0.3  10.08.1999  fixing merge errors
200f36163dSThomas Sailer  *   0.4  13.08.1999  Added Vendor/Product ID of Brad Hard's cable
210f36163dSThomas Sailer  *   0.5  20.09.1999  usb_control_msg wrapper used
220f36163dSThomas Sailer  *        Nov01.2000  usb_device_table support by Adam J. Richter
230f36163dSThomas Sailer  *        08.04.2001  Identify version on module load.  gb
240f36163dSThomas Sailer  *   0.6  02.09.2005  Fix "scheduling in interrupt" problem by making save/restore
250f36163dSThomas Sailer  *                    context asynchronous
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  */
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds /*****************************************************************************/
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #include <linux/module.h>
321da177e4SLinus Torvalds #include <linux/socket.h>
331da177e4SLinus Torvalds #include <linux/parport.h>
341da177e4SLinus Torvalds #include <linux/init.h>
351da177e4SLinus Torvalds #include <linux/usb.h>
361da177e4SLinus Torvalds #include <linux/delay.h>
370f36163dSThomas Sailer #include <linux/completion.h>
380f36163dSThomas Sailer #include <linux/kref.h>
395a0e3ad6STejun Heo #include <linux/slab.h>
40174cd4b1SIngo Molnar #include <linux/sched/signal.h>
411da177e4SLinus Torvalds 
420f36163dSThomas Sailer #define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"
431da177e4SLinus Torvalds #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds struct parport_uss720_private {
481da177e4SLinus Torvalds 	struct usb_device *usbdev;
490f36163dSThomas Sailer 	struct parport *pp;
500f36163dSThomas Sailer 	struct kref ref_count;
510f36163dSThomas Sailer 	__u8 reg[7];  /* USB registers */
520f36163dSThomas Sailer 	struct list_head asynclist;
530f36163dSThomas Sailer 	spinlock_t asynclock;
540f36163dSThomas Sailer };
550f36163dSThomas Sailer 
560f36163dSThomas Sailer struct uss720_async_request {
570f36163dSThomas Sailer 	struct parport_uss720_private *priv;
580f36163dSThomas Sailer 	struct kref ref_count;
590f36163dSThomas Sailer 	struct list_head asynclist;
600f36163dSThomas Sailer 	struct completion compl;
610f36163dSThomas Sailer 	struct urb *urb;
629821aa9dSJohan Hovold 	struct usb_ctrlrequest *dr;
630f36163dSThomas Sailer 	__u8 reg[7];
641da177e4SLinus Torvalds };
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
671da177e4SLinus Torvalds 
destroy_priv(struct kref * kref)680f36163dSThomas Sailer static void destroy_priv(struct kref *kref)
691da177e4SLinus Torvalds {
700f36163dSThomas Sailer 	struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
710f36163dSThomas Sailer 
727a2d2810SGreg Kroah-Hartman 	dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n");
730f36163dSThomas Sailer 	usb_put_dev(priv->usbdev);
740a96fa64SHangyu Hua 	priv->usbdev = NULL;
750f36163dSThomas Sailer 	kfree(priv);
760f36163dSThomas Sailer }
770f36163dSThomas Sailer 
destroy_async(struct kref * kref)780f36163dSThomas Sailer static void destroy_async(struct kref *kref)
790f36163dSThomas Sailer {
800f36163dSThomas Sailer 	struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count);
810f36163dSThomas Sailer 	struct parport_uss720_private *priv = rq->priv;
820f36163dSThomas Sailer 	unsigned long flags;
830f36163dSThomas Sailer 
840f36163dSThomas Sailer 	if (likely(rq->urb))
850f36163dSThomas Sailer 		usb_free_urb(rq->urb);
869821aa9dSJohan Hovold 	kfree(rq->dr);
870f36163dSThomas Sailer 	spin_lock_irqsave(&priv->asynclock, flags);
880f36163dSThomas Sailer 	list_del_init(&rq->asynclist);
890f36163dSThomas Sailer 	spin_unlock_irqrestore(&priv->asynclock, flags);
900f36163dSThomas Sailer 	kfree(rq);
910f36163dSThomas Sailer 	kref_put(&priv->ref_count, destroy_priv);
920f36163dSThomas Sailer }
930f36163dSThomas Sailer 
940f36163dSThomas Sailer /* --------------------------------------------------------------------- */
950f36163dSThomas Sailer 
async_complete(struct urb * urb)967d12e780SDavid Howells static void async_complete(struct urb *urb)
970f36163dSThomas Sailer {
980f36163dSThomas Sailer 	struct uss720_async_request *rq;
990f36163dSThomas Sailer 	struct parport *pp;
1000f36163dSThomas Sailer 	struct parport_uss720_private *priv;
10182210d37SGreg Kroah-Hartman 	int status = urb->status;
1020f36163dSThomas Sailer 
1030f36163dSThomas Sailer 	rq = urb->context;
1040f36163dSThomas Sailer 	priv = rq->priv;
1050f36163dSThomas Sailer 	pp = priv->pp;
10682210d37SGreg Kroah-Hartman 	if (status) {
107d2b1ff71SGreg Kroah-Hartman 		dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
108d2b1ff71SGreg Kroah-Hartman 			status);
1099821aa9dSJohan Hovold 	} else if (rq->dr->bRequest == 3) {
1100f36163dSThomas Sailer 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
1110f36163dSThomas Sailer #if 0
1125d31a6dcSAndy Shevchenko 		dev_dbg(&priv->usbdev->dev, "async_complete regs %7ph\n",
1135d31a6dcSAndy Shevchenko 			priv->reg);
1140f36163dSThomas Sailer #endif
1150f36163dSThomas Sailer 		/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
1160f36163dSThomas Sailer 		if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
117f230d101SJeff Garzik 			parport_generic_irq(pp);
1180f36163dSThomas Sailer 	}
1190f36163dSThomas Sailer 	complete(&rq->compl);
1200f36163dSThomas Sailer 	kref_put(&rq->ref_count, destroy_async);
1210f36163dSThomas Sailer }
1220f36163dSThomas Sailer 
submit_async_request(struct parport_uss720_private * priv,__u8 request,__u8 requesttype,__u16 value,__u16 index,gfp_t mem_flags)1230f36163dSThomas Sailer static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv,
1240f36163dSThomas Sailer 							 __u8 request, __u8 requesttype, __u16 value, __u16 index,
12555016f10SAl Viro 							 gfp_t mem_flags)
1260f36163dSThomas Sailer {
1270f36163dSThomas Sailer 	struct usb_device *usbdev;
1280f36163dSThomas Sailer 	struct uss720_async_request *rq;
1290f36163dSThomas Sailer 	unsigned long flags;
1300f36163dSThomas Sailer 	int ret;
1310f36163dSThomas Sailer 
1320f36163dSThomas Sailer 	if (!priv)
1330f36163dSThomas Sailer 		return NULL;
1340f36163dSThomas Sailer 	usbdev = priv->usbdev;
1350f36163dSThomas Sailer 	if (!usbdev)
1360f36163dSThomas Sailer 		return NULL;
1379821aa9dSJohan Hovold 	rq = kzalloc(sizeof(struct uss720_async_request), mem_flags);
138c9220ba5SWolfram Sang 	if (!rq)
1390f36163dSThomas Sailer 		return NULL;
1400f36163dSThomas Sailer 	kref_init(&rq->ref_count);
1410f36163dSThomas Sailer 	INIT_LIST_HEAD(&rq->asynclist);
1420f36163dSThomas Sailer 	init_completion(&rq->compl);
1430f36163dSThomas Sailer 	kref_get(&priv->ref_count);
1440f36163dSThomas Sailer 	rq->priv = priv;
1450f36163dSThomas Sailer 	rq->urb = usb_alloc_urb(0, mem_flags);
1460f36163dSThomas Sailer 	if (!rq->urb) {
1470f36163dSThomas Sailer 		kref_put(&rq->ref_count, destroy_async);
1480f36163dSThomas Sailer 		return NULL;
1490f36163dSThomas Sailer 	}
1509821aa9dSJohan Hovold 	rq->dr = kmalloc(sizeof(*rq->dr), mem_flags);
1519821aa9dSJohan Hovold 	if (!rq->dr) {
1529821aa9dSJohan Hovold 		kref_put(&rq->ref_count, destroy_async);
1539821aa9dSJohan Hovold 		return NULL;
1549821aa9dSJohan Hovold 	}
1559821aa9dSJohan Hovold 	rq->dr->bRequestType = requesttype;
1569821aa9dSJohan Hovold 	rq->dr->bRequest = request;
1579821aa9dSJohan Hovold 	rq->dr->wValue = cpu_to_le16(value);
1589821aa9dSJohan Hovold 	rq->dr->wIndex = cpu_to_le16(index);
1599821aa9dSJohan Hovold 	rq->dr->wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0);
1600f36163dSThomas Sailer 	usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0),
1619821aa9dSJohan Hovold 			     (unsigned char *)rq->dr,
1620f36163dSThomas Sailer 			     (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq);
1630f36163dSThomas Sailer 	/* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */
1640f36163dSThomas Sailer 	spin_lock_irqsave(&priv->asynclock, flags);
1650f36163dSThomas Sailer 	list_add_tail(&rq->asynclist, &priv->asynclist);
1660f36163dSThomas Sailer 	spin_unlock_irqrestore(&priv->asynclock, flags);
1670f36163dSThomas Sailer 	kref_get(&rq->ref_count);
168adaa3c63SPeter Holik 	ret = usb_submit_urb(rq->urb, mem_flags);
169adaa3c63SPeter Holik 	if (!ret)
1700f36163dSThomas Sailer 		return rq;
171adaa3c63SPeter Holik 	destroy_async(&rq->ref_count);
172d2b1ff71SGreg Kroah-Hartman 	dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret);
1730f36163dSThomas Sailer 	return NULL;
1740f36163dSThomas Sailer }
1750f36163dSThomas Sailer 
kill_all_async_requests_priv(struct parport_uss720_private * priv)1760f36163dSThomas Sailer static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv)
1770f36163dSThomas Sailer {
1780f36163dSThomas Sailer 	struct uss720_async_request *rq;
1790f36163dSThomas Sailer 	unsigned long flags;
1800f36163dSThomas Sailer 	unsigned int ret = 0;
1810f36163dSThomas Sailer 
1820f36163dSThomas Sailer 	spin_lock_irqsave(&priv->asynclock, flags);
1830f36163dSThomas Sailer 	list_for_each_entry(rq, &priv->asynclist, asynclist) {
1840f36163dSThomas Sailer 		usb_unlink_urb(rq->urb);
1850f36163dSThomas Sailer 		ret++;
1860f36163dSThomas Sailer 	}
1870f36163dSThomas Sailer 	spin_unlock_irqrestore(&priv->asynclock, flags);
1880f36163dSThomas Sailer 	return ret;
1890f36163dSThomas Sailer }
1900f36163dSThomas Sailer 
1910f36163dSThomas Sailer /* --------------------------------------------------------------------- */
1920f36163dSThomas Sailer 
get_1284_register(struct parport * pp,unsigned char reg,unsigned char * val,gfp_t mem_flags)19355016f10SAl Viro static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags)
1940f36163dSThomas Sailer {
1950f36163dSThomas Sailer 	struct parport_uss720_private *priv;
1960f36163dSThomas Sailer 	struct uss720_async_request *rq;
1971da177e4SLinus Torvalds 	static const unsigned char regindex[9] = {
1981da177e4SLinus Torvalds 		4, 0, 1, 5, 5, 0, 2, 3, 6
1991da177e4SLinus Torvalds 	};
2001da177e4SLinus Torvalds 	int ret;
2011da177e4SLinus Torvalds 
2020f36163dSThomas Sailer 	if (!pp)
2030f36163dSThomas Sailer 		return -EIO;
2040f36163dSThomas Sailer 	priv = pp->private_data;
2050f36163dSThomas Sailer 	rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
2060f36163dSThomas Sailer 	if (!rq) {
207d2b1ff71SGreg Kroah-Hartman 		dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed",
208d2b1ff71SGreg Kroah-Hartman 			(unsigned int)reg);
2090f36163dSThomas Sailer 		return -EIO;
2101da177e4SLinus Torvalds 	}
2110f36163dSThomas Sailer 	if (!val) {
2120f36163dSThomas Sailer 		kref_put(&rq->ref_count, destroy_async);
2130f36163dSThomas Sailer 		return 0;
2140f36163dSThomas Sailer 	}
2150f36163dSThomas Sailer 	if (wait_for_completion_timeout(&rq->compl, HZ)) {
2160f36163dSThomas Sailer 		ret = rq->urb->status;
2171da177e4SLinus Torvalds 		*val = priv->reg[(reg >= 9) ? 0 : regindex[reg]];
2180f36163dSThomas Sailer 		if (ret)
2193b6004f3SGreg Kroah-Hartman 			printk(KERN_WARNING "get_1284_register: "
2203b6004f3SGreg Kroah-Hartman 			       "usb error %d\n", ret);
2210f36163dSThomas Sailer 		kref_put(&rq->ref_count, destroy_async);
2221da177e4SLinus Torvalds 		return ret;
2231da177e4SLinus Torvalds 	}
2243b6004f3SGreg Kroah-Hartman 	printk(KERN_WARNING "get_1284_register timeout\n");
2250f36163dSThomas Sailer 	kill_all_async_requests_priv(priv);
2260f36163dSThomas Sailer 	return -EIO;
2270f36163dSThomas Sailer }
2281da177e4SLinus Torvalds 
set_1284_register(struct parport * pp,unsigned char reg,unsigned char val,gfp_t mem_flags)22955016f10SAl Viro static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags)
2301da177e4SLinus Torvalds {
2310f36163dSThomas Sailer 	struct parport_uss720_private *priv;
2320f36163dSThomas Sailer 	struct uss720_async_request *rq;
2331da177e4SLinus Torvalds 
2340f36163dSThomas Sailer 	if (!pp)
2350f36163dSThomas Sailer 		return -EIO;
2360f36163dSThomas Sailer 	priv = pp->private_data;
2370f36163dSThomas Sailer 	rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
2380f36163dSThomas Sailer 	if (!rq) {
239d2b1ff71SGreg Kroah-Hartman 		dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed",
240d2b1ff71SGreg Kroah-Hartman 			(unsigned int)reg, (unsigned int)val);
2410f36163dSThomas Sailer 		return -EIO;
2421da177e4SLinus Torvalds 	}
2430f36163dSThomas Sailer 	kref_put(&rq->ref_count, destroy_async);
2440f36163dSThomas Sailer 	return 0;
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds /* ECR modes */
2501da177e4SLinus Torvalds #define ECR_SPP 00
2511da177e4SLinus Torvalds #define ECR_PS2 01
2521da177e4SLinus Torvalds #define ECR_PPF 02
2531da177e4SLinus Torvalds #define ECR_ECP 03
2541da177e4SLinus Torvalds #define ECR_EPP 04
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds /* Safely change the mode bits in the ECR */
change_mode(struct parport * pp,int m)2571da177e4SLinus Torvalds static int change_mode(struct parport *pp, int m)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
2601da177e4SLinus Torvalds 	int mode;
2610f36163dSThomas Sailer 	__u8 reg;
2621da177e4SLinus Torvalds 
2630f36163dSThomas Sailer 	if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
2641da177e4SLinus Torvalds 		return -EIO;
2651da177e4SLinus Torvalds 	/* Bits <7:5> contain the mode. */
2661da177e4SLinus Torvalds 	mode = (priv->reg[2] >> 5) & 0x7;
2671da177e4SLinus Torvalds 	if (mode == m)
2681da177e4SLinus Torvalds 		return 0;
2691da177e4SLinus Torvalds 	/* We have to go through mode 000 or 001 */
2701da177e4SLinus Torvalds 	if (mode > ECR_PS2 && m > ECR_PS2)
2711da177e4SLinus Torvalds 		if (change_mode(pp, ECR_PS2))
2721da177e4SLinus Torvalds 			return -EIO;
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
2751da177e4SLinus Torvalds 		/* This mode resets the FIFO, so we may
2761da177e4SLinus Torvalds 		 * have to wait for it to drain first. */
2771da177e4SLinus Torvalds 		unsigned long expire = jiffies + pp->physport->cad->timeout;
2781da177e4SLinus Torvalds 		switch (mode) {
2791da177e4SLinus Torvalds 		case ECR_PPF: /* Parallel Port FIFO mode */
2801da177e4SLinus Torvalds 		case ECR_ECP: /* ECP Parallel Port mode */
2811da177e4SLinus Torvalds 			/* Poll slowly. */
2821da177e4SLinus Torvalds 			for (;;) {
2830f36163dSThomas Sailer 				if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
2841da177e4SLinus Torvalds 					return -EIO;
2851da177e4SLinus Torvalds 				if (priv->reg[2] & 0x01)
2861da177e4SLinus Torvalds 					break;
2871da177e4SLinus Torvalds 				if (time_after_eq (jiffies, expire))
2881da177e4SLinus Torvalds 					/* The FIFO is stuck. */
2891da177e4SLinus Torvalds 					return -EBUSY;
2901da177e4SLinus Torvalds 				msleep_interruptible(10);
2911da177e4SLinus Torvalds 				if (signal_pending (current))
2921da177e4SLinus Torvalds 					break;
2931da177e4SLinus Torvalds 			}
2941da177e4SLinus Torvalds 		}
2951da177e4SLinus Torvalds 	}
2961da177e4SLinus Torvalds 	/* Set the mode. */
2970f36163dSThomas Sailer 	if (set_1284_register(pp, 6, m << 5, GFP_KERNEL))
2980f36163dSThomas Sailer 		return -EIO;
2990f36163dSThomas Sailer 	if (get_1284_register(pp, 6, &reg, GFP_KERNEL))
3001da177e4SLinus Torvalds 		return -EIO;
3011da177e4SLinus Torvalds 	return 0;
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds /*
3051da177e4SLinus Torvalds  * Clear TIMEOUT BIT in EPP MODE
3061da177e4SLinus Torvalds  */
clear_epp_timeout(struct parport * pp)3071da177e4SLinus Torvalds static int clear_epp_timeout(struct parport *pp)
3081da177e4SLinus Torvalds {
3091da177e4SLinus Torvalds 	unsigned char stat;
3101da177e4SLinus Torvalds 
3110f36163dSThomas Sailer 	if (get_1284_register(pp, 1, &stat, GFP_KERNEL))
3121da177e4SLinus Torvalds 		return 1;
3131da177e4SLinus Torvalds 	return stat & 1;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /*
3171da177e4SLinus Torvalds  * Access functions.
3181da177e4SLinus Torvalds  */
3191da177e4SLinus Torvalds #if 0
3201da177e4SLinus Torvalds static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds 	struct parport *pp = (struct parport *)dev_id;
3231da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds 	if (usbstatus != 0 || len < 4 || !buffer)
3261da177e4SLinus Torvalds 		return 1;
3271da177e4SLinus Torvalds 	memcpy(priv->reg, buffer, 4);
3281da177e4SLinus Torvalds 	/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
3291da177e4SLinus Torvalds 	if (priv->reg[2] & priv->reg[1] & 0x10)
330f230d101SJeff Garzik 		parport_generic_irq(pp);
3311da177e4SLinus Torvalds 	return 1;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds #endif
3341da177e4SLinus Torvalds 
parport_uss720_write_data(struct parport * pp,unsigned char d)3351da177e4SLinus Torvalds static void parport_uss720_write_data(struct parport *pp, unsigned char d)
3361da177e4SLinus Torvalds {
3370f36163dSThomas Sailer 	set_1284_register(pp, 0, d, GFP_KERNEL);
3381da177e4SLinus Torvalds }
3391da177e4SLinus Torvalds 
parport_uss720_read_data(struct parport * pp)3401da177e4SLinus Torvalds static unsigned char parport_uss720_read_data(struct parport *pp)
3411da177e4SLinus Torvalds {
3421da177e4SLinus Torvalds 	unsigned char ret;
3431da177e4SLinus Torvalds 
3440f36163dSThomas Sailer 	if (get_1284_register(pp, 0, &ret, GFP_KERNEL))
3451da177e4SLinus Torvalds 		return 0;
3461da177e4SLinus Torvalds 	return ret;
3471da177e4SLinus Torvalds }
3481da177e4SLinus Torvalds 
parport_uss720_write_control(struct parport * pp,unsigned char d)3491da177e4SLinus Torvalds static void parport_uss720_write_control(struct parport *pp, unsigned char d)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	d = (d & 0xf) | (priv->reg[1] & 0xf0);
3540f36163dSThomas Sailer 	if (set_1284_register(pp, 2, d, GFP_KERNEL))
3551da177e4SLinus Torvalds 		return;
3561da177e4SLinus Torvalds 	priv->reg[1] = d;
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
parport_uss720_read_control(struct parport * pp)3591da177e4SLinus Torvalds static unsigned char parport_uss720_read_control(struct parport *pp)
3601da177e4SLinus Torvalds {
3611da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
3621da177e4SLinus Torvalds 	return priv->reg[1] & 0xf; /* Use soft copy */
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds 
parport_uss720_frob_control(struct parport * pp,unsigned char mask,unsigned char val)3651da177e4SLinus Torvalds static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val)
3661da177e4SLinus Torvalds {
3671da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
3681da177e4SLinus Torvalds 	unsigned char d;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	mask &= 0x0f;
3711da177e4SLinus Torvalds 	val &= 0x0f;
3721da177e4SLinus Torvalds 	d = (priv->reg[1] & (~mask)) ^ val;
373bc8acc21SJia-Ju Bai 	if (set_1284_register(pp, 2, d, GFP_ATOMIC))
3741da177e4SLinus Torvalds 		return 0;
3751da177e4SLinus Torvalds 	priv->reg[1] = d;
3761da177e4SLinus Torvalds 	return d & 0xf;
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds 
parport_uss720_read_status(struct parport * pp)3791da177e4SLinus Torvalds static unsigned char parport_uss720_read_status(struct parport *pp)
3801da177e4SLinus Torvalds {
3811da177e4SLinus Torvalds 	unsigned char ret;
3821da177e4SLinus Torvalds 
383bc8acc21SJia-Ju Bai 	if (get_1284_register(pp, 1, &ret, GFP_ATOMIC))
3841da177e4SLinus Torvalds 		return 0;
3851da177e4SLinus Torvalds 	return ret & 0xf8;
3861da177e4SLinus Torvalds }
3871da177e4SLinus Torvalds 
parport_uss720_disable_irq(struct parport * pp)3881da177e4SLinus Torvalds static void parport_uss720_disable_irq(struct parport *pp)
3891da177e4SLinus Torvalds {
3901da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
3911da177e4SLinus Torvalds 	unsigned char d;
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	d = priv->reg[1] & ~0x10;
3940f36163dSThomas Sailer 	if (set_1284_register(pp, 2, d, GFP_KERNEL))
3951da177e4SLinus Torvalds 		return;
3961da177e4SLinus Torvalds 	priv->reg[1] = d;
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
parport_uss720_enable_irq(struct parport * pp)3991da177e4SLinus Torvalds static void parport_uss720_enable_irq(struct parport *pp)
4001da177e4SLinus Torvalds {
4011da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4021da177e4SLinus Torvalds 	unsigned char d;
4031da177e4SLinus Torvalds 
4041da177e4SLinus Torvalds 	d = priv->reg[1] | 0x10;
4050f36163dSThomas Sailer 	if (set_1284_register(pp, 2, d, GFP_KERNEL))
4061da177e4SLinus Torvalds 		return;
4071da177e4SLinus Torvalds 	priv->reg[1] = d;
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
parport_uss720_data_forward(struct parport * pp)4101da177e4SLinus Torvalds static void parport_uss720_data_forward (struct parport *pp)
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4131da177e4SLinus Torvalds 	unsigned char d;
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds 	d = priv->reg[1] & ~0x20;
4160f36163dSThomas Sailer 	if (set_1284_register(pp, 2, d, GFP_KERNEL))
4171da177e4SLinus Torvalds 		return;
4181da177e4SLinus Torvalds 	priv->reg[1] = d;
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
parport_uss720_data_reverse(struct parport * pp)4211da177e4SLinus Torvalds static void parport_uss720_data_reverse (struct parport *pp)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4241da177e4SLinus Torvalds 	unsigned char d;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	d = priv->reg[1] | 0x20;
4270f36163dSThomas Sailer 	if (set_1284_register(pp, 2, d, GFP_KERNEL))
4281da177e4SLinus Torvalds 		return;
4291da177e4SLinus Torvalds 	priv->reg[1] = d;
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds 
parport_uss720_init_state(struct pardevice * dev,struct parport_state * s)4321da177e4SLinus Torvalds static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s)
4331da177e4SLinus Torvalds {
4341da177e4SLinus Torvalds 	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
4351da177e4SLinus Torvalds 	s->u.pc.ecr = 0x24;
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds 
parport_uss720_save_state(struct parport * pp,struct parport_state * s)4381da177e4SLinus Torvalds static void parport_uss720_save_state(struct parport *pp, struct parport_state *s)
4391da177e4SLinus Torvalds {
4401da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4411da177e4SLinus Torvalds 
4420f36163dSThomas Sailer #if 0
4430f36163dSThomas Sailer 	if (get_1284_register(pp, 2, NULL, GFP_ATOMIC))
4441da177e4SLinus Torvalds 		return;
4450f36163dSThomas Sailer #endif
4461da177e4SLinus Torvalds 	s->u.pc.ctr = priv->reg[1];
4471da177e4SLinus Torvalds 	s->u.pc.ecr = priv->reg[2];
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
parport_uss720_restore_state(struct parport * pp,struct parport_state * s)4501da177e4SLinus Torvalds static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s)
4511da177e4SLinus Torvalds {
4520f36163dSThomas Sailer 	struct parport_uss720_private *priv = pp->private_data;
4530f36163dSThomas Sailer 
4540f36163dSThomas Sailer 	set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC);
4550f36163dSThomas Sailer 	set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC);
4560f36163dSThomas Sailer 	get_1284_register(pp, 2, NULL, GFP_ATOMIC);
4570f36163dSThomas Sailer 	priv->reg[1] = s->u.pc.ctr;
4580f36163dSThomas Sailer 	priv->reg[2] = s->u.pc.ecr;
4591da177e4SLinus Torvalds }
4601da177e4SLinus Torvalds 
parport_uss720_epp_read_data(struct parport * pp,void * buf,size_t length,int flags)4611da177e4SLinus Torvalds static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags)
4621da177e4SLinus Torvalds {
4631da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4641da177e4SLinus Torvalds 	size_t got = 0;
4651da177e4SLinus Torvalds 
4661da177e4SLinus Torvalds 	if (change_mode(pp, ECR_EPP))
4671da177e4SLinus Torvalds 		return 0;
4681da177e4SLinus Torvalds 	for (; got < length; got++) {
4690f36163dSThomas Sailer 		if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
4701da177e4SLinus Torvalds 			break;
4711da177e4SLinus Torvalds 		buf++;
4721da177e4SLinus Torvalds 		if (priv->reg[0] & 0x01) {
4731da177e4SLinus Torvalds 			clear_epp_timeout(pp);
4741da177e4SLinus Torvalds 			break;
4751da177e4SLinus Torvalds 		}
4761da177e4SLinus Torvalds 	}
4771da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
4781da177e4SLinus Torvalds 	return got;
4791da177e4SLinus Torvalds }
4801da177e4SLinus Torvalds 
parport_uss720_epp_write_data(struct parport * pp,const void * buf,size_t length,int flags)4811da177e4SLinus Torvalds static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags)
4821da177e4SLinus Torvalds {
4831da177e4SLinus Torvalds #if 0
4841da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
4851da177e4SLinus Torvalds 	size_t written = 0;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	if (change_mode(pp, ECR_EPP))
4881da177e4SLinus Torvalds 		return 0;
4891da177e4SLinus Torvalds 	for (; written < length; written++) {
4900f36163dSThomas Sailer 		if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL))
4911da177e4SLinus Torvalds 			break;
4921da177e4SLinus Torvalds 		((char*)buf)++;
4930f36163dSThomas Sailer 		if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
4941da177e4SLinus Torvalds 			break;
4951da177e4SLinus Torvalds 		if (priv->reg[0] & 0x01) {
4961da177e4SLinus Torvalds 			clear_epp_timeout(pp);
4971da177e4SLinus Torvalds 			break;
4981da177e4SLinus Torvalds 		}
4991da177e4SLinus Torvalds 	}
5001da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5011da177e4SLinus Torvalds 	return written;
5021da177e4SLinus Torvalds #else
5031da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
5041da177e4SLinus Torvalds 	struct usb_device *usbdev = priv->usbdev;
505a8113da5SDongliang Mu 	int rlen = 0;
5061da177e4SLinus Torvalds 	int i;
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	if (!usbdev)
5091da177e4SLinus Torvalds 		return 0;
5101da177e4SLinus Torvalds 	if (change_mode(pp, ECR_EPP))
5111da177e4SLinus Torvalds 		return 0;
5121da177e4SLinus Torvalds 	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000);
5131da177e4SLinus Torvalds 	if (i)
5145b5e0928SAlexey Dobriyan 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buf, length, rlen);
5151da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5161da177e4SLinus Torvalds 	return rlen;
5171da177e4SLinus Torvalds #endif
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds 
parport_uss720_epp_read_addr(struct parport * pp,void * buf,size_t length,int flags)5201da177e4SLinus Torvalds static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags)
5211da177e4SLinus Torvalds {
5221da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
5231da177e4SLinus Torvalds 	size_t got = 0;
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	if (change_mode(pp, ECR_EPP))
5261da177e4SLinus Torvalds 		return 0;
5271da177e4SLinus Torvalds 	for (; got < length; got++) {
5280f36163dSThomas Sailer 		if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL))
5291da177e4SLinus Torvalds 			break;
5301da177e4SLinus Torvalds 		buf++;
5311da177e4SLinus Torvalds 		if (priv->reg[0] & 0x01) {
5321da177e4SLinus Torvalds 			clear_epp_timeout(pp);
5331da177e4SLinus Torvalds 			break;
5341da177e4SLinus Torvalds 		}
5351da177e4SLinus Torvalds 	}
5361da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5371da177e4SLinus Torvalds 	return got;
5381da177e4SLinus Torvalds }
5391da177e4SLinus Torvalds 
parport_uss720_epp_write_addr(struct parport * pp,const void * buf,size_t length,int flags)5401da177e4SLinus Torvalds static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags)
5411da177e4SLinus Torvalds {
5421da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
5431da177e4SLinus Torvalds 	size_t written = 0;
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	if (change_mode(pp, ECR_EPP))
5461da177e4SLinus Torvalds 		return 0;
5471da177e4SLinus Torvalds 	for (; written < length; written++) {
5480f36163dSThomas Sailer 		if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL))
5491da177e4SLinus Torvalds 			break;
5501da177e4SLinus Torvalds 		buf++;
5510f36163dSThomas Sailer 		if (get_1284_register(pp, 1, NULL, GFP_KERNEL))
5521da177e4SLinus Torvalds 			break;
5531da177e4SLinus Torvalds 		if (priv->reg[0] & 0x01) {
5541da177e4SLinus Torvalds 			clear_epp_timeout(pp);
5551da177e4SLinus Torvalds 			break;
5561da177e4SLinus Torvalds 		}
5571da177e4SLinus Torvalds 	}
5581da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5591da177e4SLinus Torvalds 	return written;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
parport_uss720_ecp_write_data(struct parport * pp,const void * buffer,size_t len,int flags)5621da177e4SLinus Torvalds static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags)
5631da177e4SLinus Torvalds {
5641da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
5651da177e4SLinus Torvalds 	struct usb_device *usbdev = priv->usbdev;
566a8113da5SDongliang Mu 	int rlen = 0;
5671da177e4SLinus Torvalds 	int i;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	if (!usbdev)
5701da177e4SLinus Torvalds 		return 0;
5711da177e4SLinus Torvalds 	if (change_mode(pp, ECR_ECP))
5721da177e4SLinus Torvalds 		return 0;
5731da177e4SLinus Torvalds 	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
5741da177e4SLinus Torvalds 	if (i)
5755b5e0928SAlexey Dobriyan 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buffer, len, rlen);
5761da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5771da177e4SLinus Torvalds 	return rlen;
5781da177e4SLinus Torvalds }
5791da177e4SLinus Torvalds 
parport_uss720_ecp_read_data(struct parport * pp,void * buffer,size_t len,int flags)5801da177e4SLinus Torvalds static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags)
5811da177e4SLinus Torvalds {
5821da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
5831da177e4SLinus Torvalds 	struct usb_device *usbdev = priv->usbdev;
584a8113da5SDongliang Mu 	int rlen = 0;
5851da177e4SLinus Torvalds 	int i;
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds 	if (!usbdev)
5881da177e4SLinus Torvalds 		return 0;
5891da177e4SLinus Torvalds 	if (change_mode(pp, ECR_ECP))
5901da177e4SLinus Torvalds 		return 0;
5911da177e4SLinus Torvalds 	i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000);
5921da177e4SLinus Torvalds 	if (i)
5935b5e0928SAlexey Dobriyan 		printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %zu rlen %u\n", buffer, len, rlen);
5941da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
5951da177e4SLinus Torvalds 	return rlen;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds 
parport_uss720_ecp_write_addr(struct parport * pp,const void * buffer,size_t len,int flags)5981da177e4SLinus Torvalds static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds 	size_t written = 0;
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 	if (change_mode(pp, ECR_ECP))
6031da177e4SLinus Torvalds 		return 0;
6041da177e4SLinus Torvalds 	for (; written < len; written++) {
6050f36163dSThomas Sailer 		if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL))
6061da177e4SLinus Torvalds 			break;
6071da177e4SLinus Torvalds 		buffer++;
6081da177e4SLinus Torvalds 	}
6091da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
6101da177e4SLinus Torvalds 	return written;
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
parport_uss720_write_compat(struct parport * pp,const void * buffer,size_t len,int flags)6131da177e4SLinus Torvalds static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags)
6141da177e4SLinus Torvalds {
6151da177e4SLinus Torvalds 	struct parport_uss720_private *priv = pp->private_data;
6161da177e4SLinus Torvalds 	struct usb_device *usbdev = priv->usbdev;
617a8113da5SDongliang Mu 	int rlen = 0;
6181da177e4SLinus Torvalds 	int i;
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	if (!usbdev)
6211da177e4SLinus Torvalds 		return 0;
6221da177e4SLinus Torvalds 	if (change_mode(pp, ECR_PPF))
6231da177e4SLinus Torvalds 		return 0;
6241da177e4SLinus Torvalds 	i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000);
6251da177e4SLinus Torvalds 	if (i)
6265b5e0928SAlexey Dobriyan 		printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buffer, len, rlen);
6271da177e4SLinus Torvalds 	change_mode(pp, ECR_PS2);
6281da177e4SLinus Torvalds 	return rlen;
6291da177e4SLinus Torvalds }
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
6321da177e4SLinus Torvalds 
6331da177e4SLinus Torvalds static struct parport_operations parport_uss720_ops =
6341da177e4SLinus Torvalds {
6351da177e4SLinus Torvalds 	.owner =		THIS_MODULE,
6361da177e4SLinus Torvalds 	.write_data =		parport_uss720_write_data,
6371da177e4SLinus Torvalds 	.read_data =		parport_uss720_read_data,
6381da177e4SLinus Torvalds 
6391da177e4SLinus Torvalds 	.write_control =	parport_uss720_write_control,
6401da177e4SLinus Torvalds 	.read_control =		parport_uss720_read_control,
6411da177e4SLinus Torvalds 	.frob_control =		parport_uss720_frob_control,
6421da177e4SLinus Torvalds 
6431da177e4SLinus Torvalds 	.read_status =		parport_uss720_read_status,
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	.enable_irq =		parport_uss720_enable_irq,
6461da177e4SLinus Torvalds 	.disable_irq =		parport_uss720_disable_irq,
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	.data_forward =		parport_uss720_data_forward,
6491da177e4SLinus Torvalds 	.data_reverse =		parport_uss720_data_reverse,
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	.init_state =		parport_uss720_init_state,
6521da177e4SLinus Torvalds 	.save_state =		parport_uss720_save_state,
6531da177e4SLinus Torvalds 	.restore_state =	parport_uss720_restore_state,
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 	.epp_write_data =	parport_uss720_epp_write_data,
6561da177e4SLinus Torvalds 	.epp_read_data =	parport_uss720_epp_read_data,
6571da177e4SLinus Torvalds 	.epp_write_addr =	parport_uss720_epp_write_addr,
6581da177e4SLinus Torvalds 	.epp_read_addr =	parport_uss720_epp_read_addr,
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	.ecp_write_data =	parport_uss720_ecp_write_data,
6611da177e4SLinus Torvalds 	.ecp_read_data =	parport_uss720_ecp_read_data,
6621da177e4SLinus Torvalds 	.ecp_write_addr =	parport_uss720_ecp_write_addr,
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	.compat_write_data =	parport_uss720_write_compat,
6651da177e4SLinus Torvalds 	.nibble_read_data =	parport_ieee1284_read_nibble,
6661da177e4SLinus Torvalds 	.byte_read_data =	parport_ieee1284_read_byte,
6671da177e4SLinus Torvalds };
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
6701da177e4SLinus Torvalds 
uss720_probe(struct usb_interface * intf,const struct usb_device_id * id)6711da177e4SLinus Torvalds static int uss720_probe(struct usb_interface *intf,
6721da177e4SLinus Torvalds 			const struct usb_device_id *id)
6731da177e4SLinus Torvalds {
6740f36163dSThomas Sailer 	struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf));
6751da177e4SLinus Torvalds 	struct usb_host_interface *interface;
6769fdc1c6fSJohan Hovold 	struct usb_endpoint_descriptor *epd;
6771da177e4SLinus Torvalds 	struct parport_uss720_private *priv;
6781da177e4SLinus Torvalds 	struct parport *pp;
6790f36163dSThomas Sailer 	unsigned char reg;
680*10132ccfSAlex Henrie 	int ret;
6811da177e4SLinus Torvalds 
6827a2d2810SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n",
6831da177e4SLinus Torvalds 		le16_to_cpu(usbdev->descriptor.idVendor),
6841da177e4SLinus Torvalds 		le16_to_cpu(usbdev->descriptor.idProduct));
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	/* our known interfaces have 3 alternate settings */
6870f36163dSThomas Sailer 	if (intf->num_altsetting != 3) {
6880f36163dSThomas Sailer 		usb_put_dev(usbdev);
6891da177e4SLinus Torvalds 		return -ENODEV;
6900f36163dSThomas Sailer 	}
691*10132ccfSAlex Henrie 	ret = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
692*10132ccfSAlex Henrie 	dev_dbg(&intf->dev, "set interface result %d\n", ret);
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	interface = intf->cur_altsetting;
6951da177e4SLinus Torvalds 
696f259ca3eSJohan Hovold 	if (interface->desc.bNumEndpoints < 3) {
697f259ca3eSJohan Hovold 		usb_put_dev(usbdev);
698f259ca3eSJohan Hovold 		return -ENODEV;
699f259ca3eSJohan Hovold 	}
700f259ca3eSJohan Hovold 
7011da177e4SLinus Torvalds 	/*
7021da177e4SLinus Torvalds 	 * Allocate parport interface
7031da177e4SLinus Torvalds 	 */
704adde04c6SGreg Kroah-Hartman 	priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL);
705adde04c6SGreg Kroah-Hartman 	if (!priv) {
7060f36163dSThomas Sailer 		usb_put_dev(usbdev);
7071da177e4SLinus Torvalds 		return -ENOMEM;
7080f36163dSThomas Sailer 	}
7090f36163dSThomas Sailer 	priv->pp = NULL;
7100f36163dSThomas Sailer 	priv->usbdev = usbdev;
7110f36163dSThomas Sailer 	kref_init(&priv->ref_count);
7120f36163dSThomas Sailer 	spin_lock_init(&priv->asynclock);
7130f36163dSThomas Sailer 	INIT_LIST_HEAD(&priv->asynclist);
714adde04c6SGreg Kroah-Hartman 	pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops);
715adde04c6SGreg Kroah-Hartman 	if (!pp) {
7163b6004f3SGreg Kroah-Hartman 		printk(KERN_WARNING "uss720: could not register parport\n");
7171da177e4SLinus Torvalds 		goto probe_abort;
7181da177e4SLinus Torvalds 	}
7191da177e4SLinus Torvalds 
7200f36163dSThomas Sailer 	priv->pp = pp;
7211da177e4SLinus Torvalds 	pp->private_data = priv;
7221da177e4SLinus Torvalds 	pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT;
7231da177e4SLinus Torvalds 
7241da177e4SLinus Torvalds 	/* set the USS720 control register to manual mode, no ECP compression, enable all ints */
7250f36163dSThomas Sailer 	set_1284_register(pp, 7, 0x00, GFP_KERNEL);
7260f36163dSThomas Sailer 	set_1284_register(pp, 6, 0x30, GFP_KERNEL);  /* PS/2 mode */
7270f36163dSThomas Sailer 	set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
7281da177e4SLinus Torvalds 
729*10132ccfSAlex Henrie 	/* The Belkin F5U002 Rev 2 P80453-B USB parallel port adapter shares the
730*10132ccfSAlex Henrie 	 * device ID 050d:0002 with some other device that works with this
731*10132ccfSAlex Henrie 	 * driver, but it itself does not. Detect and handle the bad cable
732*10132ccfSAlex Henrie 	 * here. */
733*10132ccfSAlex Henrie 	ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
734*10132ccfSAlex Henrie 	dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
735*10132ccfSAlex Henrie 	if (ret < 0)
736*10132ccfSAlex Henrie 		return ret;
737*10132ccfSAlex Henrie 
738*10132ccfSAlex Henrie 	ret = usb_find_last_int_in_endpoint(interface, &epd);
739*10132ccfSAlex Henrie 	if (!ret) {
7407a2d2810SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "epaddr %d interval %d\n",
7419fdc1c6fSJohan Hovold 				epd->bEndpointAddress, epd->bInterval);
7429fdc1c6fSJohan Hovold 	}
7431da177e4SLinus Torvalds 	parport_announce_port(pp);
7441da177e4SLinus Torvalds 
7451da177e4SLinus Torvalds 	usb_set_intfdata(intf, pp);
7461da177e4SLinus Torvalds 	return 0;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds probe_abort:
7490f36163dSThomas Sailer 	kill_all_async_requests_priv(priv);
7500f36163dSThomas Sailer 	kref_put(&priv->ref_count, destroy_priv);
7511da177e4SLinus Torvalds 	return -ENODEV;
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds 
uss720_disconnect(struct usb_interface * intf)7541da177e4SLinus Torvalds static void uss720_disconnect(struct usb_interface *intf)
7551da177e4SLinus Torvalds {
7561da177e4SLinus Torvalds 	struct parport *pp = usb_get_intfdata(intf);
7571da177e4SLinus Torvalds 	struct parport_uss720_private *priv;
7581da177e4SLinus Torvalds 
7597a2d2810SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "disconnect\n");
7601da177e4SLinus Torvalds 	usb_set_intfdata(intf, NULL);
7611da177e4SLinus Torvalds 	if (pp) {
7621da177e4SLinus Torvalds 		priv = pp->private_data;
7630f36163dSThomas Sailer 		priv->pp = NULL;
7647a2d2810SGreg Kroah-Hartman 		dev_dbg(&intf->dev, "parport_remove_port\n");
7650f36163dSThomas Sailer 		parport_remove_port(pp);
7661da177e4SLinus Torvalds 		parport_put_port(pp);
7670f36163dSThomas Sailer 		kill_all_async_requests_priv(priv);
7680f36163dSThomas Sailer 		kref_put(&priv->ref_count, destroy_priv);
7691da177e4SLinus Torvalds 	}
7707a2d2810SGreg Kroah-Hartman 	dev_dbg(&intf->dev, "disconnect done\n");
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds /* table of cables that work through this driver */
77433b9e162SNémeth Márton static const struct usb_device_id uss720_table[] = {
7751da177e4SLinus Torvalds 	{ USB_DEVICE(0x047e, 0x1001) },
776e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x04b8, 0x0002) },
777e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x04b8, 0x0003) },
778e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x050d, 0x0002) },
779e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x050d, 0x1202) },
7801da177e4SLinus Torvalds 	{ USB_DEVICE(0x0557, 0x2001) },
781e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x05ab, 0x0002) },
782e3cb7bdeSDaniel Gimpelevich 	{ USB_DEVICE(0x06c6, 0x0100) },
7831da177e4SLinus Torvalds 	{ USB_DEVICE(0x0729, 0x1284) },
7841da177e4SLinus Torvalds 	{ USB_DEVICE(0x1293, 0x0002) },
7851da177e4SLinus Torvalds 	{ }						/* Terminating entry */
7861da177e4SLinus Torvalds };
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds MODULE_DEVICE_TABLE (usb, uss720_table);
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds static struct usb_driver uss720_driver = {
7921da177e4SLinus Torvalds 	.name =		"uss720",
7931da177e4SLinus Torvalds 	.probe =	uss720_probe,
7941da177e4SLinus Torvalds 	.disconnect =	uss720_disconnect,
7951da177e4SLinus Torvalds 	.id_table =	uss720_table,
7961da177e4SLinus Torvalds };
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds MODULE_AUTHOR(DRIVER_AUTHOR);
8011da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
8021da177e4SLinus Torvalds MODULE_LICENSE("GPL");
8031da177e4SLinus Torvalds 
uss720_init(void)8041da177e4SLinus Torvalds static int __init uss720_init(void)
8051da177e4SLinus Torvalds {
8061da177e4SLinus Torvalds 	int retval;
8071da177e4SLinus Torvalds 	retval = usb_register(&uss720_driver);
8081da177e4SLinus Torvalds 	if (retval)
8091da177e4SLinus Torvalds 		goto out;
8101da177e4SLinus Torvalds 
811c35c376fSGreg Kroah-Hartman 	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
8121b29a375SGreg Kroah-Hartman 	printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose "
8131b29a375SGreg Kroah-Hartman 	       "driver to allow nonstandard\n");
8141b29a375SGreg Kroah-Hartman 	printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over "
8151b29a375SGreg Kroah-Hartman 	       "USS720 usb to parallel cables\n");
8161b29a375SGreg Kroah-Hartman 	printk(KERN_INFO KBUILD_MODNAME ": If you just want to connect to a "
8171b29a375SGreg Kroah-Hartman 	       "printer, use usblp instead\n");
8181da177e4SLinus Torvalds out:
8191da177e4SLinus Torvalds 	return retval;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds 
uss720_cleanup(void)8221da177e4SLinus Torvalds static void __exit uss720_cleanup(void)
8231da177e4SLinus Torvalds {
8241da177e4SLinus Torvalds 	usb_deregister(&uss720_driver);
8251da177e4SLinus Torvalds }
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds module_init(uss720_init);
8281da177e4SLinus Torvalds module_exit(uss720_cleanup);
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds /* --------------------------------------------------------------------- */
831