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, ®, 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, ®, 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, ®, 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, ®, 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