Greg,
Where is the Makefile patch ?
On Fri, 21 Dec 2001, Greg KH wrote:
> Hi,
>
> Here's a patch against 2.4.17 that adds the usb-serial ipaq driver. The
> patch is by Ganesh Varadarajan.
>
> thanks,
>
> greg k-h
>
>
>
> diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
> --- /dev/null Wed Dec 31 16:00:00 1969
> +++ b/drivers/usb/serial/ipaq.c Fri Dec 21 12:58:16 2001
> @@ -0,0 +1,532 @@
> +/*
> + * USB Compaq iPAQ driver
> + *
> + * Copyright (C) 2001
> + * Ganesh Varadarajan <[EMAIL PROTECTED]>
> + *
> + * 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.
> + *
> + */
> +
> +#include <linux/config.h>
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/signal.h>
> +#include <linux/errno.h>
> +#include <linux/poll.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/fcntl.h>
> +#include <linux/tty.h>
> +#include <linux/tty_driver.h>
> +#include <linux/tty_flip.h>
> +#include <linux/module.h>
> +#include <linux/spinlock.h>
> +#include <linux/usb.h>
> +
> +#ifdef CONFIG_USB_SERIAL_DEBUG
> + static int debug = 1;
> +#else
> + static int debug = 0;
> +#endif
> +
> +#include "usb-serial.h"
> +#include "ipaq.h"
> +
> +/*
> + * Version Information
> + */
> +#define DRIVER_VERSION "v0.1"
> +#define DRIVER_AUTHOR "Ganesh Varadarajan <[EMAIL PROTECTED]>"
> +#define DRIVER_DESC "USB Compaq iPAQ driver"
> +
> +/* Function prototypes for an ipaq */
> +static int ipaq_open (struct usb_serial_port *port, struct file *filp);
> +static void ipaq_close (struct usb_serial_port *port, struct file *filp);
> +static int ipaq_startup (struct usb_serial *serial);
> +static void ipaq_shutdown (struct usb_serial *serial);
> +static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned
>char *buf,
> + int count);
> +static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const
>unsigned char *buf,
> + int count);
> +static int ipaq_write_flush(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 usb_serial_port *port);
> +static int ipaq_chars_in_buffer(struct usb_serial_port *port);
> +static void ipaq_destroy_lists(struct usb_serial_port *port);
> +
> +
> +static __devinitdata struct usb_device_id ipaq_id_table [] = {
> + { USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
> + { } /* Terminating entry */
> +};
> +
> +MODULE_DEVICE_TABLE (usb, ipaq_id_table);
> +
> +/* All of the device info needed for the Compaq iPAQ */
> +struct usb_serial_device_type ipaq_device = {
> + name: "Compaq iPAQ",
> + id_table: ipaq_id_table,
> + needs_interrupt_in: MUST_HAVE_NOT,
> + needs_bulk_in: MUST_HAVE,
> + needs_bulk_out: MUST_HAVE,
> + num_interrupt_in: 0,
> + num_bulk_in: 1,
> + num_bulk_out: 1,
> + num_ports: 1,
> + open: ipaq_open,
> + close: ipaq_close,
> + startup: ipaq_startup,
> + shutdown: ipaq_shutdown,
> + 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 usb_serial_port *port, struct file *filp)
> +{
> + struct usb_serial *serial = port->serial;
> + struct ipaq_private *priv;
> + struct ipaq_packet *pkt;
> + int i, result = 0;
> +
> + if (port_paranoia_check(port, __FUNCTION__)) {
> + return -ENODEV;
> + }
> +
> + dbg(__FUNCTION__ " - port %d", port->number);
> +
> + down(&port->sem);
> +
> + ++port->open_count;
> + MOD_INC_USE_COUNT;
> +
> + if (!port->active) {
> + port->active = 1;
> + bytes_in = 0;
> + bytes_out = 0;
> + priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private),
>GFP_KERNEL);
> + if (priv == NULL) {
> + err(__FUNCTION__ " - Out of memory");
> + return -ENOMEM;
> + }
> + port->private = (void *)priv;
> + priv->active = 0;
> + priv->queue_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;
> + }
> +
> + /*
> + * Force low latency on. This will immediately push data to the line
> + * discipline instead of queueing.
> + */
> +
> + port->tty->low_latency = 1;
> +
> + /*
> + * Lose the small buffers usbserial provides. Make larger ones.
> + */
> +
> + kfree(port->bulk_in_buffer);
> + kfree(port->bulk_out_buffer);
> + port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
> + if (port->bulk_in_buffer == NULL) {
> + goto enomem;
> + }
> + port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
> + if (port->bulk_out_buffer == NULL) {
> + kfree(port->bulk_in_buffer);
> + goto enomem;
> + }
> + port->read_urb->transfer_buffer = port->bulk_in_buffer;
> + port->write_urb->transfer_buffer = port->bulk_out_buffer;
> + port->read_urb->transfer_buffer_length = URBDATA_SIZE;
> + port->bulk_out_size = port->write_urb->transfer_buffer_length =
>URBDATA_SIZE;
> +
> + /* Start reading from the device */
> + 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);
> + if (result) {
> + err(__FUNCTION__ " - failed submitting read urb, error %d",
>result);
> + }
> +
> + /*
> + * Send out two control messages observed in win98 sniffs. Not sure
>what
> + * they do.
> + */
> +
> + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
>0x22, 0x21,
> + 0x1, 0, NULL, 0, 5 * HZ);
> + if (result < 0) {
> + err(__FUNCTION__ " - failed doing control urb, error %d",
>result);
> + }
> + result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
>0x22, 0x21,
> + 0x1, 0, NULL, 0, 5 * HZ);
> + if (result < 0) {
> + err(__FUNCTION__ " - failed doing control urb, error %d",
>result);
> + }
> + }
> +
> + up(&port->sem);
> +
> + return result;
> +
> +enomem:
> + ipaq_destroy_lists(port);
> + kfree(priv);
> + err(__FUNCTION__ " - Out of memory");
> + return -ENOMEM;
> +}
> +
> +
> +static void ipaq_close(struct usb_serial_port *port, struct file *filp)
> +{
> + struct usb_serial *serial;
> + struct ipaq_private *priv = port->private;
> +
> + if (port_paranoia_check(port, __FUNCTION__)) {
> + return;
> + }
> +
> + dbg(__FUNCTION__ " - port %d", port->number);
> +
> + serial = get_usb_serial(port, __FUNCTION__);
> + if (!serial)
> + return;
> +
> + down (&port->sem);
> +
> + --port->open_count;
> +
> + if (port->open_count <= 0) {
> +
> + /*
> + * shut down bulk read and write
> + */
> +
> + usb_unlink_urb(port->write_urb);
> + usb_unlink_urb(port->read_urb);
> + ipaq_destroy_lists(port);
> + kfree(priv);
> + port->private = NULL;
> + port->active = 0;
> + port->open_count = 0;
> +
> + }
> + up (&port->sem);
> +
> + /* 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); */
> +
> + MOD_DEC_USE_COUNT;
> +}
> +
> +static void ipaq_read_bulk_callback(struct urb *urb)
> +{
> + struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
> + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
> + struct tty_struct *tty;
> + unsigned char *data = urb->transfer_buffer;
> + int i, result;
> +
> + if (port_paranoia_check(port, __FUNCTION__))
> + return;
> +
> + dbg(__FUNCTION__ " - port %d", port->number);
> +
> + if (!serial) {
> + dbg(__FUNCTION__ " - bad serial pointer, exiting");
> + return;
> + }
> +
> + if (urb->status) {
> + dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
>urb->status);
> + return;
> + }
> +
> + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
> +
> + tty = port->tty;
> + if (urb->actual_length) {
> + for (i = 0; i < urb->actual_length ; ++i) {
> + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop
>them. */
> + if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
> + tty_flip_buffer_push(tty);
> + }
> + /* this doesn't actually push the data through unless
>tty->low_latency is set */
> + tty_insert_flip_char(tty, data[i], 0);
> + }
> + tty_flip_buffer_push(tty);
> + bytes_in += urb->actual_length;
> + }
> +
> + /* Continue trying to always read */
> + 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);
> + if (result)
> + err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
> + return;
> +}
> +
> +static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned
>char *buf,
> + int count)
> +{
> + const unsigned char *current_position = buf;
> + int bytes_sent = 0;
> + int transfer_size;
> +
> + dbg(__FUNCTION__ " - port %d", port->number);
> +
> + usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
> +
> + while (count > 0) {
> + transfer_size = min(count, PACKET_SIZE);
> + if (ipaq_write_bulk(port, from_user, current_position, transfer_size))
>{
> + break;
> + }
> + current_position += transfer_size;
> + bytes_sent += transfer_size;
> + count -= transfer_size;
> + bytes_out += transfer_size;
> + }
> +
> + return bytes_sent;
> +}
> +
> +static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const
>unsigned char *buf,
> + int count)
> +{
> + struct ipaq_private *priv = port->private;
> + struct ipaq_packet *pkt = NULL;
> + int result = 0;
> + unsigned long flags;
> +
> + if (priv->free_len <= 0) {
> + dbg(__FUNCTION__ " - we're stuffed");
> + 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(__FUNCTION__ " - we're stuffed");
> + return -EAGAIN;
> + }
> +
> + if (from_user) {
> + copy_from_user(pkt->data, buf, count);
> + } else {
> + memcpy(pkt->data, buf, count);
> + }
> + usb_serial_debug_data(__FILE__, __FUNCTION__, 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;
> + result = ipaq_write_flush(port);
> + }
> + spin_unlock_irqrestore(&write_list_lock, flags);
> + return result;
> +}
> +
> +static int ipaq_write_flush(struct usb_serial_port *port)
> +{
> + struct ipaq_private *priv = (struct ipaq_private *)port->private;
> + struct usb_serial *serial = port->serial;
> + int count, room, result;
> + struct ipaq_packet *pkt;
> + struct urb *urb = port->write_urb;
> + struct list_head *tmp;
> +
> + if (urb->status == -EINPROGRESS) {
> + /* Should never happen */
> + err(__FUNCTION__ " - flushing while urb is active !");
> + return -EAGAIN;
> + }
> + room = URBDATA_SIZE;
> + for (tmp = priv->queue.next; tmp != &priv->queue;) {
> + pkt = list_entry(tmp, struct ipaq_packet, list);
> + tmp = tmp->next;
> + 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_del(&pkt->list);
> + list_add(&pkt->list, &priv->freelist);
> + priv->free_len += PACKET_SIZE;
> + }
> + if (room == 0) {
> + break;
> + }
> + }
> +
> + count = URBDATA_SIZE - room;
> + 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);
> + result = usb_submit_urb(urb);
> + if (result) {
> + err(__FUNCTION__ " - failed submitting write urb, error %d", result);
> + }
> + return result;
> +}
> +
> +static void ipaq_write_bulk_callback(struct urb *urb)
> +{
> + struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
> + struct ipaq_private *priv = (struct ipaq_private *)port->private;
> + unsigned long flags;
> +
> + if (port_paranoia_check (port, __FUNCTION__)) {
> + return;
> + }
> +
> + dbg(__FUNCTION__ " - port %d", port->number);
> +
> + if (urb->status) {
> + dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
>urb->status);
> + }
> +
> + spin_lock_irqsave(&write_list_lock, flags);
> + if (!list_empty(&priv->queue)) {
> + ipaq_write_flush(port);
> + } else {
> + priv->active = 0;
> + }
> + spin_unlock_irqrestore(&write_list_lock, flags);
> + queue_task(&port->tqueue, &tq_immediate);
> + mark_bh(IMMEDIATE_BH);
> +
> + return;
> +}
> +
> +static int ipaq_write_room(struct usb_serial_port *port)
> +{
> + struct ipaq_private *priv = (struct ipaq_private *)port->private;
> +
> + dbg(__FUNCTION__ " - freelen %d", priv->free_len);
> + return priv->free_len;
> +}
> +
> +static int ipaq_chars_in_buffer(struct usb_serial_port *port)
> +{
> + struct ipaq_private *priv = (struct ipaq_private *)port->private;
> +
> + dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
> + return priv->queue_len;
> +}
> +
> +static void ipaq_destroy_lists(struct usb_serial_port *port)
> +{
> + struct ipaq_private *priv = (struct ipaq_private *)port->private;
> + struct list_head *tmp;
> + struct ipaq_packet *pkt;
> +
> + for (tmp = priv->queue.next; tmp != &priv->queue;) {
> + pkt = list_entry(tmp, struct ipaq_packet, list);
> + tmp = tmp->next;
> + kfree(pkt->data);
> + kfree(pkt);
> + }
> + for (tmp = priv->freelist.next; tmp != &priv->freelist;) {
> + pkt = list_entry(tmp, struct ipaq_packet, list);
> + tmp = tmp->next;
> + kfree(pkt->data);
> + kfree(pkt);
> + }
> + return;
> +}
> +
> +
> +static int ipaq_startup(struct usb_serial *serial)
> +{
> + dbg(__FUNCTION__);
> + usb_set_configuration(serial->dev, 1);
> + return 0;
> +}
> +
> +static void ipaq_shutdown(struct usb_serial *serial)
> +{
> + int i;
> +
> + dbg (__FUNCTION__);
> +
> + /* stop reads and writes on all ports */
> + for (i=0; i < serial->num_ports; ++i) {
> + while (serial->port[i].open_count > 0) {
> + ipaq_close(&serial->port[i], NULL);
> + }
> + }
> +}
> +
> +static int __init ipaq_init(void)
> +{
> + usb_serial_register(&ipaq_device);
> + info(DRIVER_DESC " " DRIVER_VERSION);
> +
> + return 0;
> +}
> +
> +
> +static void __exit ipaq_exit(void)
> +{
> + usb_serial_deregister(&ipaq_device);
> +}
> +
> +
> +module_init(ipaq_init);
> +module_exit(ipaq_exit);
> +
> +MODULE_AUTHOR( DRIVER_AUTHOR );
> +MODULE_DESCRIPTION( DRIVER_DESC );
> +MODULE_LICENSE("GPL");
> +
> +MODULE_PARM(debug, "i");
> +MODULE_PARM_DESC(debug, "Debug enabled or not");
> +
> diff -Nru a/drivers/usb/serial/ipaq.h b/drivers/usb/serial/ipaq.h
> --- /dev/null Wed Dec 31 16:00:00 1969
> +++ b/drivers/usb/serial/ipaq.h Fri Dec 21 12:58:16 2001
> @@ -0,0 +1,60 @@
> +/*
> + * USB Compaq iPAQ driver
> + *
> + * Copyright (C) 2001
> + * Ganesh Varadarajan <[EMAIL PROTECTED]>
> + *
> + * 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
> +
> +
> +#define IPAQ_VENDOR_ID 0x049f
> +#define IPAQ_PRODUCT_ID 0x0003
> +
> +/*
> + * 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
> + * supported by the iPAQ.
> + */
> +
> +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
>
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel