Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b6962f9 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

USB: ipaq: reimplement using generic framework



Kill custom fifo, read and write implementations (single-urb and fifo,
but still maintained list of 256*256b urb buffers per port).

Compile-only tested.

Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 695aaae6
Loading
Loading
Loading
Loading
+10 −323
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include "ipaq.h"

#define KP_RETRIES	100

@@ -64,7 +63,7 @@
 * Version Information
 */

#define DRIVER_VERSION "v0.5"
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
#define DRIVER_DESC "USB PocketPC PDA driver"

@@ -76,20 +75,8 @@ static int initial_wait;
/* Function prototypes for an ipaq */
static int  ipaq_open(struct tty_struct *tty,
			struct usb_serial_port *port);
static void ipaq_close(struct usb_serial_port *port);
static int  ipaq_calc_num_ports(struct usb_serial *serial);
static int  ipaq_startup(struct usb_serial *serial);
static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
			const unsigned char *buf, int count);
static int ipaq_write_bulk(struct usb_serial_port *port,
				const unsigned char *buf, int count);
static void ipaq_write_gather(struct usb_serial_port *port);
static void ipaq_read_bulk_callback(struct urb *urb);
static void ipaq_write_bulk_callback(struct urb *urb);
static int ipaq_write_room(struct tty_struct *tty);
static int ipaq_chars_in_buffer(struct tty_struct *tty);
static void ipaq_destroy_lists(struct usb_serial_port *port);


static struct usb_device_id ipaq_id_table [] = {
	/* The first entry is a placeholder for the insmod-specified device */
@@ -571,65 +558,22 @@ static struct usb_serial_driver ipaq_device = {
	.description =		"PocketPC PDA",
	.usb_driver =		&ipaq_driver,
	.id_table =		ipaq_id_table,
	.bulk_in_size =		URBDATA_SIZE,
	.bulk_out_size =	URBDATA_SIZE,
	.bulk_in_size =		256,
	.bulk_out_size =	256,
	.open =			ipaq_open,
	.close =		ipaq_close,
	.attach =		ipaq_startup,
	.calc_num_ports =	ipaq_calc_num_ports,
	.write =		ipaq_write,
	.write_room =		ipaq_write_room,
	.chars_in_buffer =	ipaq_chars_in_buffer,
	.read_bulk_callback =	ipaq_read_bulk_callback,
	.write_bulk_callback =	ipaq_write_bulk_callback,
};

static spinlock_t	write_list_lock;
static int		bytes_in;
static int		bytes_out;

static int ipaq_open(struct tty_struct *tty,
			struct usb_serial_port *port)
{
	struct usb_serial	*serial = port->serial;
	struct ipaq_private	*priv;
	struct ipaq_packet	*pkt;
	int			i, result = 0;
	int			result = 0;
	int			retries = connect_retries;

	dbg("%s - port %d", __func__, port->number);

	bytes_in = 0;
	bytes_out = 0;
	priv = kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
	if (priv == NULL) {
		dev_err(&port->dev, "%s - Out of memory\n", __func__);
		return -ENOMEM;
	}
	usb_set_serial_port_data(port, priv);
	priv->active = 0;
	priv->queue_len = 0;
	priv->free_len = 0;
	INIT_LIST_HEAD(&priv->queue);
	INIT_LIST_HEAD(&priv->freelist);

	for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
		pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
		if (pkt == NULL)
			goto enomem;

		pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
		if (pkt->data == NULL) {
			kfree(pkt);
			goto enomem;
		}
		pkt->len = 0;
		pkt->written = 0;
		INIT_LIST_HEAD(&pkt->list);
		list_add(&pkt->list, &priv->freelist);
		priv->free_len += PACKET_SIZE;
	}

	msleep(1000*initial_wait);

	/*
@@ -639,7 +583,6 @@ static int ipaq_open(struct tty_struct *tty,
	 * through. Since this has a reasonably high failure rate, we retry
	 * several times.
	 */

	while (retries--) {
		result = usb_control_msg(serial->dev,
				usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
@@ -649,269 +592,15 @@ static int ipaq_open(struct tty_struct *tty,

		msleep(1000);
	}

	if (!retries && result) {
		dev_err(&port->dev, "%s - failed doing control urb, error %d\n",			__func__, result);
		goto error;
	}

	/* Start reading from the device */
	usb_fill_bulk_urb(port->read_urb, serial->dev,
		usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
		port->read_urb->transfer_buffer,
		port->read_urb->transfer_buffer_length,
		ipaq_read_bulk_callback, port);

	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
	if (result) {
		dev_err(&port->dev,
			"%s - failed submitting read urb, error %d\n",
		dev_err(&port->dev, "%s - failed doing control urb, error %d\n",
							__func__, result);
		goto error;
	}

	return 0;

enomem:
	result = -ENOMEM;
	dev_err(&port->dev, "%s - Out of memory\n", __func__);
error:
	ipaq_destroy_lists(port);
	kfree(priv);
		return result;
	}


static void ipaq_close(struct usb_serial_port *port)
{
	struct ipaq_private	*priv = usb_get_serial_port_data(port);

	dbg("%s - port %d", __func__, port->number);

	/*
	 * shut down bulk read and write
	 */
	usb_kill_urb(port->write_urb);
	usb_kill_urb(port->read_urb);
	ipaq_destroy_lists(port);
	kfree(priv);
	usb_set_serial_port_data(port, NULL);

	/* Uncomment the following line if you want to see some statistics
	 * in your syslog */
	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
}

static void ipaq_read_bulk_callback(struct urb *urb)
{
	struct usb_serial_port	*port = urb->context;
	struct tty_struct	*tty;
	unsigned char		*data = urb->transfer_buffer;
	int			result;
	int status = urb->status;

	dbg("%s - port %d", __func__, port->number);

	if (status) {
		dbg("%s - nonzero read bulk status received: %d",
		    __func__, status);
		return;
	}

	usb_serial_debug_data(debug, &port->dev, __func__,
						urb->actual_length, data);

	tty = tty_port_tty_get(&port->port);
	if (tty && urb->actual_length) {
		tty_insert_flip_string(tty, data, urb->actual_length);
		tty_flip_buffer_push(tty);
		bytes_in += urb->actual_length;
	}
	tty_kref_put(tty);

	/* Continue trying to always read  */
	usb_fill_bulk_urb(port->read_urb, port->serial->dev,
	    usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
	    port->read_urb->transfer_buffer,
	    port->read_urb->transfer_buffer_length,
	    ipaq_read_bulk_callback, port);
	result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
	if (result)
		dev_err(&port->dev,
			"%s - failed resubmitting read urb, error %d\n",
			__func__, result);
	return;
}

static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
			const unsigned char *buf, int count)
{
	const unsigned char	*current_position = buf;
	int			bytes_sent = 0;
	int			transfer_size;

	dbg("%s - port %d", __func__, port->number);

	while (count > 0) {
		transfer_size = min(count, PACKET_SIZE);
		if (ipaq_write_bulk(port, current_position, transfer_size))
			break;
		current_position += transfer_size;
		bytes_sent += transfer_size;
		count -= transfer_size;
		bytes_out += transfer_size;
	}

	return bytes_sent;
	return usb_serial_generic_open(tty, port);
}

static int ipaq_write_bulk(struct usb_serial_port *port,
					const unsigned char *buf, int count)
{
	struct ipaq_private	*priv = usb_get_serial_port_data(port);
	struct ipaq_packet	*pkt = NULL;
	int			result = 0;
	unsigned long		flags;

	if (priv->free_len <= 0) {
		dbg("%s - we're stuffed", __func__);
		return -EAGAIN;
	}

	spin_lock_irqsave(&write_list_lock, flags);
	if (!list_empty(&priv->freelist)) {
		pkt = list_entry(priv->freelist.next, struct ipaq_packet, list);
		list_del(&pkt->list);
		priv->free_len -= PACKET_SIZE;
	}
	spin_unlock_irqrestore(&write_list_lock, flags);
	if (pkt == NULL) {
		dbg("%s - we're stuffed", __func__);
		return -EAGAIN;
	}

	memcpy(pkt->data, buf, count);
	usb_serial_debug_data(debug, &port->dev, __func__, count, pkt->data);

	pkt->len = count;
	pkt->written = 0;
	spin_lock_irqsave(&write_list_lock, flags);
	list_add_tail(&pkt->list, &priv->queue);
	priv->queue_len += count;
	if (priv->active == 0) {
		priv->active = 1;
		ipaq_write_gather(port);
		spin_unlock_irqrestore(&write_list_lock, flags);
		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
		if (result)
			dev_err(&port->dev,
				"%s - failed submitting write urb, error %d\n",
				__func__, result);
	} else {
		spin_unlock_irqrestore(&write_list_lock, flags);
	}
	return result;
}

static void ipaq_write_gather(struct usb_serial_port *port)
{
	struct ipaq_private	*priv = usb_get_serial_port_data(port);
	struct usb_serial	*serial = port->serial;
	int			count, room;
	struct ipaq_packet	*pkt, *tmp;
	struct urb		*urb = port->write_urb;

	room = URBDATA_SIZE;
	list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
		count = min(room, (int)(pkt->len - pkt->written));
		memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
		       pkt->data + pkt->written, count);
		room -= count;
		pkt->written += count;
		priv->queue_len -= count;
		if (pkt->written == pkt->len) {
			list_move(&pkt->list, &priv->freelist);
			priv->free_len += PACKET_SIZE;
		}
		if (room == 0)
			break;
	}

	count = URBDATA_SIZE - room;
	usb_fill_bulk_urb(port->write_urb, serial->dev,
		usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
		port->write_urb->transfer_buffer, count,
		ipaq_write_bulk_callback, port);
	return;
}

static void ipaq_write_bulk_callback(struct urb *urb)
{
	struct usb_serial_port	*port = urb->context;
	struct ipaq_private	*priv = usb_get_serial_port_data(port);
	unsigned long		flags;
	int			result;
	int status = urb->status;

	dbg("%s - port %d", __func__, port->number);

	if (status) {
		dbg("%s - nonzero write bulk status received: %d",
		    __func__, status);
		return;
	}

	spin_lock_irqsave(&write_list_lock, flags);
	if (!list_empty(&priv->queue)) {
		ipaq_write_gather(port);
		spin_unlock_irqrestore(&write_list_lock, flags);
		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
		if (result)
			dev_err(&port->dev,
				"%s - failed submitting write urb, error %d\n",
				__func__, result);
	} else {
		priv->active = 0;
		spin_unlock_irqrestore(&write_list_lock, flags);
	}

	usb_serial_port_softint(port);
}

static int ipaq_write_room(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct ipaq_private	*priv = usb_get_serial_port_data(port);

	dbg("%s - freelen %d", __func__, priv->free_len);
	return priv->free_len;
}

static int ipaq_chars_in_buffer(struct tty_struct *tty)
{
	struct usb_serial_port *port = tty->driver_data;
	struct ipaq_private	*priv = usb_get_serial_port_data(port);

	dbg("%s - queuelen %d", __func__, priv->queue_len);
	return priv->queue_len;
}

static void ipaq_destroy_lists(struct usb_serial_port *port)
{
	struct ipaq_private	*priv = usb_get_serial_port_data(port);
	struct ipaq_packet	*pkt, *tmp;

	list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
		kfree(pkt->data);
		kfree(pkt);
	}
	list_for_each_entry_safe(pkt, tmp, &priv->freelist, list) {
		kfree(pkt->data);
		kfree(pkt);
	}
}


static int ipaq_calc_num_ports(struct usb_serial *serial)
{
	/*
@@ -970,7 +659,6 @@ static int ipaq_startup(struct usb_serial *serial)
static int __init ipaq_init(void)
{
	int retval;
	spin_lock_init(&write_list_lock);
	retval = usb_serial_register(&ipaq_device);
	if (retval)
		goto failed_usb_serial_register;
@@ -991,7 +679,6 @@ static int __init ipaq_init(void)
	return retval;
}


static void __exit ipaq_exit(void)
{
	usb_deregister(&ipaq_driver);

drivers/usb/serial/ipaq.h

deleted100644 → 0
+0 −54
Original line number Diff line number Diff line
/*
 * USB Compaq iPAQ driver
 *
 *	Copyright (C) 2001 - 2002
 *	    Ganesh Varadarajan <ganesh@veritas.com>
 *
 *	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.
 *
 */

#ifndef __LINUX_USB_SERIAL_IPAQ_H
#define __LINUX_USB_SERIAL_IPAQ_H

/*
 * Since we can't queue our bulk write urbs (don't know why - it just
 * doesn't work), we can send down only one write urb at a time. The simplistic
 * approach taken by the generic usbserial driver will work, but it's not good
 * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write
 * requests coming from the line discipline. This is done by chaining them
 * in lists of struct ipaq_packet, each packet holding a maximum of
 * PACKET_SIZE bytes.
 *
 * ipaq_write() can be called from bottom half context; hence we can't
 * allocate memory for packets there. So we initialize a pool of packets at
 * the first open and maintain a freelist.
 *
 * The value of PACKET_SIZE was empirically determined by
 * checking the maximum write sizes sent down by the ppp ldisc.
 * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size.
 */

struct ipaq_packet {
	char			*data;
	size_t			len;
	size_t			written;
	struct list_head	list;
};

struct ipaq_private {
	int			active;
	int			queue_len;
	int			free_len;
	struct list_head	queue;
	struct list_head	freelist;
};

#define URBDATA_SIZE		4096
#define URBDATA_QUEUE_MAX	(64 * 1024)
#define PACKET_SIZE		256

#endif