Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
4bec6175
Commit
4bec6175
authored
Jul 10, 2003
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
Merge kroah.com:/home/greg/linux/BK/bleed-2.5
into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents
c3d5155c
2fc16028
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1748 additions
and
614 deletions
+1748
-614
MAINTAINERS
MAINTAINERS
+1
-1
drivers/usb/class/usblp.c
drivers/usb/class/usblp.c
+14
-10
drivers/usb/core/inode.c
drivers/usb/core/inode.c
+0
-4
drivers/usb/core/message.c
drivers/usb/core/message.c
+1
-1
drivers/usb/net/usbnet.c
drivers/usb/net/usbnet.c
+1
-1
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.c
+1502
-462
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/ftdi_sio.h
+149
-41
drivers/usb/storage/datafab.c
drivers/usb/storage/datafab.c
+60
-30
drivers/usb/storage/freecom.c
drivers/usb/storage/freecom.c
+9
-26
drivers/usb/storage/initializers.c
drivers/usb/storage/initializers.c
+9
-27
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_devs.h
+2
-8
drivers/usb/usb-skeleton.c
drivers/usb/usb-skeleton.c
+0
-3
No files found.
MAINTAINERS
View file @
4bec6175
...
...
@@ -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
...
...
drivers/usb/class/usblp.c
View file @
4bec6175
...
...
@@ -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
clo
se */
else
/* cleanup later, on
relea
se */
up
(
&
usblp
->
sem
);
unlock_kernel
();
}
...
...
drivers/usb/core/inode.c
View file @
4bec6175
...
...
@@ -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
);
}
...
...
drivers/usb/core/message.c
View file @
4bec6175
...
...
@@ -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
;
...
...
drivers/usb/net/usbnet.c
View file @
4bec6175
...
...
@@ -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
);
...
...
drivers/usb/serial/ftdi_sio.c
View file @
4bec6175
...
...
@@ -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
...
...
@@ -13,49 +15,156 @@
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation
* 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.
*
c
leaned up write offset calculation
*
a
dded write_room since default values can be incorrect for sio
*
c
hanged 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.
*
Fixed bug in read_bulk_callback where incorrect urb buffer was used.
*
C
leaned up write offset calculation
*
A
dded write_room since default values can be incorrect for sio
*
C
hanged 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
*
s
witched from using spinlock to a semaphore, which fixes lots of problems.
*
S
witched from using spinlock to a semaphore, which fixes lots of problems.
*
* (23/May/2001) Bill Ryder
*
Added runtime debug patch (thanx Tyson D Sawyer).
*
Cleaned up comments for 8U232
*
Added parity, framing and overrun error handling
*
Added receive break handling.
*
Added runtime debug patch (thanx Tyson D Sawyer).
*
Cleaned up comments for 8U232
*
Added parity, framing and overrun error handling
*
Added receive break handling.
*
* (04/08/2001) gb
* Identify version on module load.
*
* (18/March/2001) Bill Ryder
*
(Not released)
*
Added send break handling. (requires kernel patch too)
*
Fixed 8U232AM hardware RTS/CTS etc status reporting.
*
Added flipbuf fix copied from generic device
*
(Not released)
*
Added send break handling. (requires kernel patch too)
*
Fixed 8U232AM hardware RTS/CTS etc status reporting.
*
Added flipbuf fix copied from generic device
*
* (12/3/2000) Bill Ryder
* Added support for 8U232AM device.
* Moved PID and VIDs into header file only.
* Turned on low-latency for the tty (device will do high baudrates)
* Added shutdown routine to close files when device removed.
* More debug and error message cleanups.
*
* Added support for 8U232AM device.
* Moved PID and VIDs into header file only.
* Turned on low-latency for the tty (device will do high baudrates)
* 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).
*
Cleaned up comments. Removed multiple PID/VID definitions.
*
Factorised cts/dtr code
*
Made use of __FUNCTION__ in dbg's
*
Added spinlock protected open code and close code.
*
Multiple opens work (sort of - see webpage mentioned above).
*
Cleaned up comments. Removed multiple PID/VID definitions.
*
Factorised cts/dtr code
*
Made use of __FUNCTION__ in dbg's
*
* (11/01/2000) Adam J. Richter
* usb_device_id table support
...
...
@@ -72,16 +181,16 @@
* driver is a loadable module now.
*
* (04/04/2000) Bill Ryder
*
Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
*
Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
* handled elsewhere in the tty io driver chain).
*
* (03/30/2000) Bill Ryder
*
Implemented lots of ioctls
*
Fixed a race condition in write
*
Changed some dbg's to errs
*
Implemented lots of ioctls
* Fixed a race condition in write
* Changed some dbg's to errs
*
* (03/26/2000) gkh
*
Split driver up into device specific pieces.
* Split driver up into device specific pieces.
*
*/
...
...
@@ -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
ftdi_sio_startup
(
struct
usb_serial
*
serial
)
static
int
change_speed
(
struct
usb_serial_port
*
port
)
{
struct
ftdi_private
*
priv
;
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
);
priv
=
kmalloc
(
sizeof
(
struct
ftdi_private
),
GFP_KERNEL
);
if
(
!
priv
){
err
(
"%s- kmalloc(%Zd) failed."
,
__FUNCTION__
,
sizeof
(
struct
ftdi_private
));
return
-
ENOMEM
;
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
);
}
priv
->
ftdi_type
=
sio
;
priv
->
write_offset
=
1
;
usb_set_serial_port_data
(
serial
->
port
,
priv
);
/* 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 */
return
(
0
);
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
ftdi_8U232AM_startup
(
struct
usb_serial
*
serial
)
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
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
));
priv
->
ftdi_type
=
F8U232AM
;
priv
->
write_offset
=
0
;
usb_set_serial_port_data
(
serial
->
port
,
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
;
}
usb_set_serial_port_data
(
serial
->
port
,
priv
);
return
(
0
);
}
static
void
ftdi_sio_shutdown
(
struct
usb_serial
*
serial
)
/* Startup for the SIO chip */
/* Called from usbserial:serial_probe */
static
int
ftdi_SIO_startup
(
struct
usb_serial
*
serial
)
{
void
*
priv
;
struct
ftdi_private
*
priv
;
int
err
;
dbg
(
"%s"
,
__FUNCTION__
);
dbg
(
"%s"
,
__FUNCTION__
);
priv
=
usb_get_serial_port_data
(
&
serial
->
port
[
0
]);
if
(
priv
){
kfree
(
priv
);
usb_set_serial_port_data
(
&
serial
->
port
[
0
],
NULL
);
err
=
ftdi_common_startup
(
serial
);
if
(
err
){
return
(
err
);
}
priv
=
usb_get_serial_port_data
(
serial
->
port
);
priv
->
chip_type
=
SIO
;
priv
->
baud_base
=
12000000
/
16
;
priv
->
write_offset
=
1
;
return
(
0
);
}
/* 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__
);
/* 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
(
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_s
io_s
et_termios will send usb control messages */
ftdi_s
io_set_termios
(
port
,
&
tmp_termios
);
/* ftdi_set_termios will send usb control messages */
ftdi_s
et_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,38 +1212,46 @@ 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"
);
}
/* shutdown our bulk read */
if
(
port
->
read_urb
)
{
usb_unlink_urb
(
port
->
read_urb
);
}
/* unlink the running write urbs */
}
/* Note change no line is hupcl is off */
}
/* if (serial->dev) */
/* shutdown our bulk reads and writes */
/* ***CHECK*** behaviour when there is nothing queued */
usb_unlink_urb
(
port
->
write_urb
);
usb_unlink_urb
(
port
->
read_urb
);
}
}
/* ftdi_sio_close */
}
/* 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
);
if
(
count
==
0
)
{
...
...
@@ -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
)));
}
count
+=
data_offset
;
count
=
(
count
>
port
->
bulk_out_size
)
?
port
->
bulk_out_size
:
count
;
buffer
=
kmalloc
(
transfer_size
,
GFP_ATOMIC
);
if
(
!
buffer
)
{
err
(
"%s ran out of kernel memory for urb ..."
,
__FUNCTION__
);
return
-
ENOMEM
;
}
/* Copy in the data to send */
if
(
from_user
)
{
if
(
copy_from_user
(
port
->
write_urb
->
transfer_buffer
+
data_offset
,
buf
,
count
-
data_offset
)){
return
-
EFAULT
;
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
{
memcpy
(
port
->
write_urb
->
transfer_buffer
+
data_offset
,
buf
,
count
-
data_offset
);
}
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
)
;
/* No control byte required. */
/* Copy in the data to send */
if
(
from_user
)
{
if
(
copy_from_user
(
buffer
,
buf
,
count
))
{
kfree
(
buffer
);
usb_free_urb
(
urb
);
return
-
EFAULT
;
}
}
else
{
memcpy
(
buffer
,
buf
,
count
);
}
}
dbg
(
"%s Bytes: %d, First Byte: 0x%02x"
,
__FUNCTION__
,
count
,
first_byte
[
0
]);
usb_serial_debug_data
(
__FILE__
,
__FUNCTION__
,
count
,
first_byte
);
/* send the data out the bulk port */
usb_fill_bulk_urb
(
port
->
write_urb
,
serial
->
dev
,
usb_serial_debug_data
(
__FILE__
,
__FUNCTION__
,
transfer_size
,
buffer
);
/* 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
);
result
=
usb_submit_urb
(
port
->
write_
urb
,
GFP_ATOMIC
);
if
(
result
)
{
err
(
"%s - failed submitting write urb, error %d"
,
__FUNCTION__
,
result
);
return
0
;
buffer
,
transfer_size
,
ftdi_write_bulk_callback
,
port
);
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"
))
{
return
;
}
serial
=
port
->
serial
;
if
(
serial_paranoia_check
(
serial
,
"ftdi_sio_write_bulk_callback"
))
{
if
(
port_paranoia_check
(
port
,
__FUNCTION__
))
return
;
}
if
(
urb
->
status
)
{
dbg
(
"nonzero write bulk status received: %d"
,
urb
->
status
);
return
;
}
schedule_work
(
&
port
->
work
);
}
/* ftdi_sio_write_bulk_callback */
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
);
static
int
ftdi_sio_write_room
(
struct
usb_serial_port
*
port
)
if
(
port
->
open_count
>
0
){
schedule_work
(
&
port
->
work
);
}
return
;
}
/* ftdi_write_bulk_callback */
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
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_sio_read_bulk_callback
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
/* ftdi_sio_serial_buld_callback */
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
,
"ftdi_sio_read_bulk_callback"
))
{
if
(
port_paranoia_check
(
port
,
__FUNCTION__
))
{
return
;
}
if
(
port
->
open_count
<=
0
)
return
;
serial
=
port
->
serial
;
if
(
serial_paranoia_check
(
serial
,
"ftdi_sio_read_bulk_callback"
))
{
serial
=
get_usb_serial
(
port
,
__FUNCTION__
);
if
(
!
serial
){
dbg
(
"%s - bad serial pointer - exiting"
,
__FUNCTION__
);
return
;
}
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%03
o"
,
data
[
0
],
data
[
1
]);
dbg
(
"
Status only: %03oo %03o
o"
,
data
[
0
],
data
[
1
]);
}
...
...
@@ -559,129 +1473,101 @@ 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 */
/* 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
)
{
error_flag
=
TTY_OVERRUN
;
dbg
(
"OVERRRUN error"
);
}
if
(
data
[
1
]
&
FTDI_RS_BI
)
{
error_flag
=
TTY_BREAK
;
dbg
(
"BREAK received"
);
}
if
(
data
[
1
]
&
FTDI_RS_PE
)
{
error_flag
=
TTY_PARITY
;
dbg
(
"PARITY error"
);
}
if
(
data
[
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
)
{
/* have to make sure we don't overflow the buffer
with tty_insert_flip_char's */
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
tty_flip_buffer_push
(
tty
);
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
;
}
/* 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_flip_buffer_push
(
tty
);
/* 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
[
packet_offset
+
1
]
&
FTDI_RS_OE
)
{
error_flag
=
TTY_OVERRUN
;
dbg
(
"OVERRRUN error"
);
}
if
(
data
[
packet_offset
+
1
]
&
FTDI_RS_BI
)
{
error_flag
=
TTY_BREAK
;
dbg
(
"BREAK received"
);
}
if
(
data
[
packet_offset
+
1
]
&
FTDI_RS_PE
)
{
error_flag
=
TTY_PARITY
;
dbg
(
"PARITY error"
);
}
if
(
data
[
packet_offset
+
1
]
&
FTDI_RS_FE
)
{
error_flag
=
TTY_FRAME
;
dbg
(
"FRAMING error"
);
}
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
)
{
tty_flip_buffer_push
(
tty
);
}
/* 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
[
packet_offset
+
i
],
error_flag
);
}
need_flip
=
1
;
}
#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
/* if a parity error is detected you get status packets forever
until a character is sent without a parity error.
This doesn't work well since the application receives a never
ending stream of bad data - even though new data hasn't been sent.
Therefore I (bill) have taken this out.
However - this might make sense for framing errors and so on
so I am leaving the code in for now.
*/
else
{
if
(
error_flag
!=
TTY_NORMAL
){
dbg
(
"error_flag is not normal"
);
/* if a parity error is detected you get status packets forever
until a character is sent without a parity error.
This doesn't work well since the application receives a never
ending stream of bad data - even though new data hasn't been sent.
Therefore I (bill) have taken this out.
However - this might make sense for framing errors and so on
so I am leaving the code in for now.
*/
else
{
if
(
error_flag
!=
TTY_NORMAL
){
dbg
(
"error_flag is not normal"
);
/* In this case it is just status - if that is an error send a bad character */
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
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..." */
/* 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
);
/* Low latency */
if
(
need_flip
)
{
tty_flip_buffer_push
(
tty
);
}
result
=
usb_submit_urb
(
port
->
read_urb
,
GFP_ATOMIC
);
if
(
result
)
err
(
"%s - failed resubmitting read urb, error %d"
,
__FUNCTION__
,
result
);
/* 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_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 */
}
/* ftdi_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
);
}
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,146 +1711,290 @@ static void ftdi_sio_set_termios (struct usb_serial_port *port, struct termios *
}
}
else
{
/* 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
,
usb_sndctrlpipe
(
serial
->
dev
,
0
),
FTDI_SIO_SET_FLOW_CTRL_REQUEST
,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE
,
0
,
0
,
buf
,
0
,
WDR_TIMEOUT
)
<
0
)
{
err
(
"urb failed to clear flow control"
);
}
/*
* 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
,
usb_sndctrlpipe
(
serial
->
dev
,
0
),
FTDI_SIO_SET_FLOW_CTRL_REQUEST
,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE
,
0
,
0
,
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
;
__u16
urb_value
=
0
;
/* Will hold the new flags */
char
buf
[
2
];
int
ret
,
mask
;
dbg
(
"%s
"
,
__FUNCTION__
);
dbg
(
"%s
cmd 0x%04x"
,
__FUNCTION__
,
cmd
);
buf
=
kmalloc
(
2
,
GFP_KERNEL
);
if
(
!
buf
)
goto
exit
;
/* Based on code from acm.c and others */
switch
(
cmd
)
{
if
(
priv
->
ftdi_type
==
sio
)
{
size
=
1
;
}
else
{
/* 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
,
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
;
}
ret
=
(
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
;
}
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 */
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
,
2
,
WDR_TIMEOUT
))
<
0
)
{
err
(
"%s Could not get modem status of device - err: %d"
,
__FUNCTION__
,
ret
);
return
(
ret
);
}
break
;
default:
return
-
EFAULT
;
break
;
}
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__
)
;
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
)
|
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
);
}
if
(
set
&
TIOCM_DTR
)
if
((
ret
=
set_dtr
(
serial
->
dev
,
usb_sndctrlpipe
(
serial
->
dev
,
0
),
HIGH
))
<
0
)
{
err
(
"Urb to set DTR failed"
);
goto
exit
;
urb_value
=
((
mask
&
TIOCM_RTS
)
?
HIGH
:
LOW
);
if
((
ret
=
set_rts
(
port
,
urb_value
))
<
0
){
err
(
"Error from RTS set urb (TIOCMSET)"
);
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
;
return
(
0
);
break
;
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"
);
return
(
ret
);
}
}
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
)
{
err
(
"Urb to unset DTR failed"
);
goto
exit
;
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"
);
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.
*
*/
case
TIOCGSERIAL
:
/* gets serial port data */
return
get_serial_info
(
port
,
(
struct
serial_struct
*
)
arg
);
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
*/
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 */
}
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
);
/* Consume all events */
priv
->
diff_status
=
0
;
switch
(
cmd
)
{
/* 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
;
}
/*
* Otherwise caller can't care less about what happened,
* and so we continue to wait for more events.
*/
}
}
return
(
0
);
break
;
default:
/* This is not an error - turns out the higher layers will do
* some ioctls itself
*/
dbg
(
"%s arg not supported - it was 0x%04x"
,
__FUNCTION__
,
cmd
);
return
(
-
ENOIOCTLCMD
);
break
;
}
return
0
;
}
/* ftdi_sio_ioctl */
static
int
__init
ftdi_sio_init
(
void
)
/* 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
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
);
...
...
drivers/usb/serial/ftdi_sio.h
View file @
4bec6175
...
...
@@ -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: Baud
Rate
value - see below
* wValue: Baud
Divisor
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)
...
...
drivers/usb/storage/datafab.c
View file @
4bec6175
...
...
@@ -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
)
|
...
...
drivers/usb/storage/freecom.c
View file @
4bec6175
...
...
@@ -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
);
...
...
drivers/usb/storage/initializers.c
View file @
4bec6175
...
...
@@ -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
);
}
drivers/usb/storage/unusual_devs.h
View file @
4bec6175
...
...
@@ -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
,
...
...
drivers/usb/usb-skeleton.c
View file @
4bec6175
...
...
@@ -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() */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment