Commit 4bec6175 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents c3d5155c 2fc16028
......@@ -1910,7 +1910,7 @@ L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
USB BLUETOOTH DRIVER
USB BLUETOOTH TTY CONVERTER DRIVER
P: Greg Kroah-Hartman
M: greg@kroah.com
L: linux-usb-users@lists.sourceforge.net
......
......@@ -146,6 +146,7 @@ struct usblp {
int rcomplete; /* reading is completed */
unsigned int quirks; /* quirks flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
......@@ -157,6 +158,7 @@ static void usblp_dump(struct usblp *usblp) {
dbg("usblp=0x%p", usblp);
dbg("dev=0x%p", usblp->dev);
dbg("present=%d", usblp->present);
dbg("buf=0x%p", usblp->buf);
dbg("readcount=%d", usblp->readcount);
dbg("ifnum=%d", usblp->ifnum);
......@@ -253,7 +255,7 @@ static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs)
{
struct usblp *usblp = urb->context;
if (!usblp || !usblp->dev || !usblp->used)
if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
return;
if (unlikely(urb->status))
......@@ -267,7 +269,7 @@ static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs)
{
struct usblp *usblp = urb->context;
if (!usblp || !usblp->dev || !usblp->used)
if (!usblp || !usblp->dev || !usblp->used || !usblp->present)
return;
if (unlikely(urb->status))
......@@ -332,7 +334,7 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
}
usblp = usb_get_intfdata (intf);
if (!usblp || !usblp->dev)
if (!usblp || !usblp->dev || !usblp->present)
goto out;
retval = -EBUSY;
......@@ -404,7 +406,7 @@ static int usblp_release(struct inode *inode, struct file *file)
down (&usblp->sem);
lock_kernel();
usblp->used = 0;
if (usblp->dev) {
if (usblp->present) {
usblp_unlink_urbs(usblp);
up(&usblp->sem);
} else /* finish cleanup from disconnect */
......@@ -432,7 +434,7 @@ static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
int retval = 0;
down (&usblp->sem);
if (!usblp->dev) {
if (!usblp->present) {
retval = -ENODEV;
goto done;
}
......@@ -630,7 +632,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
}
down (&usblp->sem);
if (!usblp->dev) {
if (!usblp->present) {
up (&usblp->sem);
return -ENODEV;
}
......@@ -691,7 +693,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
return -EINVAL;
down (&usblp->sem);
if (!usblp->dev) {
if (!usblp->present) {
count = -ENODEV;
goto done;
}
......@@ -726,7 +728,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
remove_wait_queue(&usblp->wait, &wait);
}
if (!usblp->dev) {
if (!usblp->present) {
count = -ENODEV;
goto done;
}
......@@ -916,6 +918,8 @@ static int usblp_probe(struct usb_interface *intf,
usb_set_intfdata (intf, usblp);
usblp->present = 1;
return 0;
abort_minor:
......@@ -1115,14 +1119,14 @@ static void usblp_disconnect(struct usb_interface *intf)
down (&usblp->sem);
lock_kernel();
usblp->dev = NULL;
usblp->present = 0;
usb_set_intfdata (intf, NULL);
usblp_unlink_urbs(usblp);
if (!usblp->used)
usblp_cleanup (usblp);
else /* cleanup later, on close */
else /* cleanup later, on release */
up (&usblp->sem);
unlock_kernel();
}
......
......@@ -491,10 +491,6 @@ static struct file_system_type usbdevice_fs_type;
static struct super_block *usb_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
if (fs_type == &usbdevice_fs_type)
printk (KERN_INFO "Please use the 'usbfs' filetype instead, "
"the 'usbdevfs' name is deprecated.\n");
return get_sb_single(fs_type, flags, data, usbfs_fill_super);
}
......
......@@ -986,7 +986,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
if (err < 0) {
err("error getting string descriptor 0 (error=%d)", err);
goto errout;
} else if (tbuf[0] < 4) {
} else if (err < 4 || tbuf[0] < 4) {
err("string descriptor 0 too short");
err = -EINVAL;
goto errout;
......
......@@ -2391,7 +2391,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
if (retval) {
devdbg (dev, "drop, code %d", retval);
drop:
retval = NET_XMIT_DROP;
retval = NET_XMIT_SUCCESS;
dev->stats.tx_dropped++;
if (skb)
dev_kfree_skb_any (skb);
......
......@@ -4,6 +4,8 @@
* Copyright (C) 1999 - 2001
* Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*
* 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
......@@ -15,17 +17,125 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation
*
* (27/Jun/2003) Ian Abbott
* Reworked the urb handling logic. We have no more pool, but dynamically
* allocate the urb and the transfer buffer on the fly. In testing this
* does not incure any measurable overhead. This also relies on the fact
* that we have proper reference counting logic for urbs. I nicked this
* from Greg KH's Visor driver.
*
* (23/Jun/2003) Ian Abbott
* Reduced flip buffer pushes and corrected a data length test in
* ftdi_read_bulk_callback.
* Defererence pointers after any paranoid checks, not before.
*
* (21/Jun/2003) Erik Nygren
* Added support for Home Electronics Tira-1 IR tranceiver using FT232BM chip.
* See <http://www.home-electro.com/tira1.htm>. Only operates properly
* at 100000 and RTS-CTS, so set custom divisor mode on startup.
* Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
*
* (18/Jun/2003) Ian Abbott
* Added Device ID of the USB relais from Rudolf Gugler (backported from
* Philipp Gühring's patch for 2.5.x kernel).
* Moved read transfer buffer reallocation into startup function.
* Free existing write urb and transfer buffer in startup function.
* Only use urbs in write urb pool that were successfully allocated.
* Moved some constant macros out of functions.
* Minor whitespace and comment changes.
*
* (12/Jun/2003) David Norwood
* Added support for USB-UIRT IR tranceiver using 8U232AM chip.
* See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>. Only
* operates properly at 312500, so set custom divisor mode on startup.
*
* (12/Jun/2003) Ian Abbott
* Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang
* - I've eliminated some that don't seem to exist!
* Added Home Electronics Tira-1 IR transceiver pid from Chris Horn
* Some whitespace/coding-style cleanups
*
* (11/Jun/2003) Ian Abbott
* Fixed unsafe spinlock usage in ftdi_write
*
* (24/Feb/2003) Richard Shooter
* Increase read buffer size to improve read speeds at higher baud rates
* (specifically tested with up to 1Mb/sec at 1.5M baud)
*
* (23/Feb/2003) John Wilkins
* Added Xon/xoff flow control (activating support in the ftdi device)
* Added vid/pid for Videonetworks/Homechoice (UK ISP)
*
* (23/Feb/2003) Bill Ryder
* Added matrix orb device vid/pids from Wayne Wylupski
*
* (19/Feb/2003) Ian Abbott
* For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
* changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
* ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in
* force, don't bother changing baud rate when custom_divisor has changed.
*
* (18/Feb/2003) Ian Abbott
* Fixed TIOCMGET handling to include state of DTR and RTS, the state
* of which are now saved by set_dtr() and set_rts().
* Fixed improper storage class for buf in set_dtr() and set_rts().
* Added FT232BM chip type and support for its extra baud rates (compared
* to FT8U232AM).
* Took account of special case divisor values for highest baud rates of
* FT8U232AM and FT232BM.
* For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
* as previous alt_speed setting is now stale.
* Moved startup code common between the startup routines for the
* different chip types into a common subroutine.
*
* (17/Feb/2003) Bill Ryder
* Added write urb buffer pool on a per device basis
* Added more checking for open file on callbacks (fixed OOPS)
* Added CrystalFontz 632 and 634 PIDs
* (thanx to CrystalFontz for the sample devices - they flushed out
* some driver bugs)
* Minor debugging message changes
* Added throttle, unthrottle and chars_in_buffer functions
* Fixed FTDI_SIO (the original device) bug
* Fixed some shutdown handling
*
*
*
*
* (07/Jun/2002) Kuba Ober
* Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
* function. It was getting too complex.
* Fix the divisor calculation logic which was setting divisor of 0.125
* instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
* Also make it bump up the divisor to next integer in case of 7/8 - it's
* a better approximation.
*
* (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
* Not tested by me but it doesn't break anything I use.
*
* (04/Jan/2002) Kuba Ober
* Implemented 38400 baudrate kludge, where it can be substituted with other
* values. That's the only way to set custom baudrates.
* Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
* FIXME: both baudrate things should eventually go to usbserial.c as other
* devices may need that functionality too. Actually, it can probably be
* merged in serial.c somehow - too many drivers repeat this code over
* and over.
* Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
* Divisors for baudrates are calculated by a macro.
* Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
*
* (04/Nov/2001) Bill Ryder
* Fixed bug in read_bulk_callback where incorrect urb buffer was used.
* cleaned up write offset calculation
* added write_room since default values can be incorrect for sio
* changed write_bulk_callback to use same queue_task as other drivers
* Cleaned up write offset calculation
* Added write_room since default values can be incorrect for sio
* Changed write_bulk_callback to use same queue_task as other drivers
* (the previous version caused panics)
* Removed port iteration code since the device only has one I/O port and it
* was wrong anyway.
*
* (31/May/2001) gkh
* switched from using spinlock to a semaphore, which fixes lots of problems.
* Switched from using spinlock to a semaphore, which fixes lots of problems.
*
* (23/May/2001) Bill Ryder
* Added runtime debug patch (thanx Tyson D Sawyer).
......@@ -49,7 +159,6 @@
* Added shutdown routine to close files when device removed.
* More debug and error message cleanups.
*
*
* (11/13/2000) Bill Ryder
* Added spinlock protected open code and close code.
* Multiple opens work (sort of - see webpage mentioned above).
......@@ -90,7 +199,6 @@
/* to talk to the device */
/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
......@@ -103,6 +211,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
#ifdef CONFIG_USB_SERIAL_DEBUG
static int debug = 1;
#else
......@@ -112,47 +221,244 @@
#include "usb-serial.h"
#include "ftdi_sio.h"
/*
* Version Information
*/
#define DRIVER_VERSION "v1.2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"
#define DRIVER_DESC "USB FTDI RS232 Converters Driver"
#define DRIVER_VERSION "v1.4.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
static struct usb_device_id id_table_sio [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ } /* Terminating entry */
};
/* THe 8U232AM has the same API as the sio except for:
- it can support MUCH higher baudrates (921600 at 48MHz/230400
at 12MHz so .. it's baudrate setting codes are different
- it has a two byte status code.
- it returns characters very 16ms (the FTDI does it every 40ms)
/*
* The 8U232AM has the same API as the sio except for:
* - it can support MUCH higher baudrates; up to:
* o 921600 for RS232 and 2000000 for RS422/485 at 48MHz
* o 230400 at 12MHz
* so .. 8U232AM's baudrate setting codes are different
* - it has a two byte status code.
* - it returns characters every 16ms (the FTDI does it every 40ms)
*
* the bcdDevice value is used to differentiate FT232BM and FT245BM from
* the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID
* combinations in both tables.
* FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know
* if those ever went into mass production. [Ian Abbott]
*/
static struct usb_device_id id_table_8U232AM [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) },
{ } /* Terminating entry */
};
static struct usb_device_id id_table_combined [] = {
static struct usb_device_id id_table_FT232BM [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) },
{ USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) },
{ } /* Terminating entry */
};
static struct usb_device_id id_table_USB_UIRT [] = {
{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
{ } /* Terminating entry */
};
static struct usb_device_id id_table_HE_TIRA1 [] = {
{ USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
{ } /* Terminating entry */
};
static __devinitdata struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_0_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_1_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_2_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_3_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_4_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_5_PID) },
{ USB_DEVICE(FTDI_MTXORB_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
{ USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
{ USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, id_table_combined);
static struct usb_driver ftdi_driver = {
.owner = THIS_MODULE,
.name = "ftdi_sio",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
......@@ -160,31 +466,63 @@ static struct usb_driver ftdi_driver = {
};
/* Constants for read urb and write urb */
#define BUFSZ 512
#define PKTSZ 64
struct ftdi_private {
enum ftdi_type ftdi_type;
__u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */
int write_offset;
ftdi_chip_type_t chip_type;
/* type of the device, either SIO or FT8U232AM */
int baud_base; /* baud base clock for divisor setting */
int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
__u16 last_set_data_urb_value ;
/* the last data state set - needed for doing a break */
int write_offset; /* This is the offset in the usb data block to write the serial data -
* it is different between devices
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
int force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
};
/* Used for TIOCMIWAIT */
#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
/* End TIOCMIWAIT */
#define FTDI_IMPL_ASYNC_FLAGS = ( ASYNC_SPD_HI | ASYNC_SPD_VHI \
ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_startup (struct usb_serial *serial);
static int ftdi_SIO_startup (struct usb_serial *serial);
static int ftdi_8U232AM_startup (struct usb_serial *serial);
static void ftdi_sio_shutdown (struct usb_serial *serial);
static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp);
static int ftdi_sio_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static int ftdi_sio_write_room (struct usb_serial_port *port);
static void ftdi_sio_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_sio_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_sio_tiocmget (struct usb_serial_port *port, struct file *file);
static int ftdi_sio_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void ftdi_sio_break_ctl (struct usb_serial_port *port, int break_state );
/* Should rename most ftdi_sio's to ftdi_ now since there are two devices
which share common code */
static struct usb_serial_device_type ftdi_sio_device = {
static int ftdi_FT232BM_startup (struct usb_serial *serial);
static int ftdi_USB_UIRT_startup (struct usb_serial *serial);
static int ftdi_HE_TIRA1_startup (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_close (struct usb_serial_port *port, struct file *filp);
static int ftdi_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static int ftdi_write_room (struct usb_serial_port *port);
static int ftdi_chars_in_buffer (struct usb_serial_port *port);
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl (struct usb_serial_port *port, int break_state );
static void ftdi_throttle (struct usb_serial_port *port);
static void ftdi_unthrottle (struct usb_serial_port *port);
static unsigned short int ftdi_232am_baud_base_to_divisor (int baud, int base);
static unsigned short int ftdi_232am_baud_to_divisor (int baud);
static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
static __u32 ftdi_232bm_baud_to_divisor (int baud);
static struct usb_serial_device_type ftdi_SIO_device = {
.owner = THIS_MODULE,
.name = "FTDI SIO",
.id_table = id_table_sio,
......@@ -192,77 +530,206 @@ static struct usb_serial_device_type ftdi_sio_device = {
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ftdi_sio_open,
.close = ftdi_sio_close,
.write = ftdi_sio_write,
.write_room = ftdi_sio_write_room,
.read_bulk_callback = ftdi_sio_read_bulk_callback,
.write_bulk_callback = ftdi_sio_write_bulk_callback,
.ioctl = ftdi_sio_ioctl,
.set_termios = ftdi_sio_set_termios,
.break_ctl = ftdi_sio_break_ctl,
.tiocmget = ftdi_sio_tiocmget,
.tiocmset = ftdi_sio_tiocmset,
.attach = ftdi_sio_startup,
.shutdown = ftdi_sio_shutdown,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.attach = ftdi_SIO_startup,
.shutdown = ftdi_shutdown,
};
static struct usb_serial_device_type ftdi_8U232AM_device = {
.owner = THIS_MODULE,
.name = "FTDI 8U232AM",
.name = "FTDI 8U232AM Compatible",
.id_table = id_table_8U232AM,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ftdi_sio_open,
.close = ftdi_sio_close,
.write = ftdi_sio_write,
.write_room = ftdi_sio_write_room,
.read_bulk_callback = ftdi_sio_read_bulk_callback,
.write_bulk_callback = ftdi_sio_write_bulk_callback,
.ioctl = ftdi_sio_ioctl,
.set_termios = ftdi_sio_set_termios,
.break_ctl = ftdi_sio_break_ctl,
.tiocmget = ftdi_sio_tiocmget,
.tiocmset = ftdi_sio_tiocmset,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.attach = ftdi_8U232AM_startup,
.shutdown = ftdi_sio_shutdown,
.shutdown = ftdi_shutdown,
};
static struct usb_serial_device_type ftdi_FT232BM_device = {
.owner = THIS_MODULE,
.name = "FTDI FT232BM Compatible",
.id_table = id_table_FT232BM,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.attach = ftdi_FT232BM_startup,
.shutdown = ftdi_shutdown,
};
static struct usb_serial_device_type ftdi_USB_UIRT_device = {
.owner = THIS_MODULE,
.name = "USB-UIRT Infrared Receiver/Transmitter",
.id_table = id_table_USB_UIRT,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.attach = ftdi_USB_UIRT_startup,
.shutdown = ftdi_shutdown,
};
/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000
* and which requires RTS-CTS to be enabled. */
static struct usb_serial_device_type ftdi_HE_TIRA1_device = {
.owner = THIS_MODULE,
.name = "Home-Electronics TIRA-1 IR Transceiver",
.id_table = id_table_HE_TIRA1,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
.write_room = ftdi_write_room,
.chars_in_buffer = ftdi_chars_in_buffer,
.read_bulk_callback = ftdi_read_bulk_callback,
.write_bulk_callback = ftdi_write_bulk_callback,
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
.attach = ftdi_HE_TIRA1_startup,
.shutdown = ftdi_shutdown,
};
#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
/* High and low are for DTR, RTS etc etc */
#define HIGH 1
#define LOW 0
/*
* ***************************************************************************
* FTDI SIO Serial Converter specific driver functions
* Utlity functions
* ***************************************************************************
*/
#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base)
{
unsigned short int divisor;
int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
if ((divisor3 & 0x7) == 7) divisor3 ++; // round x.7/8 up to x+1
divisor = divisor3 >> 3;
divisor3 &= 0x7;
if (divisor3 == 1) divisor |= 0xc000; else // 0.125
if (divisor3 >= 4) divisor |= 0x4000; else // 0.5
if (divisor3 != 0) divisor |= 0x8000; // 0.25
if (divisor == 1) divisor = 0; /* special case for maximum baud rate */
return divisor;
}
/* utility functions to set and unset dtr and rts */
#define HIGH 1
#define LOW 0
static int set_rts(struct usb_device *dev,
unsigned int pipe,
int high_or_low)
static unsigned short int ftdi_232am_baud_to_divisor(int baud)
{
static char buf[1];
unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH :
FTDI_SIO_SET_RTS_LOW);
return(usb_control_msg(dev, pipe,
return(ftdi_232am_baud_base_to_divisor(baud, 48000000));
}
static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base)
{
static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
__u32 divisor;
int divisor3 = base / 2 / baud; // divisor shifted 3 bits to the left
divisor = divisor3 >> 3;
divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
/* Deal with special cases for highest baud rates. */
if (divisor == 1) divisor = 0; else // 1.0
if (divisor == 0x4001) divisor = 1; // 1.5
return divisor;
}
static __u32 ftdi_232bm_baud_to_divisor(int baud)
{
return(ftdi_232bm_baud_base_to_divisor(baud, 48000000));
}
static int set_rts(struct usb_serial_port *port, int high_or_low)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
unsigned ftdi_high_or_low;
if (high_or_low) {
ftdi_high_or_low = FTDI_SIO_SET_RTS_HIGH;
priv->last_dtr_rts |= TIOCM_RTS;
} else {
ftdi_high_or_low = FTDI_SIO_SET_RTS_LOW;
priv->last_dtr_rts &= ~TIOCM_RTS;
}
return(usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
ftdi_high_or_low, 0,
buf, 0, WDR_TIMEOUT));
}
static int set_dtr(struct usb_device *dev,
unsigned int pipe,
int high_or_low)
static int set_dtr(struct usb_serial_port *port, int high_or_low)
{
static char buf[1];
unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH :
FTDI_SIO_SET_DTR_LOW);
return(usb_control_msg(dev, pipe,
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
unsigned ftdi_high_or_low;
if (high_or_low) {
ftdi_high_or_low = FTDI_SIO_SET_DTR_HIGH;
priv->last_dtr_rts |= TIOCM_DTR;
} else {
ftdi_high_or_low = FTDI_SIO_SET_DTR_LOW;
priv->last_dtr_rts &= ~TIOCM_DTR;
}
return(usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
ftdi_high_or_low, 0,
......@@ -270,71 +737,409 @@ static int set_dtr(struct usb_device *dev,
}
static __u32 get_ftdi_divisor(struct usb_serial_port * port);
static int change_speed(struct usb_serial_port *port)
{
char buf[1];
__u16 urb_value;
__u16 urb_index;
__u32 urb_index_value;
urb_index_value = get_ftdi_divisor(port);
urb_value = (__u16)urb_index_value;
urb_index = (__u16)(urb_index_value >> 16);
return (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
urb_value, urb_index,
buf, 0, 100) < 0);
}
static __u32 get_ftdi_divisor(struct usb_serial_port * port)
{ /* get_ftdi_divisor */
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u32 div_value = 0;
int div_okay = 1;
char *chip_name = "";
int baud;
/*
* The logic involved in setting the baudrate can be cleanly split in 3 steps.
* Obtaining the actual baud rate is a little tricky since unix traditionally
* somehow ignored the possibility to set non-standard baud rates.
* 1. Standard baud rates are set in tty->termios->c_cflag
* 2. If these are not enough, you can set any speed using alt_speed as follows:
* - set tty->termios->c_cflag speed to B38400
* - set your real speed in tty->alt_speed; it gets ignored when
* alt_speed==0, (or)
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
* flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP], this just
* sets alt_speed to (HI: 57600, VHI: 115200, SHI: 230400, WARP: 460800)
* ** Steps 1, 2 are done courtesy of tty_get_baud_rate
* 3. You can also set baud rate by setting custom divisor as follows
* - set tty->termios->c_cflag speed to B38400
* - call TIOCSSERIAL ioctl with (struct serial_struct) set as follows:
* o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST
* o custom_divisor set to baud_base / your_new_baudrate
* ** Step 3 is done courtesy of code borrowed from serial.c - I should really
* spend some time and separate+move this common code to serial.c, it is
* replicated in nearly every serial driver you see.
*/
/* 1. Get the baud rate from the tty settings, this observes alt_speed hack */
baud = tty_get_baud_rate(port->tty);
dbg("%s - tty_get_baud_rate reports speed %d", __FUNCTION__, baud);
/* 2. Observe async-compatible custom_divisor hack, update baudrate if needed */
if (baud == 38400 &&
((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
(priv->custom_divisor)) {
baud = priv->baud_base / priv->custom_divisor;
dbg("%s - custom divisor %d sets baud rate to %d", __FUNCTION__, priv->custom_divisor, baud);
}
/* 3. Convert baudrate to device-specific divisor */
if (!baud) baud = 9600;
switch(priv->chip_type) {
case SIO: /* SIO chip */
chip_name = "SIO";
switch(baud) {
case 300: div_value = ftdi_sio_b300; break;
case 600: div_value = ftdi_sio_b600; break;
case 1200: div_value = ftdi_sio_b1200; break;
case 2400: div_value = ftdi_sio_b2400; break;
case 4800: div_value = ftdi_sio_b4800; break;
case 9600: div_value = ftdi_sio_b9600; break;
case 19200: div_value = ftdi_sio_b19200; break;
case 38400: div_value = ftdi_sio_b38400; break;
case 57600: div_value = ftdi_sio_b57600; break;
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
div_value = ftdi_sio_b9600;
div_okay = 0;
}
break;
case FT8U232AM: /* 8U232AM chip */
chip_name = "FT8U232AM";
if (baud <= 3000000) {
div_value = ftdi_232am_baud_to_divisor(baud);
} else {
dbg("%s - Baud rate too high!", __FUNCTION__);
div_value = ftdi_232am_baud_to_divisor(9600);
div_okay = 0;
}
break;
case FT232BM: /* FT232BM chip */
chip_name = "FT232BM";
if (baud <= 3000000) {
div_value = ftdi_232bm_baud_to_divisor(baud);
} else {
dbg("%s - Baud rate too high!", __FUNCTION__);
div_value = ftdi_232bm_baud_to_divisor(9600);
div_okay = 0;
}
break;
} /* priv->chip_type */
if (div_okay) {
dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s",
__FUNCTION__, baud, (unsigned long)div_value, chip_name);
}
return(div_value);
}
static int get_serial_info(struct usb_serial_port * port, struct serial_struct * retinfo)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct serial_struct tmp;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.flags = priv->flags;
tmp.baud_base = priv->baud_base;
tmp.custom_divisor = priv->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
} /* get_serial_info */
static int ftdi_sio_startup (struct usb_serial *serial)
static int set_serial_info(struct usb_serial_port * port, struct serial_struct * newinfo)
{ /* set_serial_info */
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct serial_struct new_serial;
struct ftdi_private old_priv;
if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
return -EFAULT;
old_priv = * priv;
/* Do error checking and permission checking */
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
(priv->flags & ~ASYNC_USR_MASK)))
return -EPERM;
priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
(new_serial.flags & ASYNC_USR_MASK));
priv->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
if ((new_serial.baud_base != priv->baud_base) ||
(new_serial.baud_base < 9600))
return -EINVAL;
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
check_and_exit:
if ((old_priv.flags & ASYNC_SPD_MASK) !=
(priv->flags & ASYNC_SPD_MASK)) {
if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
port->tty->alt_speed = 57600;
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
port->tty->alt_speed = 115200;
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
port->tty->alt_speed = 230400;
else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
port->tty->alt_speed = 460800;
else
port->tty->alt_speed = 0;
}
if (((old_priv.flags & ASYNC_SPD_MASK) !=
(priv->flags & ASYNC_SPD_MASK)) ||
(((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
(old_priv.custom_divisor != priv->custom_divisor))) {
change_speed(port);
}
return (0);
} /* set_serial_info */
/*
* ***************************************************************************
* FTDI driver specific functions
* ***************************************************************************
*/
/* Common startup subroutine */
/* Called from ftdi_SIO_startup, etc. */
static int ftdi_common_startup (struct usb_serial *serial)
{
struct usb_serial_port *port = &serial->port[0];
struct ftdi_private *priv;
dbg("%s",__FUNCTION__);
priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv){
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
return -ENOMEM;
}
memset(priv, 0, sizeof(*priv));
init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
than queue a task to deliver them */
priv->flags = ASYNC_LOW_LATENCY;
/* Increase the size of read buffers */
if (port->bulk_in_buffer) {
kfree (port->bulk_in_buffer);
}
port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL);
if (!port->bulk_in_buffer) {
kfree (priv);
return -ENOMEM;
}
if (port->read_urb) {
port->read_urb->transfer_buffer = port->bulk_in_buffer;
port->read_urb->transfer_buffer_length = BUFSZ;
}
/* Free port's existing write urb and transfer buffer. */
if (port->write_urb) {
usb_free_urb (port->write_urb);
port->write_urb = NULL;
}
if (port->bulk_out_buffer) {
kfree (port->bulk_out_buffer);
port->bulk_out_buffer = NULL;
}
priv->ftdi_type = sio;
priv->write_offset = 1;
usb_set_serial_port_data(serial->port, priv);
return (0);
}
static int ftdi_8U232AM_startup (struct usb_serial *serial)
/* Startup for the SIO chip */
/* Called from usbserial:serial_probe */
static int ftdi_SIO_startup (struct usb_serial *serial)
{
struct ftdi_private *priv;
int err;
dbg("%s",__FUNCTION__);
priv = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv){
err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private));
return -ENOMEM;
err = ftdi_common_startup(serial);
if (err){
return (err);
}
priv->ftdi_type = F8U232AM;
priv->write_offset = 0;
usb_set_serial_port_data(serial->port, priv);
priv = usb_get_serial_port_data(serial->port);
priv->chip_type = SIO;
priv->baud_base = 12000000 / 16;
priv->write_offset = 1;
return (0);
}
static void ftdi_sio_shutdown (struct usb_serial *serial)
{
void *priv;
/* Startup for the 8U232AM chip */
/* Called from usbserial:serial_probe */
static int ftdi_8U232AM_startup (struct usb_serial *serial)
{ /* ftdi_8U232AM_startup */
struct ftdi_private *priv;
int err;
dbg("%s",__FUNCTION__);
err = ftdi_common_startup(serial);
if (err){
return (err);
}
priv = usb_get_serial_port_data(serial->port);
priv->chip_type = FT8U232AM;
priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
return (0);
} /* ftdi_8U232AM_startup */
/* Startup for the FT232BM chip */
/* Called from usbserial:serial_probe */
static int ftdi_FT232BM_startup (struct usb_serial *serial)
{ /* ftdi_FT232BM_startup */
struct ftdi_private *priv;
int err;
dbg("%s",__FUNCTION__);
err = ftdi_common_startup(serial);
if (err){
return (err);
}
priv = usb_get_serial_port_data(serial->port);
priv->chip_type = FT232BM;
priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
return (0);
} /* ftdi_FT232BM_startup */
/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */
/* Called from usbserial:serial_probe */
static int ftdi_USB_UIRT_startup (struct usb_serial *serial)
{ /* ftdi_USB_UIRT_startup */
struct ftdi_private *priv;
int err;
dbg("%s",__FUNCTION__);
err = ftdi_8U232AM_startup(serial);
if (err){
return (err);
}
priv = usb_get_serial_port_data(serial->port);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = B38400;
return (0);
} /* ftdi_USB_UIRT_startup */
/* Startup for the HE-TIRA1 device, which requires hardwired
* baudrate (38400 gets mapped to 100000) */
static int ftdi_HE_TIRA1_startup (struct usb_serial *serial)
{ /* ftdi_HE_TIRA1_startup */
struct ftdi_private *priv;
int err;
dbg("%s",__FUNCTION__);
err = ftdi_FT232BM_startup(serial);
if (err){
return (err);
}
priv = usb_get_serial_port_data(serial->port);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = B38400;
priv->force_rtscts = 1;
return (0);
} /* ftdi_HE_TIRA1_startup */
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
* it is called when the usb device is disconnected
*
* usbserial:usb_serial_disconnect
* calls __serial_close for each open of the port
* shutdown is called then (ie ftdi_shutdown)
*/
static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */
struct usb_serial_port *port = serial->port;
struct ftdi_private *priv = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__);
priv = usb_get_serial_port_data(&serial->port[0]);
if (priv){
/* all open ports are closed at this point
* (by usbserial.c:__serial_close, which calls ftdi_close)
*/
if (priv) {
kfree(priv);
usb_set_serial_port_data(&serial->port[0], NULL);
usb_set_serial_port_data(port, NULL);
}
}
} /* ftdi_shutdown */
static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_sio_open */
static int ftdi_open (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_open */
struct termios tmp_termios;
struct usb_serial *serial = port->serial;
struct ftdi_private *priv = usb_get_serial_port_data(port);
int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
dbg("%s", __FUNCTION__);
/* This will push the characters through immediately rather
than queue a task to deliver them */
port->tty->low_latency = 1;
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
......@@ -343,19 +1148,20 @@ static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
FTDI_SIO_RESET_SIO,
0, buf, 0, WDR_TIMEOUT);
/* Setup termios defaults. According to tty_io.c the
settings are driver specific */
port->tty->termios->c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
/* Termios defaults are set by usb_serial_init. We don't change
port->tty->termios - this would loose speed settings, etc.
This is same behaviour as serial.c/rs_open() - Kuba */
/* ftdi_sio_set_termios will send usb control messages */
ftdi_sio_set_termios(port, &tmp_termios);
/* ftdi_set_termios will send usb control messages */
ftdi_set_termios(port, &tmp_termios);
/* FIXME: Flow control might be enabled, so it should be checked -
we have no control of defaults! */
/* Turn on RTS and DTR since we are not flow controlling by default */
if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
if (set_dtr(port, HIGH) < 0) {
err("%s Error from DTR HIGH urb", __FUNCTION__);
}
if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
if (set_rts(port, HIGH) < 0){
err("%s Error from RTS HIGH urb", __FUNCTION__);
}
......@@ -363,23 +1169,37 @@ static int ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
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,
ftdi_sio_read_bulk_callback, port);
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
return result;
} /* ftdi_sio_open */
} /* ftdi_open */
static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_sio_close */
struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
/*
* usbserial:__serial_close only calls ftdi_close if the point is open
*
* This only gets called when it is the last close
*
*
*/
static void ftdi_close (struct usb_serial_port *port, struct file *filp)
{ /* ftdi_close */
struct usb_serial *serial;
unsigned int c_cflag = port->tty->termios->c_cflag;
char buf[1];
dbg("%s", __FUNCTION__);
serial = get_usb_serial ( port, __FUNCTION__);
if (!serial)
return;
if (serial->dev) {
if (c_cflag & HUPCL){
/* Disable flow control */
......@@ -392,37 +1212,45 @@ static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
}
/* drop DTR */
if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
if (set_dtr(port, LOW) < 0){
err("Error from DTR LOW urb");
}
/* drop RTS */
if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
if (set_rts(port, LOW) < 0) {
err("Error from RTS LOW urb");
}
} /* Note change no line is hupcl is off */
/* shutdown our bulk reads and writes */
/* ***CHECK*** behaviour when there is nothing queued */
usb_unlink_urb (port->write_urb);
/* shutdown our bulk read */
if (port->read_urb) {
usb_unlink_urb (port->read_urb);
}
} /* ftdi_sio_close */
/* unlink the running write urbs */
} /* Note change no line is hupcl is off */
} /* if (serial->dev) */
} /* ftdi_close */
/* The ftdi_sio requires the first byte to have:
/* The SIO requires the first byte to have:
* B0 1
* B1 0
* B2..7 length of message excluding byte 0
*
* The new devices do not require this byte
*/
static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
static int ftdi_write (struct usb_serial_port *port, int from_user,
const unsigned char *buf, int count)
{ /* ftdi_sio_write */
struct usb_serial *serial = port->serial;
{ /* ftdi_write */
struct usb_serial *serial = get_usb_serial ( port, __FUNCTION__);
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned char *first_byte = port->write_urb->transfer_buffer;
int data_offset ;
int result;
struct urb *urb;
unsigned char *buffer;
int data_offset ; /* will be 1 for the SIO and 0 otherwise */
int status;
int transfer_size;
dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
......@@ -434,123 +1262,209 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
if (port->write_urb->status == -EINPROGRESS) {
dbg("%s - already writing", __FUNCTION__);
return (0);
/* Determine total transfer size */
transfer_size = count;
if (data_offset > 0) {
/* Original sio needs control bytes too... */
transfer_size += (data_offset *
((count + (PKTSZ - 1 - data_offset)) /
(PKTSZ - data_offset)));
}
buffer = kmalloc (transfer_size, GFP_ATOMIC);
if (!buffer) {
err("%s ran out of kernel memory for urb ...", __FUNCTION__);
return -ENOMEM;
}
count += data_offset;
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
err("%s - no more free urbs", __FUNCTION__);
kfree (buffer);
return -ENOMEM;
}
/* Copy data */
if (data_offset > 0) {
/* Original sio requires control byte at start of each packet. */
int user_pktsz = PKTSZ - data_offset;
int todo = count;
unsigned char *first_byte = buffer;
const unsigned char *current_position = buf;
while (todo > 0) {
if (user_pktsz > todo) {
user_pktsz = todo;
}
/* Write the control byte at the front of the packet*/
*first_byte = 1 | ((user_pktsz) << 2);
/* Copy data for packet */
if (from_user) {
if (copy_from_user (first_byte + data_offset,
current_position, user_pktsz)){
kfree (buffer);
usb_free_urb (urb);
return -EFAULT;
}
} else {
memcpy (first_byte + data_offset,
current_position, user_pktsz);
}
first_byte += user_pktsz + data_offset;
current_position += user_pktsz;
todo -= user_pktsz;
}
} else {
/* No control byte required. */
/* Copy in the data to send */
if (from_user) {
if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
buf, count - data_offset )){
if (copy_from_user (buffer, buf, count)) {
kfree (buffer);
usb_free_urb (urb);
return -EFAULT;
}
} else {
memcpy(port->write_urb->transfer_buffer + data_offset,
buf, count - data_offset );
memcpy (buffer, buf, count);
}
first_byte = port->write_urb->transfer_buffer;
if (data_offset > 0){
/* Write the control byte at the front of the packet*/
*first_byte = 1 | ((count-data_offset) << 2) ;
}
dbg("%s Bytes: %d, First Byte: 0x%02x", __FUNCTION__,count, first_byte[0]);
usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, buffer);
/* send the data out the bulk port */
usb_fill_bulk_urb(port->write_urb, serial->dev,
/* fill the buffer and send it */
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer, count,
ftdi_sio_write_bulk_callback, port);
buffer, transfer_size,
ftdi_write_bulk_callback, port);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
return 0;
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status;
}
dbg("%s write returning: %d", __FUNCTION__, count - data_offset);
return (count - data_offset);
} /* ftdi_sio_write */
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
usb_free_urb (urb);
dbg("%s write returning: %d", __FUNCTION__, count);
return count;
} /* ftdi_write */
static void ftdi_sio_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
/* This function may get called when the device is closed */
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial;
struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
dbg("%s", __FUNCTION__);
if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
if (port_paranoia_check (port, __FUNCTION__))
return;
}
serial = port->serial;
if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
}
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
if (!serial) {
dbg("%s - bad serial pointer, exiting", __FUNCTION__);
return;
}
/* Have to check for validity of queueing up the tasks */
dbg("%s - port->open_count = %d", __FUNCTION__, port->open_count);
if (port->open_count > 0){
schedule_work(&port->work);
} /* ftdi_sio_write_bulk_callback */
}
return;
} /* ftdi_write_bulk_callback */
static int ftdi_sio_write_room( struct usb_serial_port *port )
static int ftdi_write_room( struct usb_serial_port *port )
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
int room;
dbg("%s - port %d", __FUNCTION__, port->number);
if ( port->write_urb->status == -EINPROGRESS) {
/* There is a race here with the _write routines but it won't hurt */
room = 0;
} else {
room = port->bulk_out_size - priv->write_offset;
}
return(room);
} /* ftdi_sio_write_room */
/*
* We really can take anything the user throws at us
* but let's pick a nice big number to tell the tty
* layer that we have lots of free space
*/
return 2048;
} /* ftdi_write_room */
static void ftdi_sio_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{ /* ftdi_sio_serial_buld_callback */
static int ftdi_chars_in_buffer (struct usb_serial_port *port)
{ /* ftdi_chars_in_buffer */
dbg("%s - port %d", __FUNCTION__, port->number);
/*
* We can't really account for how much data we
* have sent out, but hasn't made it through to the
* device, so just tell the tty layer that everything
* is flushed.
*/
return 0;
} /* ftdi_chars_in_buffer */
static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{ /* ftdi_read_bulk_callback */
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial;
struct tty_struct *tty = port->tty ;
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
unsigned char *data = urb->transfer_buffer;
const int data_offset = 2;
int i;
int result;
int need_flip;
int packet_offset;
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets );
err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags );
}
dbg("%s", __FUNCTION__);
if (port_paranoia_check (port, __FUNCTION__)) {
return;
}
if (port->open_count <= 0)
return;
if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
serial = get_usb_serial(port,__FUNCTION__);
if (!serial){
dbg("%s - bad serial pointer - exiting",__FUNCTION__);
return;
}
serial = port->serial;
if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
tty = port->tty;
if (!tty) {
dbg("%s - bad tty pointer - exiting",__FUNCTION__);
return;
}
priv = usb_get_serial_port_data(port);
if (urb->status) {
/* This will happen at close every time so it is a dbg not an err */
dbg("nonzero read bulk status received: %d", urb->status);
dbg("(this is ok on close) nonzero read bulk status received: %d", urb->status);
return;
}
/* The first two bytes of every read packet are status */
if (urb->actual_length > 2) {
usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
} else {
dbg("Just status 0o%03o0o%03o",data[0],data[1]);
dbg("Status only: %03oo %03oo",data[0],data[1]);
}
......@@ -559,31 +1473,42 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
/* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */
/* if CD is dropped and the line is not CLOCAL then we should hangup */
need_flip = 0;
for (packet_offset=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) {
/* Compare new line status to the old one, signal if different */
if (priv != NULL) {
char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK;
if (new_status != priv->prev_status) {
priv->diff_status |= new_status ^ priv->prev_status;
wake_up_interruptible(&priv->delta_msr_wait);
priv->prev_status = new_status;
}
}
/* Handle errors and break */
error_flag = TTY_NORMAL;
/* Although the device uses a bitmask and hence can have multiple */
/* errors on a packet - the order here sets the priority the */
/* error is returned to the tty layer */
if ( data[1] & FTDI_RS_OE ) {
if ( data[packet_offset+1] & FTDI_RS_OE ) {
error_flag = TTY_OVERRUN;
dbg("OVERRRUN error");
}
if ( data[1] & FTDI_RS_BI ) {
if ( data[packet_offset+1] & FTDI_RS_BI ) {
error_flag = TTY_BREAK;
dbg("BREAK received");
}
if ( data[1] & FTDI_RS_PE ) {
if ( data[packet_offset+1] & FTDI_RS_PE ) {
error_flag = TTY_PARITY;
dbg("PARITY error");
}
if ( data[1] & FTDI_RS_FE ) {
if ( data[packet_offset+1] & FTDI_RS_FE ) {
error_flag = TTY_FRAME;
dbg("FRAMING error");
}
if (urb->actual_length > data_offset) {
for (i = data_offset ; i < urb->actual_length ; ++i) {
if (urb->actual_length > packet_offset + 2) {
for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) {
/* have to make sure we don't overflow the buffer
with tty_insert_flip_char's */
if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
......@@ -592,11 +1517,9 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
/* Note that the error flag is duplicated for
every character received since we don't know
which character it applied to */
tty_insert_flip_char(tty, data[i], error_flag);
tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
}
tty_flip_buffer_push(tty);
need_flip = 1;
}
#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
......@@ -616,72 +1539,35 @@ static void ftdi_sio_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
tty_flip_buffer_push(tty);
}
tty_insert_flip_char(tty, 0xff, error_flag);
tty_flip_buffer_push(tty);
need_flip = 1;
}
}
#endif
} /* "for(packet_offset=0..." */
/* Low latency */
if (need_flip) {
tty_flip_buffer_push(tty);
}
/* if the port is closed stop trying to read */
if (port->open_count > 0){
/* Continue trying to always read */
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,
ftdi_sio_read_bulk_callback, port);
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
return;
} /* ftdi_sio_serial_read_bulk_callback */
static __u16 translate_baudrate_to_ftdi(unsigned int cflag, enum ftdi_type ftdi_type)
{ /* translate_baudrate_to_ftdi */
__u16 urb_value = ftdi_sio_b9600;
if (ftdi_type == sio){
switch(cflag & CBAUD){
case B0: break; /* ignored by this */
case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
default: dbg("%s - FTDI_SIO does not support the baudrate (%d) requested",
__FUNCTION__, (cflag & CBAUD));
break;
}
} else { /* it is 8U232AM */
switch(cflag & CBAUD){
case B0: break; /* ignored by this */
case B300: urb_value = ftdi_8U232AM_48MHz_b300; dbg("Set to 300"); break;
case B600: urb_value = ftdi_8U232AM_48MHz_b600; dbg("Set to 600") ; break;
case B1200: urb_value = ftdi_8U232AM_48MHz_b1200; dbg("Set to 1200") ; break;
case B2400: urb_value = ftdi_8U232AM_48MHz_b2400; dbg("Set to 2400") ; break;
case B4800: urb_value = ftdi_8U232AM_48MHz_b4800; dbg("Set to 4800") ; break;
case B9600: urb_value = ftdi_8U232AM_48MHz_b9600; dbg("Set to 9600") ; break;
case B19200: urb_value = ftdi_8U232AM_48MHz_b19200; dbg("Set to 19200") ; break;
case B38400: urb_value = ftdi_8U232AM_48MHz_b38400; dbg("Set to 38400") ; break;
case B57600: urb_value = ftdi_8U232AM_48MHz_b57600; dbg("Set to 57600") ; break;
case B115200: urb_value = ftdi_8U232AM_48MHz_b115200; dbg("Set to 115200") ; break;
case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break;
case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break;
case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break;
default: dbg("%s - The baudrate (%d) requested is not implemented",
__FUNCTION__, (cflag & CBAUD));
break;
}
}
return(urb_value);
}
} /* ftdi_read_bulk_callback */
static void ftdi_sio_break_ctl( struct usb_serial_port *port, int break_state )
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
{
struct usb_serial *serial = port->serial;
struct ftdi_private *priv = usb_get_serial_port_data(port);
......@@ -704,32 +1590,48 @@ static void ftdi_sio_break_ctl( struct usb_serial_port *port, int break_state )
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , 0,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s - FAILED to enable/disable break state (state was %d)",
__FUNCTION__, break_state);
err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
}
dbg("%s - break state is %d - urb is %d", __FUNCTION__, break_state, urb_value);
dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
}
/* old_termios contains the original termios settings and tty->termios contains
* the new setting to be used
* WARNING: set_termios calls this with old_termios in kernel space
*/
/* As I understand this - old_termios contains the original termios settings */
/* and tty->termios contains the new setting to be used */
/* */
/* WARNING: set_termios calls this with old_termios in kernel space */
static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{ /* ftdi_sio_set_termios */
static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{ /* ftdi_termios */
struct usb_serial *serial = port->serial;
unsigned int cflag = port->tty->termios->c_cflag;
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
// Added for xon/xoff support
unsigned int iflag = port->tty->termios->c_iflag;
unsigned char vstop;
unsigned char vstart;
dbg("%s", __FUNCTION__);
/* Force baud rate if this device requires it, unless it is set to B0. */
if (priv->force_baud && ((port->tty->termios->c_cflag & CBAUD) != B0)) {
dbg("%s: forcing baud rate for this device", __FUNCTION__);
port->tty->termios->c_cflag &= ~CBAUD;
port->tty->termios->c_cflag |= priv->force_baud;
}
/* Force RTS-CTS if this device requires it. */
if (priv->force_rtscts) {
dbg("%s: forcing rtscts for this device", __FUNCTION__);
port->tty->termios->c_cflag |= CRTSCTS;
}
cflag = port->tty->termios->c_cflag;
/* FIXME -For this cut I don't care if the line is really changing or
not - so just do the change regardless - should be able to
......@@ -771,8 +1673,6 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
}
/* Now do the baudrate */
urb_value = translate_baudrate_to_ftdi((cflag & CBAUD), priv->ftdi_type);
if ((cflag & CBAUD) == B0 ) {
/* Disable flow control */
if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
......@@ -783,24 +1683,20 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
err("%s error from disable flowcontrol urb", __FUNCTION__);
}
/* Drop RTS and DTR */
if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
if (set_dtr(port, LOW) < 0){
err("%s Error from DTR LOW urb", __FUNCTION__);
}
if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
if (set_rts(port, LOW) < 0){
err("%s Error from RTS LOW urb", __FUNCTION__);
}
} else {
/* set the baudrate determined before */
if (usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
urb_value, 0,
buf, 0, 100) < 0) {
if (change_speed(port)) {
err("%s urb failed to set baurdrate", __FUNCTION__);
}
}
/* Set flow control */
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
......@@ -815,6 +1711,32 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
}
} else {
/*
* Xon/Xoff code
*
* Check the IXOFF status in the iflag component of the termios structure
* if IXOFF is not set, the pre-xon/xoff code is executed.
*/
if (iflag & IXOFF) {
dbg("%s request to enable xonxoff iflag=%04x",__FUNCTION__,iflag);
// Try to enable the XON/XOFF on the ftdi_sio
// Set the vstart and vstop -- could have been done up above where
// a lot of other dereferencing is done but that would be very
// inefficient as vstart and vstop are not always needed
vstart=port->tty->termios->c_cc[VSTART];
vstop=port->tty->termios->c_cc[VSTOP];
urb_value=(vstop << 8) | (vstart);
if (usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
urb_value , FTDI_SIO_XON_XOFF_HS,
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to set to xon/xoff flow control");
}
} else {
/* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
dbg("%s Turning off hardware flow control", __FUNCTION__);
if (usb_control_msg(serial->dev,
......@@ -825,136 +1747,254 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to clear flow control");
}
}
}
return;
} /* ftdi_sio_set_termios */
} /* ftdi_termios */
static int ftdi_sio_tiocmget (struct usb_serial_port *port, struct file *file)
static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
struct usb_serial *serial = port->serial;
struct ftdi_private *priv = usb_get_serial_port_data(port);
char *buf = NULL;
int ret = -EINVAL;
int size;
dbg("%s", __FUNCTION__);
__u16 urb_value=0; /* Will hold the new flags */
char buf[2];
int ret, mask;
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
goto exit;
dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
if (priv->ftdi_type == sio) {
size = 1;
} else {
/* Based on code from acm.c and others */
switch (cmd) {
case TIOCMGET:
dbg("%s TIOCMGET", __FUNCTION__);
switch (priv->chip_type) {
case SIO:
/* Request the status from the device */
if ((ret = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, 0,
buf, 1, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
return(ret);
}
break;
case FT8U232AM:
case FT232BM:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
size = 2;
}
ret = usb_control_msg(serial->dev,
if ((ret = usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
0, 0, buf, size, WDR_TIMEOUT);
if (ret < 0) {
err("%s Could not get modem status of device - err: %d",
__FUNCTION__, ret);
goto exit;
0, 0,
buf, 2, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
return(ret);
}
break;
default:
return -EFAULT;
break;
}
ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0);
exit:
kfree(buf);
return ret;
}
static int ftdi_sio_tiocmset (struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
struct usb_serial *serial = port->serial;
int ret = 0;
dbg("%s", __FUNCTION__);
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
priv->last_dtr_rts,
(unsigned long *) arg);
break;
if (set & TIOCM_RTS)
if ((ret = set_rts(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
HIGH)) < 0) {
err("Urb to set RTS failed");
goto exit;
case TIOCMSET: /* Turns on and off the lines as specified by the mask */
dbg("%s TIOCMSET", __FUNCTION__);
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
if ((ret = set_dtr(port, urb_value)) < 0){
err("Error from DTR set urb (TIOCMSET)");
return(ret);
}
urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);
if ((ret = set_rts(port, urb_value)) < 0){
err("Error from RTS set urb (TIOCMSET)");
return(ret);
}
return(0);
break;
if (set & TIOCM_DTR)
if ((ret = set_dtr(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
HIGH)) < 0) {
case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
dbg("%s TIOCMBIS", __FUNCTION__);
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
if (mask & TIOCM_DTR){
if ((ret = set_dtr(port, HIGH)) < 0) {
err("Urb to set DTR failed");
goto exit;
return(ret);
}
if (clear & TIOCM_RTS)
if ((ret = set_rts(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
LOW)) < 0) {
err("Urb to unset RTS failed");
goto exit;
}
if (mask & TIOCM_RTS) {
if ((ret = set_rts(port, HIGH)) < 0){
err("Urb to set RTS failed");
return(ret);
}
}
return(0);
break;
if (clear & TIOCM_DTR)
if ((ret = set_dtr(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
LOW)) < 0) {
case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
dbg("%s TIOCMBIC", __FUNCTION__);
if (get_user(mask, (unsigned long *) arg))
return -EFAULT;
if (mask & TIOCM_DTR){
if ((ret = set_dtr(port, LOW)) < 0){
err("Urb to unset DTR failed");
goto exit;
return(ret);
}
}
if (mask & TIOCM_RTS) {
if ((ret = set_rts(port, LOW)) < 0){
err("Urb to unset RTS failed");
return(ret);
}
}
return(0);
break;
exit:
return ret;
}
/*
* I had originally implemented TCSET{A,S}{,F,W} and
* TCGET{A,S} here separately, however when testing I
* found that the higher layers actually do the termios
* conversions themselves and pass the call onto
* ftdi_sio_set_termios.
*
*/
static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
case TIOCGSERIAL: /* gets serial port data */
return get_serial_info(port, (struct serial_struct *) arg);
switch (cmd) {
default:
/* This is not an error - turns out the higher layers will do
* some ioctls itself
case TIOCSSERIAL: /* sets serial port data */
return set_serial_info(port, (struct serial_struct *) arg);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was.
*
* This code is borrowed from linux/drivers/char/serial.c
*/
dbg("%s arg not supported - it was 0x%04x", __FUNCTION__,cmd);
return(-ENOIOCTLCMD);
break;
case TIOCMIWAIT:
while (priv != NULL) {
interruptible_sleep_on(&priv->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
else {
char diff = priv->diff_status;
if (diff == 0) {
return -EIO; /* no change => error */
}
/* Consume all events */
priv->diff_status = 0;
/* Return 0 if caller wanted to know about these bits */
if ( ((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
((arg & TIOCM_CD) && (diff & FTDI_RS0_RLSD)) ||
((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS)) ) {
return 0;
} /* ftdi_sio_ioctl */
}
/*
* Otherwise caller can't care less about what happened,
* and so we continue to wait for more events.
*/
}
}
return(0);
break;
default:
break;
}
/* This is not necessarily an error - turns out the higher layers will do
* some ioctls itself (see comment above)
*/
dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
return(-ENOIOCTLCMD);
} /* ftdi_ioctl */
static int __init ftdi_sio_init (void)
static void ftdi_throttle (struct usb_serial_port *port)
{
dbg("%s - port %d", __FUNCTION__, port->number);
usb_unlink_urb (port->read_urb);
}
static void ftdi_unthrottle (struct usb_serial_port *port)
{
int result;
struct usb_serial *serial = port->serial;
dbg("%s - port %d", __FUNCTION__, port->number);
port->read_urb->dev = serial->dev;
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,
ftdi_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
}
static int __init ftdi_init (void)
{
dbg("%s", __FUNCTION__);
usb_serial_register (&ftdi_sio_device);
usb_serial_register (&ftdi_SIO_device);
usb_serial_register (&ftdi_8U232AM_device);
usb_serial_register (&ftdi_FT232BM_device);
usb_serial_register (&ftdi_USB_UIRT_device);
usb_serial_register (&ftdi_HE_TIRA1_device);
usb_register (&ftdi_driver);
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
static void __exit ftdi_sio_exit (void)
static void __exit ftdi_exit (void)
{
dbg("%s", __FUNCTION__);
usb_deregister (&ftdi_driver);
usb_serial_deregister (&ftdi_sio_device);
usb_serial_deregister (&ftdi_HE_TIRA1_device);
usb_serial_deregister (&ftdi_USB_UIRT_device);
usb_serial_deregister (&ftdi_FT232BM_device);
usb_serial_deregister (&ftdi_8U232AM_device);
usb_serial_deregister (&ftdi_SIO_device);
}
module_init(ftdi_sio_init);
module_exit(ftdi_sio_exit);
module_init(ftdi_init);
module_exit(ftdi_exit);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
......
......@@ -14,11 +14,12 @@
* of the protocol required to talk to the device and ongoing assistence
* during development.
*
* Bill Ryder - bryder@sgi.com of Silicon Graphics, Inc.- wrote the
* Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the
* FTDI_SIO implementation.
*
* Philipp Ghring - pg@futureware.at - added the Device ID of the USB relais
* from Rudolf Gugler
*
*/
#define FTDI_VID 0x0403 /* Vendor Id */
......@@ -28,6 +29,93 @@
#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
/* they use the ftdi chipset for the USB interface and the vendor id is the same */
#define FTDI_XF_634_PID 0xFC09 /* Four line device */
#define FTDI_XF_632_PID 0xFC08 /* Two line device */
/* Video Networks Limited / Homechoice in the UK use an ftdi-based device for their 1Mb */
/* broadband internet service. The following PID is exhibited by the usb device supplied */
/* (the VID is the standard ftdi vid (FTDI_VID) */
#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */
/*
* The following are the values for the Matrix Orbital LCD displays,
* which are the FT232BM ( similar to the 8U232AM )
*/
#define FTDI_MTXORB_VID FTDI_VID /* Matrix Orbital Product Id */
#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
/*
* The following are the values for the Sealevel SeaLINK+ adapters.
* (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and
* removed some PIDs that don't seem to match any existing products.)
*/
#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */
#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */
#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */
#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */
#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */
#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */
#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */
#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */
#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */
#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */
#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */
#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */
#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */
#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */
#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */
#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */
#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */
#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */
#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */
#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */
#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */
#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */
#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */
#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */
#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */
#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */
#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */
#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */
#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */
#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */
#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */
#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */
#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */
#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */
#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */
#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */
#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */
#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */
#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
/*
* Home Electronics (www.home-electro.com) USB gadgets
*/
#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR tranceiver */
/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */
/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
......@@ -84,19 +172,61 @@
/*
* BmRequestType: 0100 0000B
* bRequest: FTDI_SIO_SET_BAUDRATE
* wValue: BaudRate value - see below
* wValue: BaudDivisor value - see below
* wIndex: Port
* wLength: 0
* Data: None
* The BaudDivisor values are calculated as follows:
* - BaseClock is either 12000000 or 48000000 depending on the device. FIXME: I wish
* I knew how to detect old chips to select proper base clock!
* - BaudDivisor is a fixed point number encoded in a funny way.
* (--WRONG WAY OF THINKING--)
* BaudDivisor is a fixed point number encoded with following bit weighs:
* (-2)(-1)(13..0). It is a radical with a denominator of 4, so values
* end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...).
* (--THE REALITY--)
* The both-bits-set has quite different meaning from 0.75 - the chip designers
* have decided it to mean 0.125 instead of 0.75.
* This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates
* and Flow Control Consideration for USB to RS232".
* - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should
* automagically re-encode the resulting value to take fractions into consideration.
* As all values are integers, some bit twiddling is in order:
* BaudDivisor = (BaseClock / 16 / BaudRate) |
* (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5
* : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000 // 0.25
* : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000 // 0.125
* : 0)
*
* For the FT232BM, a 17th divisor bit was introduced to encode the multiples
* of 0.125 missing from the FT8U232AM. Bits 16 to 14 are coded as follows
* (the first four codes are the same as for the FT8U232AM, where bit 16 is
* always 0):
* 000 - add .000 to divisor
* 001 - add .500 to divisor
* 010 - add .250 to divisor
* 011 - add .125 to divisor
* 100 - add .375 to divisor
* 101 - add .625 to divisor
* 110 - add .750 to divisor
* 111 - add .875 to divisor
* Bits 15 to 0 of the 17-bit divisor are placed in the urb value. Bit 16 is
* placed in bit 0 of the urb index.
*
* Note that there are a couple of special cases to support the highest baud
* rates. If the calculated divisor value is 1, this needs to be replaced with
* 0. Additionally for the FT232BM, if the calculated divisor value is 0x4001
* (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is
* not supported by the FT8U232AM).
*/
enum ftdi_type {
sio = 1,
F8U232AM = 2,
};
typedef enum {
SIO = 1,
FT8U232AM = 2,
FT232BM = 3,
} ftdi_chip_type_t;
enum {
typedef enum {
ftdi_sio_b300 = 0,
ftdi_sio_b600 = 1,
ftdi_sio_b1200 = 2,
......@@ -107,39 +237,12 @@ enum {
ftdi_sio_b38400 = 7,
ftdi_sio_b57600 = 8,
ftdi_sio_b115200 = 9
};
enum {
ftdi_8U232AM_12MHz_b300 = 0x09c4,
ftdi_8U232AM_12MHz_b600 = 0x04E2,
ftdi_8U232AM_12MHz_b1200 = 0x0271,
ftdi_8U232AM_12MHz_b2400 = 0x4138,
ftdi_8U232AM_12MHz_b4800 = 0x809c,
ftdi_8U232AM_12MHz_b9600 = 0xc04e,
ftdi_8U232AM_12MHz_b19200 = 0x0027,
ftdi_8U232AM_12MHz_b38400 = 0x4013,
ftdi_8U232AM_12MHz_b57600 = 0x000d,
ftdi_8U232AM_12MHz_b115200 = 0x4006,
ftdi_8U232AM_12MHz_b230400 = 0x8003,
};
/* Apparently all devices are 48MHz */
enum {
ftdi_8U232AM_48MHz_b300 = 0x2710,
ftdi_8U232AM_48MHz_b600 = 0x1388,
ftdi_8U232AM_48MHz_b1200 = 0x09c4,
ftdi_8U232AM_48MHz_b2400 = 0x04e2,
ftdi_8U232AM_48MHz_b4800 = 0x0271,
ftdi_8U232AM_48MHz_b9600 = 0x4138,
ftdi_8U232AM_48MHz_b19200 = 0x809c,
ftdi_8U232AM_48MHz_b38400 = 0xc04e,
ftdi_8U232AM_48MHz_b57600 = 0x0034,
ftdi_8U232AM_48MHz_b115200 = 0x001a,
ftdi_8U232AM_48MHz_b230400 = 0x000d,
ftdi_8U232AM_48MHz_b460800 = 0x4006,
ftdi_8U232AM_48MHz_b921600 = 0x8003,
};
} FTDI_SIO_baudrate_t ;
/*
* The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor values
* are calculated internally.
*/
#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
......@@ -443,6 +546,11 @@ enum {
* B7 Error in RCVR FIFO
*
*/
#define FTDI_RS0_CTS (1 << 4)
#define FTDI_RS0_DSR (1 << 5)
#define FTDI_RS0_RI (1 << 6)
#define FTDI_RS0_RLSD (1 << 7)
#define FTDI_RS_DR 1
#define FTDI_RS_OE (1<<1)
#define FTDI_RS_PE (1<<2)
......
......@@ -94,7 +94,7 @@ static int datafab_read_data(struct us_data *us,
unsigned char *dest,
int use_sg)
{
unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x20, 0x01 };
unsigned char *command = us->iobuf;
unsigned char *buffer = NULL;
unsigned char *ptr;
unsigned char thistime;
......@@ -116,8 +116,6 @@ static int datafab_read_data(struct us_data *us,
return rc;
}
command[5] += (info->lun << 4);
totallen = sectors * info->ssize;
do {
......@@ -138,10 +136,13 @@ static int datafab_read_data(struct us_data *us,
command[3] = (sector >> 8) & 0xFF;
command[4] = (sector >> 16) & 0xFF;
command[5] = 0xE0 + (info->lun << 4);
command[5] |= (sector >> 24) & 0x0F;
command[6] = 0x20;
command[7] = 0x01;
// send the read command
result = datafab_bulk_write(us, command, sizeof(command));
result = datafab_bulk_write(us, command, 8);
if (result != USB_STOR_XFER_GOOD)
goto leave;
......@@ -180,8 +181,8 @@ static int datafab_write_data(struct us_data *us,
unsigned char *src,
int use_sg)
{
unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x30, 0x02 };
unsigned char reply[2] = { 0, 0 };
unsigned char *command = us->iobuf;
unsigned char *reply = us->iobuf;
unsigned char *buffer = NULL;
unsigned char *ptr;
unsigned char thistime;
......@@ -202,8 +203,6 @@ static int datafab_write_data(struct us_data *us,
return rc;
}
command[5] += (info->lun << 4);
// If we're using scatter-gather, we have to create a new
// buffer to read all of the data in first, since a
// scatter-gather buffer could in theory start in the middle
......@@ -237,10 +236,13 @@ static int datafab_write_data(struct us_data *us,
command[3] = (sector >> 8) & 0xFF;
command[4] = (sector >> 16) & 0xFF;
command[5] = 0xE0 + (info->lun << 4);
command[5] |= (sector >> 24) & 0x0F;
command[6] = 0x30;
command[7] = 0x02;
// send the command
result = datafab_bulk_write(us, command, sizeof(command));
result = datafab_bulk_write(us, command, 8);
if (result != USB_STOR_XFER_GOOD)
goto leave;
......@@ -250,7 +252,7 @@ static int datafab_write_data(struct us_data *us,
goto leave;
// read the result
result = datafab_bulk_read(us, reply, sizeof(reply));
result = datafab_bulk_read(us, reply, 2);
if (result != USB_STOR_XFER_GOOD)
goto leave;
......@@ -291,13 +293,19 @@ static int datafab_determine_lun(struct us_data *us,
//
// There might be a better way of doing this?
unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char buf[512];
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char *command = us->iobuf;
unsigned char *buf;
int count = 0, rc;
if (!us || !info)
return USB_STOR_TRANSPORT_ERROR;
memcpy(command, scommand, 8);
buf = kmalloc(512, GFP_NOIO);
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
US_DEBUGP("datafab_determine_lun: locating...\n");
// we'll try 3 times before giving up...
......@@ -306,31 +314,41 @@ static int datafab_determine_lun(struct us_data *us,
command[5] = 0xa0;
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (rc != USB_STOR_XFER_GOOD) {
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
rc = datafab_bulk_read(us, buf, sizeof(buf));
rc = datafab_bulk_read(us, buf, 512);
if (rc == USB_STOR_XFER_GOOD) {
info->lun = 0;
return USB_STOR_TRANSPORT_GOOD;
rc = USB_STOR_TRANSPORT_GOOD;
goto leave;
}
command[5] = 0xb0;
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (rc != USB_STOR_XFER_GOOD) {
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
rc = datafab_bulk_read(us, buf, sizeof(buf));
rc = datafab_bulk_read(us, buf, 512);
if (rc == USB_STOR_XFER_GOOD) {
info->lun = 1;
return USB_STOR_TRANSPORT_GOOD;
rc = USB_STOR_TRANSPORT_GOOD;
goto leave;
}
wait_ms(20);
}
return USB_STOR_TRANSPORT_ERROR;
rc = USB_STOR_TRANSPORT_ERROR;
leave:
kfree(buf);
return rc;
}
static int datafab_id_device(struct us_data *us,
......@@ -340,8 +358,9 @@ static int datafab_id_device(struct us_data *us,
// to the ATA spec, 'Sector Count' isn't used but the Windows driver
// sets this bit so we do too...
//
unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char reply[512];
static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
unsigned char *command = us->iobuf;
unsigned char *reply;
int rc;
if (!us || !info)
......@@ -353,11 +372,18 @@ static int datafab_id_device(struct us_data *us,
return rc;
}
memcpy(command, scommand, 8);
reply = kmalloc(512, GFP_NOIO);
if (!reply)
return USB_STOR_TRANSPORT_ERROR;
command[5] += (info->lun << 4);
rc = datafab_bulk_write(us, command, 8);
if (rc != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR;
if (rc != USB_STOR_XFER_GOOD) {
rc = USB_STOR_TRANSPORT_ERROR;
goto leave;
}
// we'll go ahead and extract the media capacity while we're here...
//
......@@ -369,10 +395,15 @@ static int datafab_id_device(struct us_data *us,
((u32)(reply[116]) << 16) |
((u32)(reply[115]) << 8) |
((u32)(reply[114]) );
return USB_STOR_TRANSPORT_GOOD;
rc = USB_STOR_TRANSPORT_GOOD;
goto leave;
}
return USB_STOR_TRANSPORT_ERROR;
rc = USB_STOR_TRANSPORT_ERROR;
leave:
kfree(reply);
return rc;
}
......@@ -571,8 +602,7 @@ int datafab_transport(Scsi_Cmnd * srb, struct us_data *us)
return USB_STOR_TRANSPORT_ERROR;
}
// don't bother implementing READ_6 or WRITE_6. Just set MODE_XLATE and
// let the usb storage code convert to READ_10/WRITE_10
// don't bother implementing READ_6 or WRITE_6.
//
if (srb->cmnd[0] == READ_10) {
block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
......
......@@ -44,11 +44,6 @@ static void pdump (void *, int);
#define ERR_STAT 0x01
#define DRQ_STAT 0x08
struct freecom_udata {
u8 buffer[64]; /* Common command block. */
};
typedef struct freecom_udata *freecom_udata_t;
/* All of the outgoing packets are 64 bytes long. */
struct freecom_cb_wrap {
u8 Type; /* Command type. */
......@@ -112,9 +107,8 @@ static int
freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
unsigned int ipipe, unsigned int opipe, int count)
{
freecom_udata_t extra = (freecom_udata_t) us->extra;
struct freecom_xfer_wrap *fxfr =
(struct freecom_xfer_wrap *) extra->buffer;
(struct freecom_xfer_wrap *) us->iobuf;
int result;
fxfr->Type = FCM_PACKET_INPUT | 0x00;
......@@ -147,9 +141,8 @@ static int
freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
int unsigned ipipe, unsigned int opipe, int count)
{
freecom_udata_t extra = (freecom_udata_t) us->extra;
struct freecom_xfer_wrap *fxfr =
(struct freecom_xfer_wrap *) extra->buffer;
(struct freecom_xfer_wrap *) us->iobuf;
int result;
fxfr->Type = FCM_PACKET_OUTPUT | 0x00;
......@@ -190,12 +183,9 @@ int freecom_transport(Scsi_Cmnd *srb, struct us_data *us)
int result;
unsigned int partial;
int length;
freecom_udata_t extra;
extra = (freecom_udata_t) us->extra;
fcb = (struct freecom_cb_wrap *) extra->buffer;
fst = (struct freecom_status *) extra->buffer;
fcb = (struct freecom_cb_wrap *) us->iobuf;
fst = (struct freecom_status *) us->iobuf;
US_DEBUGP("Freecom TRANSPORT STARTED\n");
......@@ -386,18 +376,11 @@ int
freecom_init (struct us_data *us)
{
int result;
char buffer[33];
/* Allocate a buffer for us. The upper usb transport code will
* free this for us when cleaning up. */
if (us->extra == NULL) {
us->extra = kmalloc (sizeof (struct freecom_udata),
GFP_KERNEL);
if (us->extra == NULL) {
US_DEBUGP("Out of memory\n");
return USB_STOR_TRANSPORT_ERROR;
}
}
char *buffer = us->iobuf;
/* The DMA-mapped I/O buffer is 64 bytes long, just right for
* all our packets. No need to allocate any extra buffer space.
*/
result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
......
......@@ -47,38 +47,27 @@
* mode */
int usb_stor_euscsi_init(struct us_data *us)
{
unsigned char data = 0x1;
int result;
US_DEBUGP("Attempting to init eUSCSI bridge...\n");
us->iobuf[0] = 0x1;
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
0x01, 0x0, &data, 0x1, 5*HZ);
0x01, 0x0, us->iobuf, 0x1, 5*HZ);
US_DEBUGP("-- result is %d\n", result);
US_DEBUGP("-- data afterwards is %d\n", data);
US_DEBUGP("-- data afterwards is %d\n", us->iobuf[0]);
return 0;
}
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us)
{
struct bulk_cb_wrap *bcb;
struct bulk_cs_wrap *bcs;
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf;
struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf;
int res, partial;
bcb = kmalloc(sizeof *bcb, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
if (!bcb) {
return(-1);
}
bcs = kmalloc(sizeof *bcs, in_interrupt() ? GFP_ATOMIC : GFP_NOIO);
if (!bcs) {
kfree(bcb);
return(-1);
}
US_DEBUGP("Sending UCR-61S2B initialization packet...\n");
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
......@@ -91,19 +80,12 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
US_BULK_CB_WRAP_LEN, &partial);
US_DEBUGP("-- result is %d\n", res);
kfree(bcb);
if(res) {
kfree(bcs);
return(res);
}
if(res)
return res;
US_DEBUGP("Getting status packet...\n");
res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
US_BULK_CS_WRAP_LEN, &partial);
US_DEBUGP("-- result of status read is %d\n", res);
kfree(bcs);
return(res ? -1 : 0);
return (res ? -1 : 0);
}
......@@ -90,12 +90,6 @@ UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100,
US_SC_SCSI, US_PR_DPCM_USB, NULL, 0 ),
#endif
/* Made with the help of Edd Dumbill <edd@usefulinc.com> */
UNUSUAL_DEV( 0x0451, 0x5409, 0x0001, 0x0001,
"Frontier Labs",
"Nex II Digital",
US_SC_SCSI, US_PR_BULK, NULL, 0),
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
"Kyocera",
......@@ -276,7 +270,7 @@ UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310,
UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999,
"Sony",
"Memorystick MSC-U01N",
US_SC_UFI, US_PR_CB, NULL,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999,
......@@ -301,7 +295,7 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_UFI, US_PR_CBI, NULL,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN),
UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
......
......@@ -646,9 +646,6 @@ static void skel_disconnect(struct usb_interface *interface)
dev = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
if (!dev)
return;
down (&dev->sem);
/* disable open() */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment