cregit-Linux how code gets into the kernel

Release 4.11 drivers/usb/misc/uss720.c

Directory: drivers/usb/misc
/*****************************************************************************/

/*
 *      uss720.c  --  USS720 USB Parport Cable.
 *
 *      Copyright (C) 1999, 2005, 2010
 *          Thomas Sailer (t.sailer@alumni.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Based on parport_pc.c
 *
 *  History:
 *   0.1  04.08.1999  Created
 *   0.2  07.08.1999  Some fixes mainly suggested by Tim Waugh
 *                    Interrupt handling currently disabled because
 *                    usb_request_irq crashes somewhere within ohci.c
 *                    for no apparent reason (that is for me, anyway)
 *                    ECP currently untested
 *   0.3  10.08.1999  fixing merge errors
 *   0.4  13.08.1999  Added Vendor/Product ID of Brad Hard's cable
 *   0.5  20.09.1999  usb_control_msg wrapper used
 *        Nov01.2000  usb_device_table support by Adam J. Richter
 *        08.04.2001  Identify version on module load.  gb
 *   0.6  02.09.2005  Fix "scheduling in interrupt" problem by making save/restore
 *                    context asynchronous
 *
 */

/*****************************************************************************/

#include <linux/module.h>
#include <linux/socket.h>
#include <linux/parport.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/delay.h>
#include <linux/completion.h>
#include <linux/kref.h>
#include <linux/slab.h>
#include <linux/sched/signal.h>

/*
 * Version Information
 */

#define DRIVER_VERSION "v0.6"

#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch"

#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip"

/* --------------------------------------------------------------------- */


struct parport_uss720_private {
	
struct usb_device *usbdev;
	
struct parport *pp;
	
struct kref ref_count;
	
__u8 reg[7];  /* USB registers */
	
struct list_head asynclist;
	
spinlock_t asynclock;
};


struct uss720_async_request {
	
struct parport_uss720_private *priv;
	
struct kref ref_count;
	
struct list_head asynclist;
	
struct completion compl;
	
struct urb *urb;
	
struct usb_ctrlrequest *dr;
	
__u8 reg[7];
};

/* --------------------------------------------------------------------- */


static void destroy_priv(struct kref *kref) { struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count); dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n"); usb_put_dev(priv->usbdev); kfree(priv); }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Sailer3978.00%150.00%
Greg Kroah-Hartman1122.00%150.00%
Total50100.00%2100.00%


static void destroy_async(struct kref *kref) { struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count); struct parport_uss720_private *priv = rq->priv; unsigned long flags; if (likely(rq->urb)) usb_free_urb(rq->urb); kfree(rq->dr); spin_lock_irqsave(&priv->asynclock, flags); list_del_init(&rq->asynclist); spin_unlock_irqrestore(&priv->asynclock, flags); kfree(rq); kref_put(&priv->ref_count, destroy_priv); }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Sailer9893.33%150.00%
Johan Hovold76.67%150.00%
Total105100.00%2100.00%

/* --------------------------------------------------------------------- */
static void async_complete(struct urb *urb) { struct uss720_async_request *rq; struct parport *pp; struct parport_uss720_private *priv; int status = urb->status; rq = urb->context; priv = rq->priv; pp = priv->pp; if (status) { dev_err(&urb->dev->dev, "async_complete: urb error %d\n", status); } else if (rq->dr->bRequest == 3) { memcpy(priv->reg, rq->reg, sizeof(priv->reg)); #if 0 dev_dbg(&priv->usbdev->dev, "async_complete regs %7ph\n", priv->reg); #endif /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ if (rq->reg[2] & rq->reg[1] & 0x10 && pp) parport_generic_irq(pp); } complete(&rq->compl); kref_put(&rq->ref_count, destroy_async); }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Sailer13488.16%120.00%
Greg Kroah-Hartman1610.53%240.00%
Johan Hovold10.66%120.00%
Andy Shevchenko10.66%120.00%
Total152100.00%5100.00%


static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, __u8 request, __u8 requesttype, __u16 value, __u16 index, gfp_t mem_flags) { struct usb_device *usbdev; struct uss720_async_request *rq; unsigned long flags; int ret; if (!priv) return NULL; usbdev = priv->usbdev; if (!usbdev) return NULL; rq = kzalloc(sizeof(struct uss720_async_request), mem_flags); if (!rq) return NULL; kref_init(&rq->ref_count); INIT_LIST_HEAD(&rq->asynclist); init_completion(&rq->compl); kref_get(&priv->ref_count); rq->priv = priv; rq->urb = usb_alloc_urb(0, mem_flags); if (!rq->urb) { kref_put(&rq->ref_count, destroy_async); return NULL; } rq->dr = kmalloc(sizeof(*rq->dr), mem_flags); if (!rq->dr) { kref_put(&rq->ref_count, destroy_async); return NULL; } rq->dr->bRequestType = requesttype; rq->dr->bRequest = request; rq->dr->wValue = cpu_to_le16(value); rq->dr->wIndex = cpu_to_le16(index); rq->dr->wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0); usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0), (unsigned char *)rq->dr, (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq); /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */ spin_lock_irqsave(&priv->asynclock, flags); list_add_tail(&rq->asynclist, &priv->asynclist); spin_unlock_irqrestore(&priv->asynclock, flags); kref_get(&rq->ref_count); ret = usb_submit_urb(rq->urb, mem_flags); if (!ret) return rq; destroy_async(&rq->ref_count); dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Sailer35184.99%120.00%
Johan Hovold4510.90%120.00%
Peter Holik92.18%120.00%
Greg Kroah-Hartman71.69%120.00%
Al Viro10.24%120.00%
Total413100.00%5100.00%


static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv) { struct uss720_async_request *rq; unsigned long flags; unsigned int ret = 0; spin_lock_irqsave(&priv->asynclock, flags); list_for_each_entry(rq, &priv->asynclist, asynclist) { usb_unlink_urb(rq->urb); ret++; } spin_unlock_irqrestore(&priv->asynclock, flags); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Thomas Sailer6998.57%150.00%
Linus Torvalds (pre-git)11.43%150.00%
Total70100.00%2100.00%

/* --------------------------------------------------------------------- */
static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; static const unsigned char regindex[9] = { 4, 0, 1, 5, 5, 0, 2, 3, 6 }; int ret; if (!pp) return -EIO; priv = pp->private_data; rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags); if (!rq) { dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed", (unsigned int)reg); return -EIO; } if (!val) { kref_put(&rq->ref_count, destroy_async); return 0; } if (wait_for_completion_timeout(&rq->compl, HZ)) { ret = rq->urb->status; *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; if (ret) printk(KERN_WARNING "get_1284_register: " "usb error %d\n", ret); kref_put(&rq->ref_count, destroy_async); return ret; } printk(KERN_WARNING "get_1284_register timeout\n"); kill_all_async_requests_priv(priv); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)13757.56%228.57%
Thomas Sailer8334.87%114.29%
Greg Kroah-Hartman156.30%228.57%
Linus Torvalds20.84%114.29%
Al Viro10.42%114.29%
Total238100.00%7100.00%


static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags) { struct parport_uss720_private *priv; struct uss720_async_request *rq; if (!pp) return -EIO; priv = pp->private_data; rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags); if (!rq) { dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val); return -EIO; } kref_put(&rq->ref_count, destroy_async); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8165.32%240.00%
Thomas Sailer3427.42%120.00%
Greg Kroah-Hartman86.45%120.00%
Al Viro10.81%120.00%
Total124100.00%5100.00%

/* --------------------------------------------------------------------- */ /* ECR modes */ #define ECR_SPP 00 #define ECR_PS2 01 #define ECR_PPF 02 #define ECR_ECP 03 #define ECR_EPP 04 /* Safely change the mode bits in the ECR */
static int change_mode(struct parport *pp, int m) { struct parport_uss720_private *priv = pp->private_data; int mode; __u8 reg; if (get_1284_register(pp, 6, &reg, GFP_KERNEL)) return -EIO; /* Bits <7:5> contain the mode. */ mode = (priv->reg[2] >> 5) & 0x7; if (mode == m) return 0; /* We have to go through mode 000 or 001 */ if (mode > ECR_PS2 && m > ECR_PS2) if (change_mode(pp, ECR_PS2)) return -EIO; if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) { /* This mode resets the FIFO, so we may * have to wait for it to drain first. */ unsigned long expire = jiffies + pp->physport->cad->timeout; switch (mode) { case ECR_PPF: /* Parallel Port FIFO mode */ case ECR_ECP: /* ECP Parallel Port mode */ /* Poll slowly. */ for (;;) { if (get_1284_register(pp, 6, &reg, GFP_KERNEL)) return -EIO; if (priv->reg[2] & 0x01) break; if (time_after_eq (jiffies, expire)) /* The FIFO is stuck. */ return -EBUSY; msleep_interruptible(10); if (signal_pending (current)) break; } } } /* Set the mode. */ if (set_1284_register(pp, 6, m << 5, GFP_KERNEL)) return -EIO; if (get_1284_register(pp, 6, &reg, GFP_KERNEL)) return -EIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)21384.86%120.00%
Thomas Sailer3413.55%120.00%
Nishanth Aravamudan20.80%120.00%
Greg Kroah-Hartman10.40%120.00%
Linus Torvalds10.40%120.00%
Total251100.00%5100.00%

/* * Clear TIMEOUT BIT in EPP MODE */
static int clear_epp_timeout(struct parport *pp) { unsigned char stat; if (get_1284_register(pp, 1, &stat, GFP_KERNEL)) return 1; return stat & 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3594.59%150.00%
Thomas Sailer25.41%150.00%
Total37100.00%2100.00%

/* * Access functions. */ #if 0 static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id) { struct parport *pp = (struct parport *)dev_id; struct parport_uss720_private *priv = pp->private_data; if (usbstatus != 0 || len < 4 || !buffer) return 1; memcpy(priv->reg, buffer, 4); /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ if (priv->reg[2] & priv->reg[1] & 0x10) parport_generic_irq(pp); return 1; } #endif
static void parport_uss720_write_data(struct parport *pp, unsigned char d) { set_1284_register(pp, 0, d, GFP_KERNEL); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2492.31%150.00%
Thomas Sailer27.69%150.00%
Total26100.00%2100.00%


static unsigned char parport_uss720_read_data(struct parport *pp) { unsigned char ret; if (get_1284_register(pp, 0, &ret, GFP_KERNEL)) return 0; return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3494.44%150.00%
Thomas Sailer25.56%150.00%
Total36100.00%2100.00%


static void parport_uss720_write_control(struct parport *pp, unsigned char d) { struct parport_uss720_private *priv = pp->private_data; d = (d & 0xf) | (priv->reg[1] & 0xf0); if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6496.97%150.00%
Thomas Sailer23.03%150.00%
Total66100.00%2100.00%


static unsigned char parport_uss720_read_control(struct parport *pp) { struct parport_uss720_private *priv = pp->private_data; return priv->reg[1] & 0xf; /* Use soft copy */ }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)32100.00%1100.00%
Total32100.00%1100.00%


static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val) { struct parport_uss720_private *priv = pp->private_data; unsigned char d; mask &= 0x0f; val &= 0x0f; d = (priv->reg[1] & (~mask)) ^ val; if (set_1284_register(pp, 2, d, GFP_KERNEL)) return 0; priv->reg[1] = d; return d & 0xf; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8797.75%150.00%
Thomas Sailer22.25%150.00%
Total89100.00%2100.00%


static unsigned char parport_uss720_read_status(struct parport *pp) { unsigned char ret; if (get_1284_register(pp, 1, &ret, GFP_KERNEL)) return 0; return ret & 0xf8; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3694.74%150.00%
Thomas Sailer25.26%150.00%
Total38100.00%2100.00%


static void parport_uss720_disable_irq(struct parport *pp) { struct parport_uss720_private *priv = pp->private_data; unsigned char d; d = priv->reg[1] & ~0x10; if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5796.61%150.00%
Thomas Sailer23.39%150.00%
Total59100.00%2100.00%


static void parport_uss720_enable_irq(struct parport *pp) { struct parport_uss720_private *priv = pp->private_data; unsigned char d; d = priv->reg[1] | 0x10; if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5696.55%150.00%
Thomas Sailer23.45%150.00%
Total58100.00%2100.00%


static void parport_uss720_data_forward (struct parport *pp) { struct parport_uss720_private *priv = pp->private_data; unsigned char d; d = priv->reg[1] & ~0x20; if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5796.61%150.00%
Thomas Sailer23.39%150.00%
Total59100.00%2100.00%


static void parport_uss720_data_reverse (struct parport *pp) { struct parport_uss720_private *priv = pp->private_data; unsigned char d; d = priv->reg[1] | 0x20; if (set_1284_register(pp, 2, d, GFP_KERNEL)) return; priv->reg[1] = d; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5696.55%150.00%
Thomas Sailer23.45%150.00%
Total58100.00%2100.00%


static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s) { s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); s->u.pc.ecr = 0x24; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)46100.00%1100.00%
Total46100.00%1100.00%


static void parport_uss720_save_state(struct parport *pp, struct parport_state *s) { struct parport_uss720_private *priv = pp->private_data; #if 0 if (get_1284_register(pp, 2, NULL, GFP_ATOMIC)) return; #endif s->u.pc.ctr = priv->reg[1]; s->u.pc.ecr = priv->reg[2]; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5590.16%150.00%
Thomas Sailer69.84%150.00%
Total61100.00%2100.00%


static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s) { struct parport_uss720_private *priv = pp->private_data; set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC); set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC); get_1284_register(pp, 2, NULL, GFP_ATOMIC); priv->reg[1] = s->u.pc.ctr; priv->reg[2] = s->u.pc.ecr; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5555.00%150.00%
Thomas Sailer4545.00%150.00%
Total100100.00%2100.00%


static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags) { struct parport_uss720_private *priv = pp->private_data; size_t got = 0; if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) break; buf++; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; } } change_mode(pp, ECR_PS2); return got; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10798.17%150.00%
Thomas Sailer21.83%150.00%
Total109100.00%2100.00%


static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags) { #if 0 struct parport_uss720_private *priv = pp->private_data; size_t written = 0; if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) break; ((char*)buf)++; if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) break; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; } } change_mode(pp, ECR_PS2); return written; #else struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; int rlen; int i; if (!usbdev) return 0; if (change_mode(pp, ECR_EPP)) return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000); if (i) printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buf, length, rlen); change_mode(pp, ECR_PS2); return rlen; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12497.64%562.50%
Alexey Dobriyan10.79%112.50%
Nishanth Aravamudan10.79%112.50%
Thomas Sailer10.79%112.50%
Total127100.00%8100.00%


static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags) { struct parport_uss720_private *priv = pp->private_data; size_t got = 0; if (change_mode(pp, ECR_EPP)) return 0; for (; got < length; got++) { if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL)) break; buf++; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; } } change_mode(pp, ECR_PS2); return got; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10798.17%150.00%
Thomas Sailer21.83%150.00%
Total109100.00%2100.00%


static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags) { struct parport_uss720_private *priv = pp->private_data; size_t written = 0; if (change_mode(pp, ECR_EPP)) return 0; for (; written < length; written++) { if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL)) break; buf++; if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) break; if (priv->reg[0] & 0x01) { clear_epp_timeout(pp); break; } } change_mode(pp, ECR_PS2); return written; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)12196.80%150.00%
Thomas Sailer43.20%150.00%
Total125100.00%2100.00%


static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags) { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; int rlen; int i; if (!usbdev) return 0; if (change_mode(pp, ECR_ECP)) return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000); if (i) printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11798.32%571.43%
Nishanth Aravamudan10.84%114.29%
Alexey Dobriyan10.84%114.29%
Total119100.00%7100.00%


static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags) { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; int rlen; int i; if (!usbdev) return 0; if (change_mode(pp, ECR_ECP)) return 0; i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000); if (i) printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11298.25%466.67%
Nishanth Aravamudan10.88%116.67%
Alexey Dobriyan10.88%116.67%
Total114100.00%6100.00%


static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags) { size_t written = 0; if (change_mode(pp, ECR_ECP)) return 0; for (; written < len; written++) { if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL)) break; buffer++; } change_mode(pp, ECR_PS2); return written; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)8197.59%150.00%
Thomas Sailer22.41%150.00%
Total83100.00%2100.00%


static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags) { struct parport_uss720_private *priv = pp->private_data; struct usb_device *usbdev = priv->usbdev; int rlen; int i; if (!usbdev) return 0; if (change_mode(pp, ECR_PPF)) return 0; i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000); if (i) printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %zu rlen %u\n", buffer, len, rlen); change_mode(pp, ECR_PS2); return rlen; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11798.32%571.43%
Nishanth Aravamudan10.84%114.29%
Alexey Dobriyan10.84%114.29%
Total119100.00%7100.00%

/* --------------------------------------------------------------------- */ static struct parport_operations parport_uss720_ops = { .owner = THIS_MODULE, .write_data = parport_uss720_write_data, .read_data = parport_uss720_read_data, .write_control = parport_uss720_write_control, .read_control = parport_uss720_read_control, .frob_control = parport_uss720_frob_control, .read_status = parport_uss720_read_status, .enable_irq = parport_uss720_enable_irq, .disable_irq = parport_uss720_disable_irq, .data_forward = parport_uss720_data_forward, .data_reverse = parport_uss720_data_reverse, .init_state = parport_uss720_init_state, .save_state = parport_uss720_save_state, .restore_state = parport_uss720_restore_state, .epp_write_data = parport_uss720_epp_write_data, .epp_read_data = parport_uss720_epp_read_data, .epp_write_addr = parport_uss720_epp_write_addr, .epp_read_addr = parport_uss720_epp_read_addr, .ecp_write_data = parport_uss720_ecp_write_data, .ecp_read_data = parport_uss720_ecp_read_data, .ecp_write_addr = parport_uss720_ecp_write_addr, .compat_write_data = parport_uss720_write_compat, .nibble_read_data = parport_ieee1284_read_nibble, .byte_read_data = parport_ieee1284_read_byte, }; /* --------------------------------------------------------------------- */
static int uss720_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf)); struct usb_host_interface *interface; struct usb_host_endpoint *endpoint; struct parport_uss720_private *priv; struct parport *pp; unsigned char reg; int i; dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n", le16_to_cpu(usbdev->descriptor.idVendor), le16_to_cpu(usbdev->descriptor.idProduct)); /* our known interfaces have 3 alternate settings */ if (intf->num_altsetting != 3) { usb_put_dev(usbdev); return -ENODEV; } i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); dev_dbg(&intf->dev, "set interface result %d\n", i); interface = intf->cur_altsetting; if (interface->desc.bNumEndpoints < 3) { usb_put_dev(usbdev); return -ENODEV; } /* * Allocate parport interface */ priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL); if (!priv) { usb_put_dev(usbdev); return -ENOMEM; } priv->pp = NULL; priv->usbdev = usbdev; kref_init(&priv->ref_count); spin_lock_init(&priv->asynclock); INIT_LIST_HEAD(&priv->asynclist); pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops); if (!pp) { printk(KERN_WARNING "uss720: could not register parport\n"); goto probe_abort; } priv->pp = pp; pp->private_data = priv; pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ set_1284_register(pp, 7, 0x00, GFP_KERNEL); set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */ set_1284_register(pp, 2, 0x0c, GFP_KERNEL); /* debugging */ get_1284_register(pp, 0, &reg, GFP_KERNEL); dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg); endpoint = &interface->endpoint[2]; dev_dbg(&intf->dev, "epaddr %d interval %d\n", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); parport_announce_port(pp); usb_set_intfdata(intf, pp); return 0; probe_abort: kill_all_async_requests_priv(priv); kref_put(&priv->ref_count, destroy_priv); return -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)21752.54%423.53%
Greg Kroah-Hartman8620.82%741.18%
Thomas Sailer8520.58%15.88%
Johan Hovold215.08%15.88%
Robert P. J. Day10.24%15.88%
Andy Shevchenko10.24%15.88%
Masanari Iida10.24%15.88%
Alan Stern10.24%15.88%
Total413100.00%17100.00%


static void uss720_disconnect(struct usb_interface *intf) { struct parport *pp = usb_get_intfdata(intf); struct parport_uss720_private *priv; struct usb_device *usbdev; dev_dbg(&intf->dev, "disconnect\n"); usb_set_intfdata(intf, NULL); if (pp) { priv = pp->private_data; usbdev = priv->usbdev; priv->usbdev = NULL; priv->pp = NULL; dev_dbg(&intf->dev, "parport_remove_port\n"); parport_remove_port(pp); parport_put_port(pp); kill_all_async_requests_priv(priv); kref_put(&priv->ref_count, destroy_priv); } dev_dbg(&intf->dev, "disconnect done\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman4435.77%342.86%
Thomas Sailer4133.33%114.29%
Linus Torvalds (pre-git)3629.27%228.57%
Al Viro21.63%114.29%
Total123100.00%7100.00%

/* table of cables that work through this driver */ static const struct usb_device_id uss720_table[] = { { USB_DEVICE(0x047e, 0x1001) }, { USB_DEVICE(0x0557, 0x2001) }, { USB_DEVICE(0x0729, 0x1284) }, { USB_DEVICE(0x1293, 0x0002) }, { USB_DEVICE(0x050d, 0x0002) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, uss720_table); static struct usb_driver uss720_driver = { .name = "uss720", .probe = uss720_probe, .disconnect = uss720_disconnect, .id_table = uss720_table, }; /* --------------------------------------------------------------------- */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL");
static int __init uss720_init(void) { int retval; retval = usb_register(&uss720_driver); if (retval) goto out; printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose " "driver to allow nonstandard\n"); printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over " "USS720 usb to parallel cables\n"); printk(KERN_INFO KBUILD_MODNAME ": If you just want to connect to a " "printer, use usblp instead\n"); out: return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Greg Kroah-Hartman2234.92%116.67%
Linus Torvalds (pre-git)1930.16%233.33%
Daniele Bellucci1523.81%116.67%
Thomas Sailer69.52%116.67%
Linus Torvalds11.59%116.67%
Total63100.00%6100.00%


static void __exit uss720_cleanup(void) { usb_deregister(&uss720_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)15100.00%1100.00%
Total15100.00%1100.00%

module_init(uss720_init); module_exit(uss720_cleanup); /* --------------------------------------------------------------------- */

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)250661.29%1326.00%
Thomas Sailer113227.68%24.00%
Greg Kroah-Hartman2846.95%1224.00%
Johan Hovold751.83%24.00%
Linus Torvalds290.71%510.00%
Daniele Bellucci150.37%12.00%
Peter Holik90.22%12.00%
Nishanth Aravamudan90.22%24.00%
Rusty Russell80.20%12.00%
Al Viro50.12%24.00%
Alexey Dobriyan40.10%12.00%
Tejun Heo30.07%12.00%
Ingo Molnar30.07%12.00%
Andy Shevchenko20.05%12.00%
Alan Stern10.02%12.00%
Márton Németh10.02%12.00%
Jeff Garzik10.02%12.00%
Robert P. J. Day10.02%12.00%
Masanari Iida10.02%12.00%
Total4089100.00%50100.00%
Directory: drivers/usb/misc
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.