/*
* KLSI KL5KUSB105 chip RS232 converter driver
*
* Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
*
* 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.
*
* All information about the device was acquired using SniffUSB ans snoopUSB
* on Windows98.
* It was written out of frustration with the PalmConnect USB Serial adapter
* sold by Palm Inc.
* Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
* information that was not already available.
*
* It seems that KLSI bought some silicon-design information from ScanLogic,
* whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
* KLSI has firmware available for their devices; it is probable that the
* firmware differs from that used by KLSI in their products. If you have an
* original KLSI device and can provide some information on it, I would be
* most interested in adding support for it here. If you have any information
* on the protocol used (or find errors in my reverse-engineered stuff), please
* let me know.
*
* The code was only tested with a PalmConnect USB adapter; if you
* are adventurous, try it with any KLSI-based device and let me know how it
* breaks so that I can fix it!
*/
/* TODO:
* check modem line signals
* implement handshaking or decide that we do not support it
*/
/* History:
* 0.3a - implemented pools of write URBs
* 0.3 - alpha version for public testing
* 0.2 - TIOCMGET works, so autopilot(1) can be used!
* 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l
*
* The driver skeleton is mainly based on mct_u232.c and various other
* pieces of code shamelessly copied from the drivers/usb/serial/ directory.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include "kl5kusb105.h"
static int debug;
/*
* Version Information
*/
#define DRIVER_VERSION "v0.3a"
#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
/*
* Function prototypes
*/
static int klsi_105_startup(struct usb_serial *serial);
static void klsi_105_disconnect(struct usb_serial *serial);
static void klsi_105_release(struct usb_serial *serial);
static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port);
static void klsi_105_close(struct usb_serial_port *port);
static int klsi_105_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
static void klsi_105_write_bulk_callback(struct urb *urb);
static int klsi_105_chars_in_buffer(struct tty_struct *tty);
static int klsi_105_write_room(struct tty_struct *tty);
static void klsi_105_read_bulk_callback(struct urb *urb);
static void klsi_105_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static void klsi_105_throttle(struct tty_struct *tty);
static void klsi_105_unthrottle(struct tty_struct *tty);
static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file);
static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
/*
* All of the device info needed for the KLSI converters.
*/
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver kl5kusb105d_driver = {
.name = "kl5kusb105d",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver kl5kusb105d_device = {
.driver = {
.owner = THIS_MODULE,
.name = "kl5kusb105d",
},
.description = "KL5KUSB105D / PalmConnect",
.usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
.num_ports = 1,
.open = klsi_105_open,
.close = klsi_105_close,
.write = klsi_105_write,
.write_bulk_callback = klsi_105_write_bulk_callback,
.chars_in_buffer = klsi_105_chars_in_buffer,
.write_room = klsi_105_write_room,
.read_bulk_callback = klsi_105_read_bulk_callback,
.set_termios = klsi_105_set_termios,
/*.break_ctl = klsi_105_break_ctl,*/
.tiocmget = klsi_105_tiocmget,
.tiocmset = klsi_105_tiocmset,
.attach = klsi_105_startup,
.disconnect = klsi_105_disconnect,
.release = klsi_105_release,
.throttle = klsi_105_throttle,
.unthrottle = klsi_105_unthrottle,
};
struct klsi_105_port_settings {
__u8 pktlen; /* always 5, it seems */
__u8 baudrate;
__u8 databits;
__u8 unknown1;
__u8 unknown2;
} __attribute__ ((packed));
/* we implement a pool of NUM_URBS urbs per usb_serial */
#define NUM_URBS 1