Merge branch 'serial-from-alan'

* serial-from-alan: (79 commits)
  moxa: prevent opening unavailable ports
  imx: serial: use tty_encode_baud_rate to set true rate
  imx: serial: add IrDA support to serial driver
  imx: serial: use rational library function
  lib: isolate rational fractions helper function
  imx: serial: handle initialisation failure correctly
  imx: serial: be sure to stop xmit upon shutdown
  imx: serial: notify higher layers in case xmit IRQ was not called
  imx: serial: fix one bit field type
  imx: serial: fix whitespaces (no changes in functionality)
  tty: use prepare/finish_wait
  tty: remove sleep_on
  sierra: driver interface blacklisting
  sierra: driver urb handling improvements
  tty: resolve some sierra breakage
  timbuart: Fix the termios logic
  serial: Added Timberdale UART driver
  tty: Add URL for ttydev queue
  devpts: unregister the file system on error
  tty: Untangle termios and mm mutex dependencies
  ...
This commit is contained in:
Linus Torvalds 2009-06-11 08:57:47 -07:00
commit 49c355617f
95 changed files with 4433 additions and 2709 deletions

View File

@ -71,7 +71,7 @@ P: Person
M: Mail patches to
L: Mailing list that is relevant to this area
W: Web-page with status/info
T: SCM tree type and location. Type is one of: git, hg, quilt.
T: SCM tree type and location. Type is one of: git, hg, quilt, stgit.
S: Status, one of the following:
Supported: Someone is actually paid to look after this.
@ -159,7 +159,8 @@ F: drivers/net/r8169.c
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net
S: Orphan
M: alan@lxorguk.ukuu.org.uk
S: Odd Fixes
F: drivers/serial/8250*
F: include/linux/serial_8250.h
@ -5629,6 +5630,7 @@ P: Alan Cox
M: alan@lxorguk.ukuu.org.uk
L: linux-kernel@vger.kernel.org
S: Maintained
T: stgit http://zeniv.linux.org.uk/~alan/ttydev/
TULIP NETWORK DRIVERS
P: Grant Grundler

View File

@ -20,11 +20,16 @@
#define ASMARM_ARCH_UART_H
#define IMXUART_HAVE_RTSCTS (1<<0)
#define IMXUART_IRDA (1<<1)
struct imxuart_platform_data {
int (*init)(struct platform_device *pdev);
int (*exit)(struct platform_device *pdev);
unsigned int flags;
void (*irda_enable)(int enable);
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short transceiver_delay;
};
#endif

View File

@ -67,6 +67,7 @@ static inline int user_termio_to_kernel_termios(struct ktermios *termios,
SET_LOW_TERMIOS_BITS(termios, termio, c_oflag);
SET_LOW_TERMIOS_BITS(termios, termio, c_cflag);
SET_LOW_TERMIOS_BITS(termios, termio, c_lflag);
get_user(termios->c_line, &termio->c_line);
return copy_from_user(termios->c_cc, termio->c_cc, NCC);
}

View File

@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
open path is before the ldisc is referencable */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
return 0;
@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
return err;
}
tty->low_latency = 1;
} else
return -EBUSY;
break;

View File

@ -97,6 +97,19 @@ config DEVKMEM
kind of kernel debugging operations.
When in doubt, say "N".
config BFIN_JTAG_COMM
tristate "Blackfin JTAG Communication"
depends on BLACKFIN
help
Add support for emulating a TTY device over the Blackfin JTAG.
To compile this driver as a module, choose M here: the
module will be called bfin_jtag_comm.
config BFIN_JTAG_COMM_CONSOLE
bool "Console on Blackfin JTAG"
depends on BFIN_JTAG_COMM=y
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
depends on HAS_IOMEM

View File

@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o
obj-$(CONFIG_UNIX98_PTYS) += pty.o
obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
obj-$(CONFIG_AUDIT) += tty_audit.o

View File

@ -0,0 +1,365 @@
/*
* TTY over Blackfin JTAG Communication
*
* Copyright 2008-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/circ_buf.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <asm/atomic.h>
/* See the Debug/Emulation chapter in the HRM */
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
#define DRV_NAME "bfin-jtag-comm"
#define DEV_NAME "ttyBFJC"
#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
static inline uint32_t bfin_write_emudat(uint32_t emudat)
{
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
return emudat;
}
static inline uint32_t bfin_read_emudat(void)
{
uint32_t emudat;
__asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
return emudat;
}
static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
{
return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24));
}
#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */
#define CIRC_MASK (CIRC_SIZE - 1)
#define circ_empty(circ) ((circ)->head == (circ)->tail)
#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE)
#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK])
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
static struct tty_struct * volatile bfin_jc_tty;
static unsigned long bfin_jc_count;
static DEFINE_MUTEX(bfin_jc_tty_mutex);
static volatile struct circ_buf bfin_jc_write_buf;
static int
bfin_jc_emudat_manager(void *arg)
{
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
/* no one left to give data to, so sleep */
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
if (inbound_len)
schedule();
else
schedule_timeout_interruptible(HZ);
continue;
}
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
struct tty_struct *tty;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
debug("incoming length: 0x%08x\n", emudat);
inbound_len = emudat;
} else {
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
inbound_len -= num_chars;
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
tty_flip_buffer_push(tty);
}
}
mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) {
if (outbound_len == 0) {
outbound_len = circ_cnt(&bfin_jc_write_buf);
bfin_write_emudat(outbound_len);
debug("outgoing length: 0x%08x\n", outbound_len);
} else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
bfin_write_emudat_chars(
circ_byte(&bfin_jc_write_buf, tail + 0),
circ_byte(&bfin_jc_write_buf, tail + 1),
circ_byte(&bfin_jc_write_buf, tail + 2),
circ_byte(&bfin_jc_write_buf, tail + 3)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
mutex_lock(&bfin_jc_tty_mutex);
tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
}
__set_current_state(TASK_RUNNING);
return 0;
}
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
debug("open %lu\n", bfin_jc_count);
++bfin_jc_count;
bfin_jc_tty = tty;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
debug("close %lu\n", bfin_jc_count);
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL;
wake_up_process(bfin_jc_kthread);
mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
static int
bfin_jc_circ_write(const unsigned char *buf, int count)
{
int i;
count = min(count, circ_free(&bfin_jc_write_buf));
debug("going to write chunk of %i bytes\n", count);
for (i = 0; i < count; ++i)
circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
bfin_jc_write_buf.head += i;
return i;
}
#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
# define acquire_console_sem()
# define release_console_sem()
#endif
static int
bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int i;
acquire_console_sem();
i = bfin_jc_circ_write(buf, count);
release_console_sem();
wake_up_process(bfin_jc_kthread);
return i;
}
static void
bfin_jc_flush_chars(struct tty_struct *tty)
{
wake_up_process(bfin_jc_kthread);
}
static int
bfin_jc_write_room(struct tty_struct *tty)
{
return circ_free(&bfin_jc_write_buf);
}
static int
bfin_jc_chars_in_buffer(struct tty_struct *tty)
{
return circ_cnt(&bfin_jc_write_buf);
}
static void
bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
{
unsigned long expire = jiffies + timeout;
while (!circ_empty(&bfin_jc_write_buf)) {
if (signal_pending(current))
break;
if (time_after(jiffies, expire))
break;
}
}
static struct tty_operations bfin_jc_ops = {
.open = bfin_jc_open,
.close = bfin_jc_close,
.write = bfin_jc_write,
/*.put_char = bfin_jc_put_char,*/
.flush_chars = bfin_jc_flush_chars,
.write_room = bfin_jc_write_room,
.chars_in_buffer = bfin_jc_chars_in_buffer,
.wait_until_sent = bfin_jc_wait_until_sent,
};
static int __init bfin_jc_init(void)
{
int ret;
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
ret = -ENOMEM;
bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
if (!bfin_jc_write_buf.buf)
goto err;
bfin_jc_driver = alloc_tty_driver(1);
if (!bfin_jc_driver)
goto err;
bfin_jc_driver->owner = THIS_MODULE;
bfin_jc_driver->driver_name = DRV_NAME;
bfin_jc_driver->name = DEV_NAME;
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
bfin_jc_driver->init_termios = tty_std_termios;
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
ret = tty_register_driver(bfin_jc_driver);
if (ret)
goto err;
pr_init(KERN_INFO DRV_NAME ": initialized\n");
return 0;
err:
put_tty_driver(bfin_jc_driver);
kfree(bfin_jc_write_buf.buf);
kthread_stop(bfin_jc_kthread);
return ret;
}
module_init(bfin_jc_init);
static void __exit bfin_jc_exit(void)
{
kthread_stop(bfin_jc_kthread);
kfree(bfin_jc_write_buf.buf);
tty_unregister_driver(bfin_jc_driver);
put_tty_driver(bfin_jc_driver);
}
module_exit(bfin_jc_exit);
#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
static void
bfin_jc_straight_buffer_write(const char *buf, unsigned count)
{
unsigned ate = 0;
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat(count);
while (ate < count) {
while (bfin_read_DBGSTAT() & EMUDOF)
continue;
bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]);
ate += 4;
}
}
#endif
#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE
static void
bfin_jc_console_write(struct console *co, const char *buf, unsigned count)
{
if (bfin_jc_kthread == NULL)
bfin_jc_straight_buffer_write(buf, count);
else
bfin_jc_circ_write(buf, count);
}
static struct tty_driver *
bfin_jc_console_device(struct console *co, int *index)
{
*index = co->index;
return bfin_jc_driver;
}
static struct console bfin_jc_console = {
.name = DEV_NAME,
.write = bfin_jc_console_write,
.device = bfin_jc_console_device,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
static int __init bfin_jc_console_init(void)
{
register_console(&bfin_jc_console);
return 0;
}
console_initcall(bfin_jc_console_init);
#endif
#ifdef CONFIG_EARLY_PRINTK
static void __init
bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)
{
bfin_jc_straight_buffer_write(buf, count);
}
static struct __initdata console bfin_jc_early_console = {
.name = "early_BFJC",
.write = bfin_jc_early_write,
.flags = CON_ANYTIME | CON_PRINTBUFFER,
.index = -1,
};
struct console * __init
bfin_jc_early_init(unsigned int port, unsigned int cflag)
{
return &bfin_jc_early_console;
}
#endif
MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
MODULE_LICENSE("GPL");

View File

@ -604,7 +604,6 @@
#define NR_PORTS 256
#define ZE_V1_NPORTS 64
#define ZO_V1 0
#define ZO_V2 1
#define ZE_V1 2
@ -663,18 +662,6 @@
static void cy_throttle(struct tty_struct *tty);
static void cy_send_xchar(struct tty_struct *tty, char ch);
#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
#define Z_FPGA_CHECK(card) \
((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
(ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
#endif
@ -687,8 +674,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
#define DRIVER_VERSION 0x02010203
#define RAM_SIZE 0x80000
#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
enum zblock_type {
ZBLOCK_PRG = 0,
ZBLOCK_FPGA = 1
@ -883,6 +868,29 @@ static void cyz_rx_restart(unsigned long);
static struct timer_list cyz_rx_full_timer[NR_PORTS];
#endif /* CONFIG_CYZ_INTR */
static inline bool cy_is_Z(struct cyclades_card *card)
{
return card->num_chips == (unsigned int)-1;
}
static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
{
return readl(&ctl_addr->init_ctrl) & (1 << 17);
}
static inline bool cyz_fpga_loaded(struct cyclades_card *card)
{
return __cyz_fpga_loaded(card->ctl_addr.p9060);
}
static inline bool cyz_is_loaded(struct cyclades_card *card)
{
struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
readl(&fw_id->signature) == ZFIRM_ID;
}
static inline int serial_paranoia_check(struct cyclades_port *info,
char *name, const char *routine)
{
@ -1395,19 +1403,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
unsigned long loc_doorbell;
firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo))
return -1;
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->loc_doorbell);
loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
if (loc_doorbell) {
*cmd = (char)(0xff & loc_doorbell);
*channel = readl(&board_ctrl->fwcmd_channel);
*param = (__u32) readl(&board_ctrl->fwcmd_param);
cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
loc_doorbell, 0xffffffff);
cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
return 1;
}
return 0;
@ -1424,15 +1428,14 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
unsigned int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo))
if (!cyz_is_loaded(cinfo))
return -1;
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
index = 0;
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
if (index++ == 1000)
return (int)(readl(pci_doorbell) & 0xff);
@ -1624,10 +1627,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
static struct BOARD_CTRL __iomem *board_ctrl;
static struct CH_CTRL __iomem *ch_ctrl;
static struct BUF_CTRL __iomem *buf_ctrl;
__u32 channel;
__u32 channel, param, fw_ver;
__u8 cmd;
__u32 param;
__u32 hw_ver, fw_ver;
int special_count;
int delta_count;
@ -1635,8 +1636,6 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
fw_ver = readl(&board_ctrl->fw_version);
hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
mail_box_0);
while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
@ -1737,15 +1736,7 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
{
struct cyclades_card *cinfo = dev_id;
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
if (unlikely(!ISZLOADED(*cinfo))) {
if (unlikely(!cyz_is_loaded(cinfo))) {
#ifdef CY_DEBUG_INTERRUPTS
printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
"(IRQ%d).\n", irq);
@ -1785,7 +1776,6 @@ static void cyz_poll(unsigned long arg)
struct tty_struct *tty;
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
struct BUF_CTRL __iomem *buf_ctrl;
unsigned long expires = jiffies + HZ;
unsigned int port, card;
@ -1793,19 +1783,17 @@ static void cyz_poll(unsigned long arg)
for (card = 0; card < NR_CARDS; card++) {
cinfo = &cy_card[card];
if (!IS_CYC_Z(*cinfo))
if (!cy_is_Z(cinfo))
continue;
if (!ISZLOADED(*cinfo))
if (!cyz_is_loaded(cinfo))
continue;
firm_id = cinfo->base_addr + ID_ADDRESS;
zfw_ctrl = cinfo->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &(zfw_ctrl->board_ctrl);
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
cinfo->nports = (int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
continue;
}
@ -1874,7 +1862,7 @@ static int startup(struct cyclades_port *info)
set_line_char(info);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -1931,7 +1919,7 @@ static int startup(struct cyclades_port *info)
base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
if (!ISZLOADED(*card))
if (!cyz_is_loaded(card))
return -ENODEV;
zfw_ctrl = card->base_addr +
@ -2026,7 +2014,7 @@ static void start_xmit(struct cyclades_port *info)
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -2070,7 +2058,7 @@ static void shutdown(struct cyclades_port *info)
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -2126,7 +2114,7 @@ static void shutdown(struct cyclades_port *info)
#endif
firm_id = base_addr + ID_ADDRESS;
if (!ISZLOADED(*card))
if (!cyz_is_loaded(card))
return;
zfw_ctrl = card->base_addr +
@ -2233,7 +2221,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
#endif
info->port.blocked_open++;
if (!IS_CYC_Z(*cinfo)) {
if (!cy_is_Z(cinfo)) {
chip = channel >> 2;
channel &= 0x03;
index = cinfo->bus_index;
@ -2296,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
base_addr = cinfo->base_addr;
firm_id = base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
if (!cyz_is_loaded(cinfo)) {
__set_current_state(TASK_RUNNING);
remove_wait_queue(&info->port.open_wait, &wait);
return -EINVAL;
@ -2397,16 +2385,14 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
treat it as absent from the system. This
will make the user pay attention.
*/
if (IS_CYC_Z(*info->card)) {
if (cy_is_Z(info->card)) {
struct cyclades_card *cinfo = info->card;
struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->mail_box_0)) &&
Z_FPGA_CHECK(*cinfo)) &&
(ZFIRM_HLT == readl(
&firm_id->signature))) {
if (!cyz_is_loaded(cinfo)) {
if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
readl(&firm_id->signature) ==
ZFIRM_HLT) {
printk(KERN_ERR "cyc:Cyclades-Z Error: you "
"need an external power supply for "
"this number of ports.\nFirmware "
@ -2423,18 +2409,13 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
interrupts should be enabled as soon as the first open
happens to one of its ports. */
if (!cinfo->intr_enabled) {
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
zfw_ctrl = cinfo->base_addr +
(readl(&firm_id->zfwctrl_addr) &
0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
u16 intr;
/* Enable interrupts on the PLX chip */
cy_writew(cinfo->ctl_addr + 0x68,
readw(cinfo->ctl_addr + 0x68) | 0x0900);
intr = readw(&cinfo->ctl_addr.p9060->
intr_ctrl_stat) | 0x0900;
cy_writew(&cinfo->ctl_addr.p9060->
intr_ctrl_stat, intr);
/* Enable interrupts on the FW */
retval = cyz_issue_cmd(cinfo, 0,
C_CM_IRQ_ENBL, 0L);
@ -2442,8 +2423,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
printk(KERN_ERR "cyc:IRQ enable retval "
"was %x\n", retval);
}
cinfo->nports =
(int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
}
}
@ -2556,7 +2535,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
#endif
card = info->card;
channel = (info->line) - (card->first_line);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -2601,7 +2580,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
spin_unlock_irqrestore(&card->card_lock, flags);
if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
buffers as well */
spin_lock_irqsave(&card->card_lock, flags);
retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
@ -2682,7 +2661,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&card->card_lock, flags);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
int channel = info->line - card->first_line;
int index = card->bus_index;
void __iomem *base_addr = card->base_addr +
@ -2902,7 +2881,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
channel = (info->line) - (card->first_line);
#ifdef Z_EXT_CHARS_IN_BUFFER
if (!IS_CYC_Z(cy_card[card])) {
if (!cy_is_Z(card)) {
#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
@ -2984,7 +2963,6 @@ static void set_line_char(struct cyclades_port *info)
void __iomem *base_addr;
int chip, channel, index;
unsigned cflag, iflag;
unsigned short chip_number;
int baud, baud_rate = 0;
int i;
@ -3013,9 +2991,8 @@ static void set_line_char(struct cyclades_port *info)
card = info->card;
channel = info->line - card->first_line;
chip_number = channel / 4;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
index = card->bus_index;
@ -3233,21 +3210,17 @@ static void set_line_char(struct cyclades_port *info)
} else {
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
struct BUF_CTRL __iomem *buf_ctrl;
__u32 sw_flow;
int retval;
firm_id = card->base_addr + ID_ADDRESS;
if (!ISZLOADED(*card))
if (!cyz_is_loaded(card))
return;
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
/* baud rate */
baud = tty_get_baud_rate(info->port.tty);
@ -3457,7 +3430,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
card = info->card;
channel = (info->line) - (card->first_line);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3497,7 +3470,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3523,7 +3496,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
} else {
base_addr = card->base_addr;
firm_id = card->base_addr + ID_ADDRESS;
if (ISZLOADED(*card)) {
if (cyz_is_loaded(card)) {
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@ -3566,7 +3539,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
card = info->card;
channel = (info->line) - (card->first_line);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3641,7 +3614,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
base_addr = card->base_addr;
firm_id = card->base_addr + ID_ADDRESS;
if (ISZLOADED(*card)) {
if (cyz_is_loaded(card)) {
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@ -3713,7 +3686,7 @@ static int cy_break(struct tty_struct *tty, int break_state)
card = info->card;
spin_lock_irqsave(&card->card_lock, flags);
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
/* Let the transmit ISR take care of this (since it
requires stuffing characters into the output stream).
*/
@ -3782,7 +3755,7 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3810,7 +3783,7 @@ static int get_threshold(struct cyclades_port *info,
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3844,7 +3817,7 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -3867,7 +3840,7 @@ static int get_timeout(struct cyclades_port *info,
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -4121,7 +4094,7 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
card = info->card;
channel = info->line - card->first_line;
if (IS_CYC_Z(*card)) {
if (cy_is_Z(card)) {
if (ch == STOP_CHAR(tty))
cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
else if (ch == START_CHAR(tty))
@ -4154,7 +4127,7 @@ static void cy_throttle(struct tty_struct *tty)
card = info->card;
if (I_IXOFF(tty)) {
if (!IS_CYC_Z(*card))
if (!cy_is_Z(card))
cy_send_xchar(tty, STOP_CHAR(tty));
else
info->throttle = 1;
@ -4162,7 +4135,7 @@ static void cy_throttle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -4219,7 +4192,7 @@ static void cy_unthrottle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
if (!cy_is_Z(card)) {
chip = channel >> 2;
channel &= 0x03;
index = card->bus_index;
@ -4263,7 +4236,7 @@ static void cy_stop(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
if (!IS_CYC_Z(*cinfo)) {
if (!cy_is_Z(cinfo)) {
index = cinfo->bus_index;
chip = channel >> 2;
channel &= 0x03;
@ -4296,7 +4269,7 @@ static void cy_start(struct tty_struct *tty)
cinfo = info->card;
channel = info->line - cinfo->first_line;
index = cinfo->bus_index;
if (!IS_CYC_Z(*cinfo)) {
if (!cy_is_Z(cinfo)) {
chip = channel >> 2;
channel &= 0x03;
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
@ -4347,33 +4320,20 @@ static void cy_hangup(struct tty_struct *tty)
static int __devinit cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
u32 uninitialized_var(mailbox);
unsigned int nports, port;
unsigned int port;
unsigned short chip_number;
int uninitialized_var(index);
spin_lock_init(&cinfo->card_lock);
cinfo->intr_enabled = 0;
if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
mailbox = readl(&((struct RUNTIME_9060 __iomem *)
cinfo->ctl_addr)->mail_box_0);
nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
cinfo->intr_enabled = 0;
cinfo->nports = 0; /* Will be correctly set later, after
Z FW is loaded */
} else {
index = cinfo->bus_index;
nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
}
cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
GFP_KERNEL);
if (cinfo->ports == NULL) {
printk(KERN_ERR "Cyclades: cannot allocate ports\n");
cinfo->nports = 0;
return -ENOMEM;
}
for (port = cinfo->first_line; port < cinfo->first_line + nports;
for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
port++) {
info = &cinfo->ports[port - cinfo->first_line];
tty_port_init(&info->port);
@ -4387,9 +4347,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
init_completion(&info->shutdown_wait);
init_waitqueue_head(&info->delta_msr_wait);
if (IS_CYC_Z(*cinfo)) {
if (cy_is_Z(cinfo)) {
info->type = PORT_STARTECH;
if (mailbox == ZO_V1)
if (cinfo->hw_ver == ZO_V1)
info->xmit_fifo_size = CYZ_FIFO_SIZE;
else
info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
@ -4398,6 +4358,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
cyz_rx_restart, (unsigned long)info);
#endif
} else {
int index = cinfo->bus_index;
info->type = PORT_CIRRUS;
info->xmit_fifo_size = CyMAX_CHAR_FIFO;
info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
@ -4430,7 +4391,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
}
#ifndef CONFIG_CYZ_INTR
if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
mod_timer(&cyz_timerlist, jiffies + 1);
#ifdef CY_PCI_DEBUG
printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
@ -4621,11 +4582,12 @@ static int __init cy_detect_isa(void)
/* set cy_card */
cy_card[j].base_addr = cy_isa_address;
cy_card[j].ctl_addr = NULL;
cy_card[j].ctl_addr.p9050 = NULL;
cy_card[j].irq = (int)cy_isa_irq;
cy_card[j].bus_index = 0;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_isa_nchan / 4;
cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
cy_card[j].nports = cy_isa_nchan;
if (cy_init_card(&cy_card[j])) {
cy_card[j].base_addr = NULL;
free_irq(cy_isa_irq, &cy_card[j]);
@ -4781,7 +4743,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
struct CUSTOM_REG __iomem *cust = base_addr;
struct ZFW_CTRL __iomem *pt_zfwctrl;
void __iomem *tmp;
u32 mailbox, status;
u32 mailbox, status, nchan;
unsigned int i;
int retval;
@ -4793,7 +4755,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
/* Check whether the firmware is already loaded and running. If
positive, skip this board */
if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
u32 cntval = readl(base_addr + 0x190);
udelay(100);
@ -4812,7 +4774,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
mailbox = readl(&ctl_addr->mail_box_0);
if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
/* stops CPU and set window to beginning of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
cy_writel(&cust->cpu_stop, 0);
@ -4828,7 +4790,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
base_addr);
if (retval)
goto err_rel;
if (!Z_FPGA_LOADED(ctl_addr)) {
if (!__cyz_fpga_loaded(ctl_addr)) {
dev_err(&pdev->dev, "fw upload successful, but fw is "
"not loaded\n");
goto err_rel;
@ -4887,7 +4849,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
"system before loading the new FW to the "
"Cyclades-Z.\n");
if (Z_FPGA_LOADED(ctl_addr))
if (__cyz_fpga_loaded(ctl_addr))
plx_init(pdev, irq, ctl_addr);
retval = -EIO;
@ -4902,16 +4864,16 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
base_addr + readl(&fid->zfwctrl_addr));
nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
readl(&pt_zfwctrl->board_ctrl.fw_version),
readl(&pt_zfwctrl->board_ctrl.n_channel));
readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
if (nchan == 0) {
dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
"check the connection between the Z host card and the "
"serial expanders.\n");
if (Z_FPGA_LOADED(ctl_addr))
if (__cyz_fpga_loaded(ctl_addr))
plx_init(pdev, irq, ctl_addr);
dev_info(&pdev->dev, "Null number of ports detected. Board "
@ -4932,9 +4894,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
0x00030800UL);
plx_init(pdev, irq, ctl_addr);
return 0;
return nchan;
err_rel:
release_firmware(fw);
err:
@ -4946,7 +4906,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
{
void __iomem *addr0 = NULL, *addr2 = NULL;
char *card_name = NULL;
u32 mailbox;
u32 uninitialized_var(mailbox);
unsigned int device_id, nchan = 0, card_no, i;
unsigned char plx_ver;
int retval, irq;
@ -5023,11 +4983,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* Disable interrupts on the PLX before resetting it */
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
cy_writew(&ctl_addr->intr_ctrl_stat,
readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
plx_init(pdev, irq, addr0);
mailbox = (u32)readl(&ctl_addr->mail_box_0);
mailbox = readl(&ctl_addr->mail_box_0);
addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
@ -5038,12 +4999,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
if (mailbox == ZE_V1) {
card_name = "Cyclades-Ze";
readl(&ctl_addr->mail_box_0);
nchan = ZE_V1_NPORTS;
} else {
card_name = "Cyclades-8Zo";
#ifdef CY_PCI_DEBUG
if (mailbox == ZO_V1) {
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
@ -5065,15 +5022,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
*/
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
cy_writel(addr2 + ID_ADDRESS, 0L);
retval = cyz_load_fw(pdev, addr2, addr0, irq);
if (retval)
goto err_unmap;
/* This must be a Cyclades-8Zo/PCI. The extendable
version will have a different device_id and will
be allocated its maximum number of ports. */
nchan = 8;
}
retval = cyz_load_fw(pdev, addr2, addr0, irq);
if (retval <= 0)
goto err_unmap;
nchan = retval;
}
if ((cy_next_channel + nchan) > NR_PORTS) {
@ -5103,8 +5057,10 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "could not allocate IRQ\n");
goto err_unmap;
}
cy_card[card_no].num_chips = nchan / 4;
cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
} else {
cy_card[card_no].hw_ver = mailbox;
cy_card[card_no].num_chips = (unsigned int)-1;
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
if (irq != 0 && irq != 255) {
@ -5117,15 +5073,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
}
#endif /* CONFIG_CYZ_INTR */
cy_card[card_no].num_chips = (unsigned int)-1;
}
/* set cy_card */
cy_card[card_no].base_addr = addr2;
cy_card[card_no].ctl_addr = addr0;
cy_card[card_no].ctl_addr.p9050 = addr0;
cy_card[card_no].irq = irq;
cy_card[card_no].bus_index = 1;
cy_card[card_no].first_line = cy_next_channel;
cy_card[card_no].nports = nchan;
retval = cy_init_card(&cy_card[card_no]);
if (retval)
goto err_null;
@ -5138,17 +5094,20 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
switch (plx_ver) {
case PLX_9050:
cy_writeb(addr0 + 0x4c, 0x43);
break;
case PLX_9060:
case PLX_9080:
default: /* Old boards, use PLX_9060 */
plx_init(pdev, irq, addr0);
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
{
struct RUNTIME_9060 __iomem *ctl_addr = addr0;
plx_init(pdev, irq, ctl_addr);
cy_writew(&ctl_addr->intr_ctrl_stat,
readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
break;
}
}
}
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
@ -5179,22 +5138,23 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
unsigned int i;
/* non-Z with old PLX */
if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
PLX_9050)
cy_writeb(cinfo->ctl_addr + 0x4c, 0);
cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
else
#ifndef CONFIG_CYZ_INTR
if (!IS_CYC_Z(*cinfo))
if (!cy_is_Z(cinfo))
#endif
cy_writew(cinfo->ctl_addr + 0x68,
readw(cinfo->ctl_addr + 0x68) & ~0x0900);
cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
~0x0900);
iounmap(cinfo->base_addr);
if (cinfo->ctl_addr)
iounmap(cinfo->ctl_addr);
if (cinfo->ctl_addr.p9050)
iounmap(cinfo->ctl_addr.p9050);
if (cinfo->irq
#ifndef CONFIG_CYZ_INTR
&& !IS_CYC_Z(*cinfo)
&& !cy_is_Z(cinfo)
#endif /* CONFIG_CYZ_INTR */
)
free_irq(cinfo->irq, cinfo);
@ -5240,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
(cur_jifs - info->idle_stats.recv_idle)/
HZ, info->idle_stats.overruns,
/* FIXME: double check locking */
(long)info->port.tty->ldisc.ops->num);
(long)info->port.tty->ldisc->ops->num);
else
seq_printf(m, "%3d %8lu %10lu %8lu "
"%10lu %8lu %9lu %6ld\n",
@ -5386,11 +5346,11 @@ static void __exit cy_cleanup_module(void)
/* clear interrupt */
cy_writeb(card->base_addr + Cy_ClrIntr, 0);
iounmap(card->base_addr);
if (card->ctl_addr)
iounmap(card->ctl_addr);
if (card->ctl_addr.p9050)
iounmap(card->ctl_addr.p9050);
if (card->irq
#ifndef CONFIG_CYZ_INTR
&& !IS_CYC_Z(*card)
&& !cy_is_Z(card)
#endif /* CONFIG_CYZ_INTR */
)
free_irq(card->irq, card);

View File

@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port)
return 0;
}
static void epca_raise_dtr_rts(struct tty_port *port)
static void epca_dtr_rts(struct tty_port *port, int onoff)
{
}
@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = {
static const struct tty_port_operations epca_port_ops = {
.carrier_raised = epca_carrier_raised,
.raise_dtr_rts = epca_raise_dtr_rts,
.dtr_rts = epca_dtr_rts,
};
static int info_open(struct tty_struct *tty, struct file *filp)
@ -1518,7 +1518,7 @@ static void doevent(int crd)
if (event & MODEMCHG_IND) {
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
/* We are now receiving dcd */
if (mstat & ch->dcd)
wake_up_interruptible(&ch->port.open_wait);
@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
* that the driver will wait on carrier detect.
*/
if (ts->c_cflag & CLOCAL)
clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
else
set_bit(ASYNC_CHECK_CD, &ch->port.flags);
set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
mval = ch->m_dtr | ch->m_rts;
} /* End CBAUD not detected */
iflag = termios2digi_i(ch, ts->c_iflag);
@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
tty_wait_until_sent(tty, 0);
} else {
/* ldisc lock already held in ioctl */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
}
unlock_kernel();
/* Fall Thru */
@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work)
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
tty_hangup(tty);
wake_up_interruptible(&ch->port.open_wait);
clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
clear_bit(ASYNCB_NORMAL_ACTIVE,
&ch->port.flags);
}
}
tty_kref_put(tty);

View File

@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
amountToMove = count;
}
// Move the first block
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
&(pCh->Ibuf[stripIndex]), NULL, amountToMove );
// If we needed to wrap, do the second data move
if (count > amountToMove) {
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
pCh->Ibuf, NULL, count - amountToMove );
}
// Bump and wrap the stripIndex all at once by the amount of data read. This

View File

@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
if (tty->pgrp)
kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
if ( tty->ldisc.ops->flush_buffer )
tty->ldisc.ops->flush_buffer(tty);
if ( tty->ldisc->ops->flush_buffer )
tty->ldisc->ops->flush_buffer(tty);
i2InputFlush( tty->driver_data );
}
}

View File

@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port)
/* card->lock MUST NOT be held */
static void isicom_raise_dtr_rts(struct tty_port *port)
static void isicom_dtr_rts(struct tty_port *port, int on)
{
struct isi_port *ip = container_of(port, struct isi_port, port);
struct isi_board *card = ip->card;
@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port)
if (!lock_card(card))
return;
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
InterruptTheCard(base);
ip->status |= (ISI_DTR | ISI_RTS);
if (on) {
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0f04, base);
InterruptTheCard(base);
ip->status |= (ISI_DTR | ISI_RTS);
} else {
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
outw(0x0C04, base);
InterruptTheCard(base);
ip->status &= ~(ISI_DTR | ISI_RTS);
}
unlock_card(card);
}
@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = {
static const struct tty_port_operations isicom_port_ops = {
.carrier_raised = isicom_carrier_raised,
.raise_dtr_rts = isicom_raise_dtr_rts,
.dtr_rts = isicom_dtr_rts,
};
static int __devinit reset_card(struct pci_dev *pdev,

View File

@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port)
return (portp->sigs & TIOCM_CD) ? 1 : 0;
}
static void stli_raise_dtr_rts(struct tty_port *port)
static void stli_dtr_rts(struct tty_port *port, int on)
{
struct stliport *portp = container_of(port, struct stliport, port);
struct stlibrd *brdp = stli_brds[portp->brdnr];
stli_mkasysigs(&portp->asig, 1, 1);
stli_mkasysigs(&portp->asig, on, on);
if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
sizeof(asysigs_t), 0) < 0)
printk(KERN_WARNING "istallion: dtr raise failed.\n");
printk(KERN_WARNING "istallion: dtr set failed.\n");
}
@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = {
static const struct tty_port_operations stli_port_ops = {
.carrier_raised = stli_carrier_raised,
.raise_dtr_rts = stli_raise_dtr_rts,
.dtr_rts = stli_dtr_rts,
};
/*****************************************************************************/

View File

@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
mutex_unlock(&moxa_openlock);
return -ENODEV;
}
ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->port.count++;
tty->driver_data = ch;

View File

@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port)
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
}
static void mxser_raise_dtr_rts(struct tty_port *port)
static void mxser_dtr_rts(struct tty_port *port, int on)
{
struct mxser_port *mp = container_of(port, struct mxser_port, port);
unsigned long flags;
spin_lock_irqsave(&mp->slock, flags);
outb(inb(mp->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
if (on)
outb(inb(mp->ioaddr + UART_MCR) |
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
else
outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
mp->ioaddr + UART_MCR);
spin_unlock_irqrestore(&mp->slock, flags);
}
@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = {
struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.raise_dtr_rts = mxser_raise_dtr_rts,
.dtr_rts = mxser_dtr_rts,
};
/*

View File

@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
#endif
/* Flush any pending characters in the driver and discipline. */
if (tty->ldisc.ops->flush_buffer)
tty->ldisc.ops->flush_buffer(tty);
if (tty->ldisc->ops->flush_buffer)
tty->ldisc->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);

View File

@ -73,24 +73,6 @@
#define ECHO_OP_SET_CANON_COL 0x81
#define ECHO_OP_ERASE_TAB 0x82
static inline unsigned char *alloc_buf(void)
{
gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
return kmalloc(N_TTY_BUF_SIZE, prio);
else
return (unsigned char *)__get_free_page(prio);
}
static inline void free_buf(unsigned char *buf)
{
if (PAGE_SIZE != N_TTY_BUF_SIZE)
kfree(buf);
else
free_page((unsigned long) buf);
}
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
unsigned char __user *ptr)
{
@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty)
{
n_tty_flush_buffer(tty);
if (tty->read_buf) {
free_buf(tty->read_buf);
kfree(tty->read_buf);
tty->read_buf = NULL;
}
if (tty->echo_buf) {
free_buf(tty->echo_buf);
kfree(tty->echo_buf);
tty->echo_buf = NULL;
}
}
@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty)
/* These are ugly. Currently a malloc failure here can panic */
if (!tty->read_buf) {
tty->read_buf = alloc_buf();
tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->read_buf)
return -ENOMEM;
}
if (!tty->echo_buf) {
tty->echo_buf = alloc_buf();
tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!tty->echo_buf)
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
reset_buffer_flags(tty);
tty->column = 0;
n_tty_set_termios(tty, NULL);

View File

@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info);
static void tx_timeout(unsigned long context);
static int carrier_raised(struct tty_port *port);
static void raise_dtr_rts(struct tty_port *port);
static void dtr_rts(struct tty_port *port, int onoff);
#if SYNCLINK_GENERIC_HDLC
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
static const struct tty_port_operations mgslpc_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts
.dtr_rts = dtr_rts
};
static int mgslpc_probe(struct pcmcia_device *link)
@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port)
return 0;
}
static void raise_dtr_rts(struct tty_port *port)
static void dtr_rts(struct tty_port *port, int onoff)
{
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
if (onoff)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}

View File

@ -30,7 +30,6 @@
#include <asm/system.h>
/* These are global because they are accessed in tty_io.c */
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf,
c = to->receive_room;
if (c > count)
c = count;
to->ldisc.ops->receive_buf(to, buf, NULL, c);
to->ldisc->ops->receive_buf(to, buf, NULL, c);
return c;
}
@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
int count;
/* We should get the line discipline lock for "tty->link" */
if (!to || !to->ldisc.ops->chars_in_buffer)
if (!to || !to->ldisc->ops->chars_in_buffer)
return 0;
/* The ldisc must report 0 if no characters available to be read */
count = to->ldisc.ops->chars_in_buffer(to);
count = to->ldisc->ops->chars_in_buffer(to);
if (tty->driver->subtype == PTY_TYPE_SLAVE)
return count;
@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
if (!to)
return;
if (to->ldisc.ops->flush_buffer)
to->ldisc.ops->flush_buffer(to);
if (to->ldisc->ops->flush_buffer)
to->ldisc->ops->flush_buffer(to);
if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags);

View File

@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port)
return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
static void dtr_rts(struct tty_port *port, int on)
{
struct r_port *info = container_of(port, struct r_port, port);
sSetDTR(&info->channel);
sSetRTS(&info->channel);
if (on) {
sSetDTR(&info->channel);
sSetRTS(&info->channel);
} else {
sClrDTR(&info->channel);
sClrRTS(&info->channel);
}
}
/*
@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/*
* Info->count is now 1; so it's safe to sleep now.
*/
if (!test_bit(ASYNC_INITIALIZED, &port->flags)) {
if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
cp = &info->channel;
sSetRxTrigger(cp, TRIG_1);
if (sGetChanStatus(cp) & CD_ACT)
@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
sEnRxFIFO(cp);
sEnTransmit(cp);
set_bit(ASYNC_INITIALIZED, &info->port.flags);
set_bit(ASYNCB_INITIALIZED, &info->port.flags);
/*
* Set up the tty->alt_speed kludge
@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty,
/* Write remaining data into the port's xmit_buf */
while (1) {
/* Hung up ? */
if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
goto end;
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
c = min(c, XMIT_BUF_SIZE - info->xmit_head);
@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = {
static const struct tty_port_operations rocket_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};
/*

View File

@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty)
}
count = sel_buffer_lth - pasted;
count = min(count, tty->receive_room);
tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted,
tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
NULL, count);
pasted += count;
}

View File

@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port)
return (portp->sigs & TIOCM_CD) ? 1 : 0;
}
static void stl_raise_dtr_rts(struct tty_port *port)
static void stl_dtr_rts(struct tty_port *port, int on)
{
struct stlport *portp = container_of(port, struct stlport, port);
/* Takes brd_lock internally */
stl_setsignals(portp, 1, 1);
stl_setsignals(portp, on, on);
}
/*****************************************************************************/
@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = {
static const struct tty_port_operations stl_port_ops = {
.carrier_raised = stl_carrier_raised,
.raise_dtr_rts = stl_raise_dtr_rts,
.dtr_rts = stl_dtr_rts,
};
/*****************************************************************************/

View File

@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port)
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
static void dtr_rts(struct tty_port *port, int on)
{
struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
unsigned long flags;
spin_lock_irqsave(&info->irq_spinlock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
if (on)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
usc_set_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info )
static const struct tty_port_operations mgsl_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};

View File

@ -214,6 +214,7 @@ struct slgt_desc
#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b))
#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b))
#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
#define desc_count(a) (le16_to_cpu((a).count))
#define desc_status(a) (le16_to_cpu((a).status))
#define desc_complete(a) (le16_to_cpu((a).status) & BIT15)
@ -297,6 +298,7 @@ struct slgt_info {
u32 max_frame_size; /* as set by device config */
unsigned int rbuf_fill_level;
unsigned int rx_pio;
unsigned int if_mode;
unsigned int base_clock;
@ -331,6 +333,8 @@ struct slgt_info {
struct slgt_desc *rbufs;
unsigned int rbuf_current;
unsigned int rbuf_index;
unsigned int rbuf_fill_index;
unsigned short rbuf_fill_count;
unsigned int tbuf_count;
struct slgt_desc *tbufs;
@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short status)
info->pending_bh |= BH_STATUS;
}
static void isr_rxdata(struct slgt_info *info)
{
unsigned int count = info->rbuf_fill_count;
unsigned int i = info->rbuf_fill_index;
unsigned short reg;
while (rd_reg16(info, SSR) & IRQ_RXDATA) {
reg = rd_reg16(info, RDR);
DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg));
if (desc_complete(info->rbufs[i])) {
/* all buffers full */
rx_stop(info);
info->rx_restart = 1;
continue;
}
info->rbufs[i].buf[count++] = (unsigned char)reg;
/* async mode saves status byte to buffer for each data byte */
if (info->params.mode == MGSL_MODE_ASYNC)
info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
if (count == info->rbuf_fill_level || (reg & BIT10)) {
/* buffer full or end of frame */
set_desc_count(info->rbufs[i], count);
set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
info->rbuf_fill_count = count = 0;
if (++i == info->rbuf_count)
i = 0;
info->pending_bh |= BH_RECEIVE;
}
}
info->rbuf_fill_index = i;
info->rbuf_fill_count = count;
}
static void isr_serial(struct slgt_info *info)
{
unsigned short status = rd_reg16(info, SSR);
@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info)
if (info->tx_count)
isr_txeom(info, status);
}
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
info->icount.brk++;
/* process break detection if tty control allows */
@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info)
} else {
if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
isr_txeom(info, status);
if (info->rx_pio && (status & IRQ_RXDATA))
isr_rxdata(info);
if (status & IRQ_RXIDLE) {
if (status & RXIDLE)
info->icount.rxidle++;
@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable)
return -EINVAL;
}
info->rbuf_fill_level = rbuf_fill_level;
if (rbuf_fill_level < 128)
info->rx_pio = 1; /* PIO mode */
else
info->rx_pio = 0; /* DMA mode */
rx_stop(info); /* restart receiver to use new fill level */
}
@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port)
return (info->signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
static void dtr_rts(struct tty_port *port, int on)
{
unsigned long flags;
struct slgt_info *info = container_of(port, struct slgt_info, port);
spin_lock_irqsave(&info->lock,flags);
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
if (on)
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info)
static const struct tty_port_operations slgt_port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};
/*
@ -3841,15 +3889,27 @@ static void rx_start(struct slgt_info *info)
rdma_reset(info);
reset_rbufs(info);
/* set 1st descriptor address */
wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
if (info->params.mode != MGSL_MODE_ASYNC) {
/* enable rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT2 + BIT0));
if (info->rx_pio) {
/* rx request when rx FIFO not empty */
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
slgt_irq_on(info, IRQ_RXDATA);
if (info->params.mode == MGSL_MODE_ASYNC) {
/* enable saving of rx status */
wr_reg32(info, RDCSR, BIT6);
}
} else {
/* enable saving of rx status, rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
/* rx request when rx FIFO half full */
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
/* set 1st descriptor address */
wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
if (info->params.mode != MGSL_MODE_ASYNC) {
/* enable rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT2 + BIT0));
} else {
/* enable saving of rx status, rx DMA and DMA interrupt */
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
}
}
slgt_irq_on(info, IRQ_RXOVER);
@ -4467,6 +4527,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
static void reset_rbufs(struct slgt_info *info)
{
free_rbufs(info, 0, info->rbuf_count - 1);
info->rbuf_fill_index = 0;
info->rbuf_fill_count = 0;
}
/*

View File

@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port)
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
}
static void raise_dtr_rts(struct tty_port *port)
static void dtr_rts(struct tty_port *port, int on)
{
SLMP_INFO *info = container_of(port, SLMP_INFO, port);
unsigned long flags;
spin_lock_irqsave(&info->lock,flags);
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
if (on)
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
else
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
set_signals(info);
spin_unlock_irqrestore(&info->lock,flags);
}
@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info)
static const struct tty_port_operations port_ops = {
.carrier_raised = carrier_raised,
.raise_dtr_rts = raise_dtr_rts,
.dtr_rts = dtr_rts,
};
/* Allocate and initialize a device instance structure

View File

@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
if (!buf)
goto err;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
else
buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
atomic_set(&buf->count, 1);
@ -52,10 +49,7 @@ err:
static void tty_audit_buf_free(struct tty_audit_buf *buf)
{
WARN_ON(buf->valid != 0);
if (PAGE_SIZE != N_TTY_BUF_SIZE)
kfree(buf->data);
else
free_page((unsigned long)buf->data);
kfree(buf->data);
kfree(buf);
}

View File

@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
struct tty_driver *p, *res = NULL;
int tty_line = 0;
int len;
char *str;
char *str, *stp;
for (str = name; *str; str++)
if ((*str >= '0' && *str <= '9') || *str == ',')
@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (strncmp(name, p->name, len) != 0)
continue;
if (*str == ',')
str++;
if (*str == '\0')
str = NULL;
stp = str;
if (*stp == ',')
stp++;
if (*stp == '\0')
stp = NULL;
if (tty_line >= 0 && tty_line <= p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
res = tty_driver_kref_get(p);
*line = tty_line;
break;
@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_wakeup);
/**
* tty_ldisc_flush - flush line discipline queue
* @tty: tty
*
* Flush the line discipline queue (if any) for this tty. If there
* is no line discipline active this is a no-op.
*/
void tty_ldisc_flush(struct tty_struct *tty)
{
struct tty_ldisc *ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_ldisc_deref(ld);
}
tty_buffer_flush(tty);
}
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
/**
* tty_reset_termios - reset terminal state
* @tty: tty to reset
*
* Restore a terminal to the driver default state
*/
static void tty_reset_termios(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
*tty->termios = tty->driver->init_termios;
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
mutex_unlock(&tty->termios_mutex);
}
/**
* do_tty_hangup - actual handler for hangup events
* @work: tty device
@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work)
struct file *cons_filp = NULL;
struct file *filp, *f = NULL;
struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n;
unsigned long flags;
int refs = 0;
@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work)
filp->f_op = &hung_up_tty_fops;
}
file_list_unlock();
/*
* FIXME! What are the locking issues here? This may me overdoing
* things... This question is especially important now that we've
* removed the irqlock.
*/
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
/* We may have no line discipline at this point */
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->ops->write_wakeup)
ld->ops->write_wakeup(tty);
if (ld->ops->hangup)
ld->ops->hangup(tty);
}
/*
* FIXME: Once we trust the LDISC code better we can wait here for
* ldisc completion and fix the driver call race
*/
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
/*
* Shutdown the current line discipline, and reset it to
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
tty_reset_termios(tty);
/* Defer ldisc switch */
/* tty_deferred_ldisc_switch(N_TTY);
This should get done automatically when the port closes and
tty_release is called */
tty_ldisc_hangup(tty);
read_lock(&tasklist_lock);
if (tty->session) {
@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work)
read_unlock(&tasklist_lock);
spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->flags = 0;
clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_PUSH, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
set_bit(TTY_HUPPED, &tty->flags);
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
/* Account for the p->signal references we killed */
@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work)
* can't yet guarantee all that.
*/
set_bit(TTY_HUPPED, &tty->flags);
if (ld) {
tty_ldisc_enable(tty);
tty_ldisc_deref(ld);
}
tty_ldisc_enable(tty);
unlock_kernel();
if (f)
fput(f);
@ -2480,6 +2411,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
return tty->ops->tiocmset(tty, file, set, clear);
}
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
tty = tty->link;
return tty;
}
EXPORT_SYMBOL(tty_pair_get_tty);
struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
{
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
return tty;
return tty->link;
}
EXPORT_SYMBOL(tty_pair_get_pty);
/*
* Split this up, as gcc can choke on it otherwise..
*/
@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
real_tty = tty->link;
real_tty = tty_pair_get_tty(tty);
/*
* Factor out some common prep work
@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
return put_user(tty->ldisc.ops->num, (int __user *)p);
return put_user(tty->ldisc->ops->num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
/*
@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);

View File

@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
* @tty: terminal
*
* Indicate that a tty should stop transmitting data down the stack.
* Takes the termios mutex to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*/
void tty_throttle(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->throttle)
tty->ops->throttle(tty);
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_throttle);
@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
* @tty: terminal
*
* Indicate that a tty may continue transmitting data down the stack.
* Takes the termios mutex to protect against parallel throttle/unthrottle
* and also to ensure the driver can consistently reference its own
* termios data at this point when implementing software flow control.
*
* Drivers should however remember that the stack can issue a throttle,
* then change flow control method, then unthrottle.
*/
void tty_unthrottle(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->ops->unthrottle)
tty->ops->unthrottle(tty);
mutex_unlock(&tty->termios_mutex);
}
EXPORT_SYMBOL(tty_unthrottle);
@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
return 0;
}
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
memcpy(kterm, tty->termios, sizeof(struct ktermios));
mutex_unlock(&tty->termios_mutex);
}
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
{
mutex_lock(&tty->termios_mutex);
memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
mutex_unlock(&tty->termios_mutex);
}
static int get_termio(struct tty_struct *tty, struct termio __user *termio)
{
if (kernel_termios_to_user_termio(termio, tty->termios))
struct ktermios kterm;
copy_termios(tty, &kterm);
if (kernel_termios_to_user_termio(termio, &kterm))
return -EFAULT;
return 0;
}
@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
struct tty_struct *real_tty;
void __user *p = (void __user *)arg;
int ret = 0;
struct ktermios kterm;
struct termiox ktermx;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_OLD);
#ifndef TCGETS2
case TCGETS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
#else
case TCGETS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TCGETS2:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
copy_termios(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TCSETSF2:
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termios(real_tty, p, TERMIOS_TERMIO);
#ifndef TCGETS2
case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios(real_tty->termios_locked,
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios(&kterm,
(struct termios __user *) arg))
ret = -EFAULT;
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
mutex_unlock(&real_tty->termios_mutex);
return ret;
return 0;
#else
case TIOCGLCKTRMIOS:
mutex_lock(&real_tty->termios_mutex);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
copy_termios_locked(real_tty, &kterm);
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
ret = -EFAULT;
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSLCKTRMIOS:
if (!capable(CAP_SYS_ADMIN))
ret = -EPERM;
mutex_lock(&real_tty->termios_mutex);
if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
return -EPERM;
copy_termios_locked(real_tty, &kterm);
if (user_termios_to_kernel_termios_1(&kterm,
(struct termios __user *) arg))
ret = -EFAULT;
return -EFAULT;
mutex_lock(&real_tty->termios_mutex);
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
mutex_unlock(&real_tty->termios_mutex);
return ret;
#endif
@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (real_tty->termiox == NULL)
return -EINVAL;
mutex_lock(&real_tty->termios_mutex);
if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
ret = -EFAULT;
memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
mutex_unlock(&real_tty->termios_mutex);
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
ret = -EFAULT;
return ret;
case TCSETX:
return set_termiox(real_tty, p, 0);
@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return set_termiox(real_tty, p, TERMIOS_FLUSH);
#endif
case TIOCGSOFTCAR:
mutex_lock(&real_tty->termios_mutex);
ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
copy_termios(real_tty, &kterm);
ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
(int __user *)arg);
mutex_unlock(&real_tty->termios_mutex);
return ret;
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))

View File

@ -115,19 +115,22 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
/**
* tty_ldisc_try_get - try and reference an ldisc
* @disc: ldisc number
* @ld: tty ldisc structure to complete
*
* Attempt to open and lock a line discipline into place. Return
* the line discipline refcounted and assigned in ld. On an error
* report the error code back
* the line discipline refcounted or an error.
*/
static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
static struct tty_ldisc *tty_ldisc_try_get(int disc)
{
unsigned long flags;
struct tty_ldisc *ld;
struct tty_ldisc_ops *ldops;
int err = -EINVAL;
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
if (ld == NULL)
return ERR_PTR(-ENOMEM);
spin_lock_irqsave(&tty_ldisc_lock, flags);
ld->ops = NULL;
ldops = tty_ldiscs[disc];
@ -140,17 +143,19 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
/* lock it */
ldops->refcount++;
ld->ops = ldops;
ld->refcount = 0;
err = 0;
}
}
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return err;
if (err)
return ERR_PTR(err);
return ld;
}
/**
* tty_ldisc_get - take a reference to an ldisc
* @disc: ldisc number
* @ld: tty line discipline structure to use
*
* Takes a reference to a line discipline. Deals with refcounts and
* module locking counts. Returns NULL if the discipline is not available.
@ -161,52 +166,54 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
* takes tty_ldisc_lock to guard against ldisc races
*/
static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
static struct tty_ldisc *tty_ldisc_get(int disc)
{
int err;
struct tty_ldisc *ld;
if (disc < N_TTY || disc >= NR_LDISCS)
return -EINVAL;
err = tty_ldisc_try_get(disc, ld);
if (err < 0) {
return ERR_PTR(-EINVAL);
ld = tty_ldisc_try_get(disc);
if (IS_ERR(ld)) {
request_module("tty-ldisc-%d", disc);
err = tty_ldisc_try_get(disc, ld);
ld = tty_ldisc_try_get(disc);
}
return err;
return ld;
}
/**
* tty_ldisc_put - drop ldisc reference
* @disc: ldisc number
* @ld: ldisc
*
* Drop a reference to a line discipline. Manage refcounts and
* module usage counts
* module usage counts. Free the ldisc once the recount hits zero.
*
* Locking:
* takes tty_ldisc_lock to guard against ldisc races
*/
static void tty_ldisc_put(struct tty_ldisc_ops *ld)
static void tty_ldisc_put(struct tty_ldisc *ld)
{
unsigned long flags;
int disc = ld->num;
int disc = ld->ops->num;
struct tty_ldisc_ops *ldo;
BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
spin_lock_irqsave(&tty_ldisc_lock, flags);
ld = tty_ldiscs[disc];
BUG_ON(ld->refcount == 0);
ld->refcount--;
module_put(ld->owner);
ldo = tty_ldiscs[disc];
BUG_ON(ldo->refcount == 0);
ldo->refcount--;
module_put(ldo->owner);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
kfree(ld);
}
static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
return (*pos < NR_LDISCS) ? pos : NULL;
}
static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
{
(*pos)++;
return (*pos < NR_LDISCS) ? pos : NULL;
@ -219,12 +226,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
{
int i = *(loff_t *)v;
struct tty_ldisc ld;
if (tty_ldisc_get(i, &ld) < 0)
struct tty_ldisc *ld;
ld = tty_ldisc_try_get(i);
if (IS_ERR(ld))
return 0;
seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
tty_ldisc_put(ld.ops);
seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
tty_ldisc_put(ld);
return 0;
}
@ -263,8 +271,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
{
ld->refcount = 0;
tty->ldisc = *ld;
tty->ldisc = ld;
}
/**
@ -286,7 +293,7 @@ static int tty_ldisc_try(struct tty_struct *tty)
int ret = 0;
spin_lock_irqsave(&tty_ldisc_lock, flags);
ld = &tty->ldisc;
ld = tty->ldisc;
if (test_bit(TTY_LDISC, &tty->flags)) {
ld->refcount++;
ret = 1;
@ -315,10 +322,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
/* wait_event is a macro */
wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
WARN_ON(tty->ldisc.refcount == 0);
return &tty->ldisc;
WARN_ON(tty->ldisc->refcount == 0);
return tty->ldisc;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
/**
@ -335,10 +341,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
{
if (tty_ldisc_try(tty))
return &tty->ldisc;
return tty->ldisc;
return NULL;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
/**
@ -366,7 +371,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
wake_up(&tty_ldisc_wait);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
}
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
/**
@ -388,6 +392,26 @@ void tty_ldisc_enable(struct tty_struct *tty)
wake_up(&tty_ldisc_wait);
}
/**
* tty_ldisc_flush - flush line discipline queue
* @tty: tty
*
* Flush the line discipline queue (if any) for this tty. If there
* is no line discipline active this is a no-op.
*/
void tty_ldisc_flush(struct tty_struct *tty)
{
struct tty_ldisc *ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_ldisc_deref(ld);
}
tty_buffer_flush(tty);
}
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
/**
* tty_set_termios_ldisc - set ldisc field
* @tty: tty structure
@ -407,6 +431,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
mutex_unlock(&tty->termios_mutex);
}
/**
* tty_ldisc_open - open a line discipline
* @tty: tty we are opening the ldisc on
* @ld: discipline to open
*
* A helper opening method. Also a convenient debugging and check
* point.
*/
static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
{
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
if (ld->ops->open)
return ld->ops->open(tty);
return 0;
}
/**
* tty_ldisc_close - close a line discipline
* @tty: tty we are opening the ldisc on
* @ld: discipline to close
*
* A helper close method. Also a convenient debugging and check
* point.
*/
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
{
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
ld->ops->close(tty);
}
/**
* tty_ldisc_restore - helper for tty ldisc change
@ -420,66 +477,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
{
char buf[64];
struct tty_ldisc new_ldisc;
struct tty_ldisc *new_ldisc;
int r;
/* There is an outstanding reference here so this is safe */
tty_ldisc_get(old->ops->num, old);
old = tty_ldisc_get(old->ops->num);
WARN_ON(IS_ERR(old));
tty_ldisc_assign(tty, old);
tty_set_termios_ldisc(tty, old->ops->num);
if (old->ops->open && (old->ops->open(tty) < 0)) {
tty_ldisc_put(old->ops);
if (tty_ldisc_open(tty, old) < 0) {
tty_ldisc_put(old);
/* This driver is always present */
if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
new_ldisc = tty_ldisc_get(N_TTY);
if (IS_ERR(new_ldisc))
panic("n_tty: get");
tty_ldisc_assign(tty, &new_ldisc);
tty_ldisc_assign(tty, new_ldisc);
tty_set_termios_ldisc(tty, N_TTY);
if (new_ldisc.ops->open) {
int r = new_ldisc.ops->open(tty);
if (r < 0)
panic("Couldn't open N_TTY ldisc for "
"%s --- error %d.",
tty_name(tty, buf), r);
}
r = tty_ldisc_open(tty, new_ldisc);
if (r < 0)
panic("Couldn't open N_TTY ldisc for "
"%s --- error %d.",
tty_name(tty, buf), r);
}
}
/**
* tty_ldisc_halt - shut down the line discipline
* @tty: tty device
*
* Shut down the line discipline and work queue for this tty device.
* The TTY_LDISC flag being cleared ensures no further references can
* be obtained while the delayed work queue halt ensures that no more
* data is fed to the ldisc.
*
* In order to wait for any existing references to complete see
* tty_ldisc_wait_idle.
*/
static int tty_ldisc_halt(struct tty_struct *tty)
{
clear_bit(TTY_LDISC, &tty->flags);
return cancel_delayed_work(&tty->buf.work);
}
/**
* tty_ldisc_wait_idle - wait for the ldisc to become idle
* @tty: tty to wait for
*
* Wait for the line discipline to become idle. The discipline must
* have been halted for this to guarantee it remains idle.
*
* tty_ldisc_lock protects the ref counts currently.
*/
static int tty_ldisc_wait_idle(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty_ldisc_lock, flags);
while (tty->ldisc->refcount) {
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
if (wait_event_timeout(tty_ldisc_wait,
tty->ldisc->refcount == 0, 5 * HZ) == 0)
return -EBUSY;
spin_lock_irqsave(&tty_ldisc_lock, flags);
}
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
return 0;
}
/**
* tty_set_ldisc - set line discipline
* @tty: the terminal to set
* @ldisc: the line discipline
*
* Set the discipline of a tty line. Must be called from a process
* context.
* context. The ldisc change logic has to protect itself against any
* overlapping ldisc change (including on the other end of pty pairs),
* the close of one side of a tty/pty pair, and eventually hangup.
*
* Locking: takes tty_ldisc_lock.
* called functions take termios_mutex
* Locking: takes tty_ldisc_lock, termios_mutex
*/
int tty_set_ldisc(struct tty_struct *tty, int ldisc)
{
int retval;
struct tty_ldisc o_ldisc, new_ldisc;
int work;
unsigned long flags;
struct tty_ldisc *o_ldisc, *new_ldisc;
int work, o_work = 0;
struct tty_struct *o_tty;
restart:
/* This is a bit ugly for now but means we can break the 'ldisc
is part of the tty struct' assumption later */
retval = tty_ldisc_get(ldisc, &new_ldisc);
if (retval)
return retval;
new_ldisc = tty_ldisc_get(ldisc);
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
/*
* We need to look at the tty locking here for pty/tty pairs
* when both sides try to change in parallel.
*/
o_tty = tty->link; /* o_tty is the pty side or NULL */
/*
* Check the no-op case
*/
if (tty->ldisc->ops->num == ldisc) {
tty_ldisc_put(new_ldisc);
return 0;
}
/*
* Problem: What do we do if this blocks ?
* We could deadlock here
*/
tty_wait_until_sent(tty, 0);
if (tty->ldisc.ops->num == ldisc) {
tty_ldisc_put(new_ldisc.ops);
return 0;
mutex_lock(&tty->ldisc_mutex);
/*
* We could be midstream of another ldisc change which has
* dropped the lock during processing. If so we need to wait.
*/
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
mutex_unlock(&tty->ldisc_mutex);
wait_event(tty_ldisc_wait,
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
mutex_lock(&tty->ldisc_mutex);
}
set_bit(TTY_LDISC_CHANGING, &tty->flags);
/*
* No more input please, we are switching. The new ldisc
@ -489,8 +616,6 @@ restart:
tty->receive_room = 0;
o_ldisc = tty->ldisc;
o_tty = tty->link;
/*
* Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit
@ -501,108 +626,181 @@ restart:
* with a userspace app continually trying to use the tty in
* parallel to the change and re-referencing the tty.
*/
clear_bit(TTY_LDISC, &tty->flags);
if (o_tty)
clear_bit(TTY_LDISC, &o_tty->flags);
spin_lock_irqsave(&tty_ldisc_lock, flags);
if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
if (tty->ldisc.refcount) {
/* Free the new ldisc we grabbed. Must drop the lock
first. */
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_put(o_ldisc.ops);
/*
* There are several reasons we may be busy, including
* random momentary I/O traffic. We must therefore
* retry. We could distinguish between blocking ops
* and retries if we made tty_ldisc_wait() smarter.
* That is up for discussion.
*/
if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
return -ERESTARTSYS;
goto restart;
}
if (o_tty && o_tty->ldisc.refcount) {
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_put(o_tty->ldisc.ops);
if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
return -ERESTARTSYS;
goto restart;
}
}
/*
* If the TTY_LDISC bit is set, then we are racing against
* another ldisc change
*/
if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
struct tty_ldisc *ld;
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_put(new_ldisc.ops);
ld = tty_ldisc_ref_wait(tty);
tty_ldisc_deref(ld);
goto restart;
}
/*
* This flag is used to avoid two parallel ldisc changes. Once
* open and close are fine grained locked this may work better
* as a mutex shared with the open/close/hup paths
*/
set_bit(TTY_LDISC_CHANGING, &tty->flags);
work = tty_ldisc_halt(tty);
if (o_tty)
set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
o_work = tty_ldisc_halt(o_tty);
/*
* From this point on we know nobody has an ldisc
* usage reference, nor can they obtain one until
* we say so later on.
* Wait for ->hangup_work and ->buf.work handlers to terminate.
* We must drop the mutex here in case a hangup is also in process.
*/
work = cancel_delayed_work(&tty->buf.work);
/*
* Wait for ->hangup_work and ->buf.work handlers to terminate
* MUST NOT hold locks here.
*/
mutex_unlock(&tty->ldisc_mutex);
flush_scheduled_work();
/* Let any existing reference holders finish */
retval = tty_ldisc_wait_idle(tty);
if (retval < 0) {
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
tty_ldisc_put(new_ldisc);
return retval;
}
mutex_lock(&tty->ldisc_mutex);
if (test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
the ldisc data and closed the ldisc down */
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
mutex_unlock(&tty->ldisc_mutex);
tty_ldisc_put(new_ldisc);
return -EIO;
}
/* Shutdown the current discipline. */
if (o_ldisc.ops->close)
(o_ldisc.ops->close)(tty);
tty_ldisc_close(tty, o_ldisc);
/* Now set up the new line discipline. */
tty_ldisc_assign(tty, &new_ldisc);
tty_ldisc_assign(tty, new_ldisc);
tty_set_termios_ldisc(tty, ldisc);
if (new_ldisc.ops->open)
retval = (new_ldisc.ops->open)(tty);
retval = tty_ldisc_open(tty, new_ldisc);
if (retval < 0) {
tty_ldisc_put(new_ldisc.ops);
tty_ldisc_restore(tty, &o_ldisc);
/* Back to the old one or N_TTY if we can't */
tty_ldisc_put(new_ldisc);
tty_ldisc_restore(tty, o_ldisc);
}
/* At this point we hold a reference to the new ldisc and a
a reference to the old ldisc. If we ended up flipping back
to the existing ldisc we have two references to it */
if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
tty->ops->set_ldisc(tty);
tty_ldisc_put(o_ldisc.ops);
tty_ldisc_put(o_ldisc);
/*
* Allow ldisc referencing to occur as soon as the driver
* ldisc callback completes.
* Allow ldisc referencing to occur again
*/
tty_ldisc_enable(tty);
if (o_tty)
tty_ldisc_enable(o_tty);
/* Restart it in case no characters kick it off. Safe if
/* Restart the work queue in case no characters kick it off. Safe if
already running */
if (work)
schedule_delayed_work(&tty->buf.work, 1);
if (o_work)
schedule_delayed_work(&o_tty->buf.work, 1);
mutex_unlock(&tty->ldisc_mutex);
return retval;
}
/**
* tty_reset_termios - reset terminal state
* @tty: tty to reset
*
* Restore a terminal to the driver default state.
*/
static void tty_reset_termios(struct tty_struct *tty)
{
mutex_lock(&tty->termios_mutex);
*tty->termios = tty->driver->init_termios;
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
mutex_unlock(&tty->termios_mutex);
}
/**
* tty_ldisc_reinit - reinitialise the tty ldisc
* @tty: tty to reinit
*
* Switch the tty back to N_TTY line discipline and leave the
* ldisc state closed
*/
static void tty_ldisc_reinit(struct tty_struct *tty)
{
struct tty_ldisc *ld;
tty_ldisc_close(tty, tty->ldisc);
tty_ldisc_put(tty->ldisc);
tty->ldisc = NULL;
/*
* Switch the line discipline back
*/
ld = tty_ldisc_get(N_TTY);
BUG_ON(IS_ERR(ld));
tty_ldisc_assign(tty, ld);
tty_set_termios_ldisc(tty, N_TTY);
}
/**
* tty_ldisc_hangup - hangup ldisc reset
* @tty: tty being hung up
*
* Some tty devices reset their termios when they receive a hangup
* event. In that situation we must also switch back to N_TTY properly
* before we reset the termios data.
*
* Locking: We can take the ldisc mutex as the rest of the code is
* careful to allow for this.
*
* In the pty pair case this occurs in the close() path of the
* tty itself so we must be careful about locking rules.
*/
void tty_ldisc_hangup(struct tty_struct *tty)
{
struct tty_ldisc *ld;
/*
* FIXME! What are the locking issues here? This may me overdoing
* things... This question is especially important now that we've
* removed the irqlock.
*/
ld = tty_ldisc_ref(tty);
if (ld != NULL) {
/* We may have no line discipline at this point */
if (ld->ops->flush_buffer)
ld->ops->flush_buffer(tty);
tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->ops->write_wakeup)
ld->ops->write_wakeup(tty);
if (ld->ops->hangup)
ld->ops->hangup(tty);
tty_ldisc_deref(ld);
}
/*
* FIXME: Once we trust the LDISC code better we can wait here for
* ldisc completion and fix the driver call race
*/
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
/*
* Shutdown the current line discipline, and reset it to
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
/* Avoid racing set_ldisc */
mutex_lock(&tty->ldisc_mutex);
/* Switch back to N_TTY */
tty_ldisc_reinit(tty);
/* At this point we have a closed ldisc and we want to
reopen it. We could defer this to the next open but
it means auditing a lot of other paths so this is a FIXME */
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
tty_ldisc_enable(tty);
mutex_unlock(&tty->ldisc_mutex);
tty_reset_termios(tty);
}
}
/**
* tty_ldisc_setup - open line discipline
@ -610,24 +808,23 @@ restart:
* @o_tty: pair tty for pty/tty pairs
*
* Called during the initial open of a tty/pty pair in order to set up the
* line discplines and bind them to the tty.
* line disciplines and bind them to the tty. This has no locking issues
* as the device isn't yet active.
*/
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
{
struct tty_ldisc *ld = &tty->ldisc;
struct tty_ldisc *ld = tty->ldisc;
int retval;
if (ld->ops->open) {
retval = (ld->ops->open)(tty);
if (retval)
return retval;
}
if (o_tty && o_tty->ldisc.ops->open) {
retval = (o_tty->ldisc.ops->open)(o_tty);
retval = tty_ldisc_open(tty, ld);
if (retval)
return retval;
if (o_tty) {
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
if (retval) {
if (ld->ops->close)
(ld->ops->close)(tty);
tty_ldisc_close(tty, ld);
return retval;
}
tty_ldisc_enable(o_tty);
@ -635,32 +832,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_enable(tty);
return 0;
}
/**
* tty_ldisc_release - release line discipline
* @tty: tty being shut down
* @o_tty: pair tty for pty/tty pairs
*
* Called during the final close of a tty/pty pair in order to shut down the
* line discpline layer.
* Called during the final close of a tty/pty pair in order to shut down
* the line discpline layer. On exit the ldisc assigned is N_TTY and the
* ldisc has not been opened.
*/
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
{
unsigned long flags;
struct tty_ldisc ld;
/*
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
* kill any delayed work. As this is the final close it does not
* race with the set_ldisc code path.
*/
clear_bit(TTY_LDISC, &tty->flags);
cancel_delayed_work(&tty->buf.work);
/*
* Wait for ->hangup_work and ->buf.work handlers to terminate
*/
tty_ldisc_halt(tty);
flush_scheduled_work();
/*
@ -668,38 +858,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
* side waiters as the file is closing so user count on the file
* side is zero.
*/
spin_lock_irqsave(&tty_ldisc_lock, flags);
while (tty->ldisc.refcount) {
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
spin_lock_irqsave(&tty_ldisc_lock, flags);
}
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
tty_ldisc_wait_idle(tty);
/*
* Shutdown the current line discipline, and reset it to N_TTY.
*
* FIXME: this MUST get fixed for the new reflocking
*/
if (tty->ldisc.ops->close)
(tty->ldisc.ops->close)(tty);
tty_ldisc_put(tty->ldisc.ops);
/*
* Switch the line discipline back
*/
WARN_ON(tty_ldisc_get(N_TTY, &ld));
tty_ldisc_assign(tty, &ld);
tty_set_termios_ldisc(tty, N_TTY);
if (o_tty) {
/* FIXME: could o_tty be in setldisc here ? */
clear_bit(TTY_LDISC, &o_tty->flags);
if (o_tty->ldisc.ops->close)
(o_tty->ldisc.ops->close)(o_tty);
tty_ldisc_put(o_tty->ldisc.ops);
WARN_ON(tty_ldisc_get(N_TTY, &ld));
tty_ldisc_assign(o_tty, &ld);
tty_set_termios_ldisc(o_tty, N_TTY);
}
tty_ldisc_reinit(tty);
/* This will need doing differently if we need to lock */
if (o_tty)
tty_ldisc_release(o_tty, NULL);
}
/**
@ -712,10 +883,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
void tty_ldisc_init(struct tty_struct *tty)
{
struct tty_ldisc ld;
if (tty_ldisc_get(N_TTY, &ld) < 0)
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
if (IS_ERR(ld))
panic("n_tty: init_tty");
tty_ldisc_assign(tty, &ld);
tty_ldisc_assign(tty, ld);
}
void tty_ldisc_begin(void)

View File

@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port)
EXPORT_SYMBOL(tty_port_carrier_raised);
/**
* tty_port_raise_dtr_rts - Riase DTR/RTS
* tty_port_raise_dtr_rts - Raise DTR/RTS
* @port: tty port
*
* Wrapper for the DTR/RTS raise logic. For the moment this is used
@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->raise_dtr_rts)
port->ops->raise_dtr_rts(port);
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 1);
}
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
/**
* tty_port_lower_dtr_rts - Lower DTR/RTS
* @port: tty port
*
* Wrapper for the DTR/RTS raise logic. For the moment this is used
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
port->ops->dtr_rts(port, 0);
}
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
/**
* tty_port_block_til_ready - Waiting logic for tty open
* @port: the tty port being opened
@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* - port flags and counts
*
* The passed tty_port must implement the carrier_raised method if it can
* do carrier detect and the raise_dtr_rts method if it supports software
* do carrier detect and the dtr_rts method if it supports software
* management of these lines. Note that the dtr/rts raise is done each
* iteration as a hangup may have previously dropped them while we wait.
*/
@ -182,7 +198,8 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&port->close_wait);
wait_event_interruptible(port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
else
@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port,
before the next open may complete */
retval = 0;
add_wait_queue(&port->open_wait, &wait);
/* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags);
@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port,
if (tty->termios->c_cflag & CBAUD)
tty_port_raise_dtr_rts(port);
set_current_state(TASK_INTERRUPTIBLE);
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
/* Check for a hangup or uninitialised port. Return accordingly */
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
if (port->flags & ASYNC_HUP_NOTIFY)
@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port,
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
finish_wait(&port->open_wait, &wait);
/* Update counts. A parallel hangup will have set count to zero and
we must not mess that up further */
@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
if (port->flags & ASYNC_INITIALIZED &&
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
if (port->drain_delay) {
unsigned int bps = tty_get_baud_rate(tty);
long timeout;
if (bps > 1200)
timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
HZ / 10);
else
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
return 1;
}
EXPORT_SYMBOL(tty_port_close_start);
@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
tty_ldisc_flush(tty);
if (tty->termios->c_cflag & HUPCL)
tty_port_lower_dtr_rts(port);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;

File diff suppressed because it is too large Load Diff

View File

@ -287,6 +287,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
[PORT_AR7] = {
.name = "AR7",
.fifo_size = 16,
.tx_loadsz = 16,
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
};
#if defined (CONFIG_SERIAL_8250_AU1X00)

View File

@ -2776,6 +2776,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_C950,
PCI_VENDOR_ID_OXSEMI, PCI_SUBDEVICE_ID_OXSEMI_C950, 0, 0,
pbn_b0_1_921600 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_115200 },

View File

@ -833,6 +833,7 @@ config SERIAL_IMX
bool "IMX serial port support"
depends on ARM && (ARCH_IMX || ARCH_MXC)
select SERIAL_CORE
select RATIONAL
help
If you have a machine based on a Motorola IMX CPU you
can enable its onboard serial port by enabling this option.
@ -1433,4 +1434,11 @@ config SPORT_BAUD_RATE
default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
config SERIAL_TIMBERDALE
tristate "Support for timberdale UART"
depends on MFD_TIMBERDALE
select SERIAL_CORE
---help---
Add support for UART controller on timberdale.
endmenu

View File

@ -77,3 +77,4 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o
obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o

View File

@ -330,6 +330,11 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#endif
/* Anomaly notes:
* 05000215 - we always clear ETBEI within last UART TX
* interrupt to end a string. It is always set
* when start a new tx.
*/
UART_CLEAR_IER(uart, ETBEI);
return;
}
@ -415,6 +420,7 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1);
SSYNC();
enable_dma(uart->tx_dma_channel);
UART_SET_IER(uart, ETBEI);
@ -473,27 +479,41 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
int x_pos, pos;
unsigned long flags;
spin_lock_irqsave(&uart->port.lock, flags);
dma_disable_irq(uart->rx_dma_channel);
spin_lock_bh(&uart->port.lock);
/* 2D DMA RX buffer ring is used. Because curr_y_count and
* curr_x_count can't be read as an atomic operation,
* curr_y_count should be read before curr_x_count. When
* curr_x_count is read, curr_y_count may already indicate
* next buffer line. But, the position calculated here is
* still indicate the old line. The wrong position data may
* be smaller than current buffer tail, which cause garbages
* are received if it is not prohibit.
*/
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
if (uart->rx_dma_nrows == DMA_RX_YCOUNT)
if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
uart->rx_dma_nrows = 0;
x_pos = DMA_RX_XCOUNT - x_pos;
if (x_pos == DMA_RX_XCOUNT)
x_pos = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
if (pos != uart->rx_dma_buf.tail) {
/* Ignore receiving data if new position is in the same line of
* current buffer tail and small.
*/
if (pos > uart->rx_dma_buf.tail ||
uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart);
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
spin_unlock_irqrestore(&uart->port.lock, flags);
spin_unlock_bh(&uart->port.lock);
dma_enable_irq(uart->rx_dma_channel);
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}
@ -514,6 +534,11 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
disable_dma(uart->tx_dma_channel);
clear_dma_irqstat(uart->tx_dma_channel);
/* Anomaly notes:
* 05000215 - we always clear ETBEI within last UART TX
* interrupt to end a string. It is always set
* when start a new tx.
*/
UART_CLEAR_IER(uart, ETBEI);
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
uart->port.icount.tx += uart->tx_count;
@ -532,11 +557,26 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
unsigned short irqstat;
int x_pos, pos;
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel);
bfin_serial_dma_rx_chars(uart);
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
uart->rx_dma_nrows = DMA_RX_YCOUNT - uart->rx_dma_nrows;
if (uart->rx_dma_nrows == DMA_RX_YCOUNT || x_pos == 0)
uart->rx_dma_nrows = 0;
pos = uart->rx_dma_nrows * DMA_RX_XCOUNT;
if (pos > uart->rx_dma_buf.tail ||
uart->rx_dma_nrows < (uart->rx_dma_buf.tail/DMA_RX_XCOUNT)) {
uart->rx_dma_buf.head = pos;
bfin_serial_dma_rx_chars(uart);
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
spin_unlock(&uart->port.lock);
return IRQ_HANDLED;
@ -789,8 +829,16 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
__func__);
}
if (termios->c_cflag & CSTOPB)
lcr |= STB;
/* Anomaly notes:
* 05000231 - STOP bit is always set to 1 whatever the user is set.
*/
if (termios->c_cflag & CSTOPB) {
if (ANOMALY_05000231)
printk(KERN_WARNING "STOP bits other than 1 is not "
"supported in case of anomaly 05000231.\n");
else
lcr |= STB;
}
if (termios->c_cflag & PARENB)
lcr |= PEN;
if (!(termios->c_cflag & PARODD))
@ -940,6 +988,10 @@ static void bfin_serial_reset_irda(struct uart_port *port)
}
#ifdef CONFIG_CONSOLE_POLL
/* Anomaly notes:
* 05000099 - Because we only use THRE in poll_put and DR in poll_get,
* losing other bits of UART_LSR is not a problem here.
*/
static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
@ -1245,12 +1297,17 @@ static __init void early_serial_write(struct console *con, const char *s,
}
}
/*
* This should have a .setup or .early_setup in it, but then things get called
* without the command line options, and the baud rate gets messed up - so
* don't let the common infrastructure play with things. (see calls to setup
* & earlysetup in ./kernel/printk.c:register_console()
*/
static struct __initdata console bfin_early_serial_console = {
.name = "early_BFuart",
.write = early_serial_write,
.device = uart_console_device,
.flags = CON_PRINTBUFFER,
.setup = bfin_serial_console_setup,
.index = -1,
.data = &bfin_serial_reg,
};

View File

@ -101,15 +101,16 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
{
pr_debug("%s value:%x\n", __func__, value);
/* Place a Start and Stop bit */
__asm__ volatile (
"R2 = b#01111111100;\n\t"
"R3 = b#10000000001;\n\t"
"%0 <<= 2;\n\t"
"%0 = %0 & R2;\n\t"
"%0 = %0 | R3;\n\t"
:"=r"(value)
:"0"(value)
:"R2", "R3");
__asm__ __volatile__ (
"R2 = b#01111111100;"
"R3 = b#10000000001;"
"%0 <<= 2;"
"%0 = %0 & R2;"
"%0 = %0 | R3;"
: "=d"(value)
: "d"(value)
: "ASTAT", "R2", "R3"
);
pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, value);
@ -118,27 +119,30 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
static inline unsigned int rx_one_byte(struct sport_uart_port *up)
{
unsigned int value, extract;
u32 tmp_mask1, tmp_mask2, tmp_shift, tmp;
value = SPORT_GET_RX32(up);
pr_debug("%s value:%x\n", __func__, value);
/* Extract 8 bits data */
__asm__ volatile (
"R5 = 0;\n\t"
"P0 = 8;\n\t"
"R1 = 0x1801(Z);\n\t"
"R3 = 0x0300(Z);\n\t"
"R4 = 0;\n\t"
"LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
"R2 = extract(%1, R1.L)(Z);\n\t"
"R2 <<= R4;\n\t"
"R5 = R5 | R2;\n\t"
"R1 = R1 - R3;\nloop_e:\t"
"R4 += 1;\n\t"
"%0 = R5;\n\t"
:"=r"(extract)
:"r"(value)
:"P0", "R1", "R2","R3","R4", "R5");
__asm__ __volatile__ (
"%[extr] = 0;"
"%[mask1] = 0x1801(Z);"
"%[mask2] = 0x0300(Z);"
"%[shift] = 0;"
"LSETUP(.Lloop_s, .Lloop_e) LC0 = %[lc];"
".Lloop_s:"
"%[tmp] = extract(%[val], %[mask1].L)(Z);"
"%[tmp] <<= %[shift];"
"%[extr] = %[extr] | %[tmp];"
"%[mask1] = %[mask1] - %[mask2];"
".Lloop_e:"
"%[shift] += 1;"
: [val]"=d"(value), [extr]"=d"(extract), [shift]"=d"(tmp_shift), [tmp]"=d"(tmp),
[mask1]"=d"(tmp_mask1), [mask2]"=d"(tmp_mask2)
: "d"(value), [lc]"a"(8)
: "ASTAT", "LB0", "LC0", "LT0"
);
pr_debug(" extract:%x\n", extract);
return extract;
@ -149,7 +153,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
int tclkdiv, tfsdiv, rclkdiv;
/* Set TCR1 and TCR2 */
SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
SPORT_PUT_TCR1(up, (LATFS | ITFS | TFSR | TLSBIT | ITCLK));
SPORT_PUT_TCR2(up, 10);
pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
@ -419,7 +423,7 @@ static void sport_shutdown(struct uart_port *port)
}
static void sport_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old)
struct ktermios *termios, struct ktermios *old)
{
pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
uart_update_timeout(port, CS8 ,port->uartclk);

View File

@ -137,7 +137,12 @@ static LIST_HEAD(icom_adapter_head);
static spinlock_t icom_lock;
#ifdef ICOM_TRACE
static inline void trace(struct icom_port *, char *, unsigned long) {};
static inline void trace(struct icom_port *icom_port, char *trace_pt,
unsigned long trace_data)
{
dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
icom_port->port, trace_pt, trace_data);
}
#else
static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
#endif
@ -408,7 +413,7 @@ static void load_code(struct icom_port *icom_port)
release_firmware(fw);
/* Set Hardware level */
if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2)
if (icom_port->adapter->version == ADAPTER_V2)
writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
/* Start the processor in Adapter */
@ -861,7 +866,7 @@ static irqreturn_t icom_interrupt(int irq, void *dev_id)
/* find icom_port for this interrupt */
icom_adapter = (struct icom_adapter *) dev_id;
if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) {
if (icom_adapter->version == ADAPTER_V2) {
int_reg = icom_adapter->base_addr + 0x8024;
adapter_interrupts = readl(int_reg);
@ -1647,15 +1652,6 @@ static void __exit icom_exit(void)
module_init(icom_init);
module_exit(icom_exit);
#ifdef ICOM_TRACE
static inline void trace(struct icom_port *icom_port, char *trace_pt,
unsigned long trace_data)
{
dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
icom_port->port, trace_pt, trace_data);
}
#endif
MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
MODULE_SUPPORTED_DEVICE

View File

@ -8,6 +8,9 @@
* Author: Sascha Hauer <sascha@saschahauer.de>
* Copyright (C) 2004 Pengutronix
*
* Copyright (C) 2009 emlix GmbH
* Author: Fabian Godehardt (added IrDA support for iMX)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@ -41,6 +44,8 @@
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/rational.h>
#include <asm/io.h>
#include <asm/irq.h>
@ -148,6 +153,7 @@
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
#define USR1_RTSS (1<<14) /* RTS pin status */
@ -211,10 +217,20 @@ struct imx_port {
struct timer_list timer;
unsigned int old_status;
int txirq,rxirq,rtsirq;
int have_rtscts:1;
unsigned int have_rtscts:1;
unsigned int use_irda:1;
unsigned int irda_inv_rx:1;
unsigned int irda_inv_tx:1;
unsigned short trcv_delay; /* transceiver delay */
struct clk *clk;
};
#ifdef CONFIG_IRDA
#define USE_IRDA(sport) ((sport)->use_irda)
#else
#define USE_IRDA(sport) (0)
#endif
/*
* Handle any change of modem status signal since we were last called.
*/
@ -268,6 +284,48 @@ static void imx_stop_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
if (USE_IRDA(sport)) {
/* half duplex - wait for end of transmission */
int n = 256;
while ((--n > 0) &&
!(readl(sport->port.membase + USR2) & USR2_TXDC)) {
udelay(5);
barrier();
}
/*
* irda transceiver - wait a bit more to avoid
* cutoff, hardware dependent
*/
udelay(sport->trcv_delay);
/*
* half duplex - reactivate receive mode,
* flush receive pipe echo crap
*/
if (readl(sport->port.membase + USR2) & USR2_TXDC) {
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN);
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp &= ~(UCR4_TCEN);
writel(temp, sport->port.membase + UCR4);
while (readl(sport->port.membase + URXD0) &
URXD_CHARRDY)
barrier();
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_DREN;
writel(temp, sport->port.membase + UCR4);
}
return;
}
temp = readl(sport->port.membase + UCR1);
writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
}
@ -302,13 +360,15 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
/* send xmit->buf[xmit->tail]
* out the port here */
writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
xmit->tail = (xmit->tail + 1) &
(UART_XMIT_SIZE - 1);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (uart_circ_empty(xmit))
imx_stop_tx(&sport->port);
}
@ -321,9 +381,30 @@ static void imx_start_tx(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
if (USE_IRDA(sport)) {
/* half duplex in IrDA mode; have to disable receive mode */
temp = readl(sport->port.membase + UCR4);
temp &= ~(UCR4_DREN);
writel(temp, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_RRDYEN);
writel(temp, sport->port.membase + UCR1);
}
temp = readl(sport->port.membase + UCR1);
writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
if (USE_IRDA(sport)) {
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_TRDYEN;
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR4);
temp |= UCR4_TCEN;
writel(temp, sport->port.membase + UCR4);
}
if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
imx_transmit_buffer(sport);
}
@ -395,8 +476,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
continue;
}
if (uart_handle_sysrq_char
(&sport->port, (unsigned char)rx))
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
continue;
if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
@ -471,26 +551,26 @@ static unsigned int imx_tx_empty(struct uart_port *port)
*/
static unsigned int imx_get_mctrl(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS;
if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS;
if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
return tmp;
return tmp;
}
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct imx_port *sport = (struct imx_port *)port;
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
if (mctrl & TIOCM_RTS)
if (mctrl & TIOCM_RTS)
temp |= UCR2_CTS;
writel(temp, sport->port.membase + UCR2);
@ -534,12 +614,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
if(!ufcr_rfdiv)
ufcr_rfdiv = 1;
if(ufcr_rfdiv >= 7)
ufcr_rfdiv = 6;
else
ufcr_rfdiv = 6 - ufcr_rfdiv;
val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
val |= UFCR_RFDIV_REG(ufcr_rfdiv);
writel(val, sport->port.membase + UFCR);
@ -558,8 +633,24 @@ static int imx_startup(struct uart_port *port)
* requesting IRQs
*/
temp = readl(sport->port.membase + UCR4);
if (USE_IRDA(sport))
temp |= UCR4_IRSC;
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
if (USE_IRDA(sport)) {
/* reset fifo's and state machines */
int i = 100;
temp = readl(sport->port.membase + UCR2);
temp &= ~UCR2_SRST;
writel(temp, sport->port.membase + UCR2);
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) &&
(--i > 0)) {
udelay(1);
}
}
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
* chips only have one interrupt.
@ -575,12 +666,16 @@ static int imx_startup(struct uart_port *port)
if (retval)
goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint,
(sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval)
goto error_out3;
/* do not use RTS IRQ on IrDA */
if (!USE_IRDA(sport)) {
retval = request_irq(sport->rtsirq, imx_rtsint,
(sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval)
goto error_out3;
}
} else {
retval = request_irq(sport->port.irq, imx_int, 0,
DRIVER_NAME, sport);
@ -597,18 +692,49 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
if (USE_IRDA(sport)) {
temp |= UCR1_IREN;
temp &= ~(UCR1_RTSDEN);
}
writel(temp, sport->port.membase + UCR1);
temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN);
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
/* clear RX-FIFO */
int i = 64;
while ((--i > 0) &&
(readl(sport->port.membase + URXD0) & URXD_CHARRDY)) {
barrier();
}
}
#if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
temp = readl(sport->port.membase + UCR3);
temp |= UCR3_RXDMUXSEL;
writel(temp, sport->port.membase + UCR3);
#endif
if (USE_IRDA(sport)) {
temp = readl(sport->port.membase + UCR4);
if (sport->irda_inv_rx)
temp |= UCR4_INVR;
else
temp &= ~(UCR4_INVR);
writel(temp | UCR4_DREN, sport->port.membase + UCR4);
temp = readl(sport->port.membase + UCR3);
if (sport->irda_inv_tx)
temp |= UCR3_INVT;
else
temp &= ~(UCR3_INVT);
writel(temp, sport->port.membase + UCR3);
}
/*
* Enable modem status interrupts
*/
@ -616,6 +742,16 @@ static int imx_startup(struct uart_port *port)
imx_enable_ms(&sport->port);
spin_unlock_irqrestore(&sport->port.lock,flags);
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
pdata = sport->port.dev->platform_data;
sport->irda_inv_rx = pdata->irda_inv_rx;
sport->irda_inv_tx = pdata->irda_inv_tx;
sport->trcv_delay = pdata->transceiver_delay;
if (pdata->irda_enable)
pdata->irda_enable(1);
}
return 0;
error_out3:
@ -633,6 +769,17 @@ static void imx_shutdown(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned long temp;
temp = readl(sport->port.membase + UCR2);
temp &= ~(UCR2_TXEN);
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
struct imxuart_platform_data *pdata;
pdata = sport->port.dev->platform_data;
if (pdata->irda_enable)
pdata->irda_enable(0);
}
/*
* Stop our timer.
*/
@ -642,7 +789,8 @@ static void imx_shutdown(struct uart_port *port)
* Free the interrupts
*/
if (sport->txirq > 0) {
free_irq(sport->rtsirq, sport);
if (!USE_IRDA(sport))
free_irq(sport->rtsirq, sport);
free_irq(sport->txirq, sport);
free_irq(sport->rxirq, sport);
} else
@ -654,6 +802,9 @@ static void imx_shutdown(struct uart_port *port)
temp = readl(sport->port.membase + UCR1);
temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
if (USE_IRDA(sport))
temp &= ~(UCR1_IREN);
writel(temp, sport->port.membase + UCR1);
}
@ -665,7 +816,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags;
unsigned int ucr2, old_ucr1, old_txrxen, baud, quot;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned int div, num, denom, ufcr;
unsigned int div, ufcr;
unsigned long num, denom;
uint64_t tdiv64;
/*
* If we don't support modem control lines, don't allow
@ -761,38 +914,39 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.membase + UCR2);
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
div = sport->port.uartclk / (baud * 16);
if (div > 7)
div = 7;
if (!div)
if (USE_IRDA(sport)) {
/*
* use maximum available submodule frequency to
* avoid missing short pulses due to low sampling rate
*/
div = 1;
num = baud;
denom = port->uartclk / div / 16;
/* shift num and denom right until they fit into 16 bits */
while (num > 0x10000 || denom > 0x10000) {
num >>= 1;
denom >>= 1;
} else {
div = sport->port.uartclk / (baud * 16);
if (div > 7)
div = 7;
if (!div)
div = 1;
}
if (num > 0)
num -= 1;
if (denom > 0)
denom -= 1;
rational_best_approximation(16 * div * baud, sport->port.uartclk,
1 << 16, 1 << 16, &num, &denom);
tdiv64 = sport->port.uartclk;
tdiv64 *= num;
do_div(tdiv64, denom * 16 * div);
tty_encode_baud_rate(sport->port.info->port.tty,
(speed_t)tdiv64, (speed_t)tdiv64);
num -= 1;
denom -= 1;
ufcr = readl(sport->port.membase + UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div);
writel(ufcr, sport->port.membase + UFCR);
writel(num, sport->port.membase + UBIR);
writel(denom, sport->port.membase + UBMR);
if (div == 7)
div = 6; /* 6 in RFDIV means divide by 7 */
else
div = 6 - div;
ufcr = readl(sport->port.membase + UFCR);
ufcr = (ufcr & (~UFCR_RFDIV)) |
(div << 7);
writel(ufcr, sport->port.membase + UFCR);
#ifdef ONEMS
writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
#endif
@ -1072,22 +1226,22 @@ static struct uart_driver imx_reg = {
static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
{
struct imx_port *sport = platform_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(dev);
if (sport)
uart_suspend_port(&imx_reg, &sport->port);
if (sport)
uart_suspend_port(&imx_reg, &sport->port);
return 0;
return 0;
}
static int serial_imx_resume(struct platform_device *dev)
{
struct imx_port *sport = platform_get_drvdata(dev);
struct imx_port *sport = platform_get_drvdata(dev);
if (sport)
uart_resume_port(&imx_reg, &sport->port);
if (sport)
uart_resume_port(&imx_reg, &sport->port);
return 0;
return 0;
}
static int serial_imx_probe(struct platform_device *pdev)
@ -1143,19 +1297,29 @@ static int serial_imx_probe(struct platform_device *pdev)
imx_ports[pdev->id] = sport;
pdata = pdev->dev.platform_data;
if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
sport->have_rtscts = 1;
#ifdef CONFIG_IRDA
if (pdata && (pdata->flags & IMXUART_IRDA))
sport->use_irda = 1;
#endif
if (pdata->init) {
ret = pdata->init(pdev);
if (ret)
goto clkput;
}
uart_add_one_port(&imx_reg, &sport->port);
ret = uart_add_one_port(&imx_reg, &sport->port);
if (ret)
goto deinit;
platform_set_drvdata(pdev, &sport->port);
return 0;
deinit:
if (pdata->exit)
pdata->exit(pdev);
clkput:
clk_put(sport->clk);
clk_disable(sport->clk);
@ -1193,13 +1357,13 @@ static int serial_imx_remove(struct platform_device *pdev)
}
static struct platform_driver serial_imx_driver = {
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.probe = serial_imx_probe,
.remove = serial_imx_remove,
.suspend = serial_imx_suspend,
.resume = serial_imx_resume,
.driver = {
.name = "imx-uart",
.name = "imx-uart",
.owner = THIS_MODULE,
},
};

View File

@ -61,6 +61,7 @@ enum {
if ((DBG_##nlevel & jsm_debug)) \
dev_printk(KERN_##klevel, pdev->dev, fmt, ## args)
#define MAXLINES 256
#define MAXPORTS 8
#define MAX_STOPS_SENT 5

View File

@ -33,6 +33,8 @@
#include "jsm.h"
static DECLARE_BITMAP(linemap, MAXLINES);
static void jsm_carrier(struct jsm_channel *ch);
static inline int jsm_get_mstat(struct jsm_channel *ch)
@ -433,6 +435,7 @@ int __devinit jsm_tty_init(struct jsm_board *brd)
int __devinit jsm_uart_port_init(struct jsm_board *brd)
{
int i;
unsigned int line;
struct jsm_channel *ch;
if (!brd)
@ -459,9 +462,15 @@ int __devinit jsm_uart_port_init(struct jsm_board *brd)
brd->channels[i]->uart_port.membase = brd->re_map_membase;
brd->channels[i]->uart_port.fifosize = 16;
brd->channels[i]->uart_port.ops = &jsm_ops;
brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2;
line = find_first_zero_bit(linemap, MAXLINES);
if (line >= MAXLINES) {
printk(KERN_INFO "jsm: linemap is full, added device failed\n");
continue;
} else
set_bit((int)line, linemap);
brd->channels[i]->uart_port.line = line;
if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port))
printk(KERN_INFO "Added device failed\n");
printk(KERN_INFO "jsm: add device failed\n");
else
printk(KERN_INFO "Added device \n");
}
@ -494,6 +503,7 @@ int jsm_remove_uart_port(struct jsm_board *brd)
ch = brd->channels[i];
clear_bit((int)(ch->uart_port.line), linemap);
uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port);
}

526
drivers/serial/timbuart.c Normal file
View File

@ -0,0 +1,526 @@
/*
* timbuart.c timberdale FPGA UART driver
* Copyright (c) 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Timberdale FPGA UART
*/
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include "timbuart.h"
struct timbuart_port {
struct uart_port port;
struct tasklet_struct tasklet;
int usedma;
u8 last_ier;
struct platform_device *dev;
};
static int baudrates[] = {9600, 19200, 38400, 57600, 115200, 230400, 460800,
921600, 1843200, 3250000};
static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier);
static irqreturn_t timbuart_handleinterrupt(int irq, void *devid);
static void timbuart_stop_rx(struct uart_port *port)
{
/* spin lock held by upper layer, disable all RX interrupts */
u8 ier = ioread8(port->membase + TIMBUART_IER) & ~RXFLAGS;
iowrite8(ier, port->membase + TIMBUART_IER);
}
static void timbuart_stop_tx(struct uart_port *port)
{
/* spinlock held by upper layer, disable TX interrupt */
u8 ier = ioread8(port->membase + TIMBUART_IER) & ~TXBAE;
iowrite8(ier, port->membase + TIMBUART_IER);
}
static void timbuart_start_tx(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
/* do not transfer anything here -> fire off the tasklet */
tasklet_schedule(&uart->tasklet);
}
static void timbuart_flush_buffer(struct uart_port *port)
{
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) | TIMBUART_CTRL_FLSHTX;
iowrite8(ctl, port->membase + TIMBUART_CTRL);
iowrite8(TXBF, port->membase + TIMBUART_ISR);
}
static void timbuart_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->info->port.tty;
while (ioread8(port->membase + TIMBUART_ISR) & RXDP) {
u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
port->icount.rx++;
tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
spin_unlock(&port->lock);
tty_flip_buffer_push(port->info->port.tty);
spin_lock(&port->lock);
dev_dbg(port->dev, "%s - total read %d bytes\n",
__func__, port->icount.rx);
}
static void timbuart_tx_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
while (!(ioread8(port->membase + TIMBUART_ISR) & TXBF) &&
!uart_circ_empty(xmit)) {
iowrite8(xmit->buf[xmit->tail],
port->membase + TIMBUART_TXFIFO);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
dev_dbg(port->dev,
"%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
__func__,
port->icount.tx,
ioread8(port->membase + TIMBUART_CTRL),
port->mctrl & TIOCM_RTS,
ioread8(port->membase + TIMBUART_BAUDRATE));
}
static void timbuart_handle_tx_port(struct uart_port *port, u8 isr, u8 *ier)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
struct circ_buf *xmit = &port->info->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
return;
if (port->x_char)
return;
if (isr & TXFLAGS) {
timbuart_tx_chars(port);
/* clear all TX interrupts */
iowrite8(TXFLAGS, port->membase + TIMBUART_ISR);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
} else
/* Re-enable any tx interrupt */
*ier |= uart->last_ier & TXFLAGS;
/* enable interrupts if there are chars in the transmit buffer,
* Or if we delivered some bytes and want the almost empty interrupt
* we wake up the upper layer later when we got the interrupt
* to give it some time to go out...
*/
if (!uart_circ_empty(xmit))
*ier |= TXBAE;
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
void timbuart_handle_rx_port(struct uart_port *port, u8 isr, u8 *ier)
{
if (isr & RXFLAGS) {
/* Some RX status is set */
if (isr & RXBF) {
u8 ctl = ioread8(port->membase + TIMBUART_CTRL) |
TIMBUART_CTRL_FLSHRX;
iowrite8(ctl, port->membase + TIMBUART_CTRL);
port->icount.overrun++;
} else if (isr & (RXDP))
timbuart_rx_chars(port);
/* ack all RX interrupts */
iowrite8(RXFLAGS, port->membase + TIMBUART_ISR);
}
/* always have the RX interrupts enabled */
*ier |= RXBAF | RXBF | RXTT;
dev_dbg(port->dev, "%s - leaving\n", __func__);
}
void timbuart_tasklet(unsigned long arg)
{
struct timbuart_port *uart = (struct timbuart_port *)arg;
u8 isr, ier = 0;
spin_lock(&uart->port.lock);
isr = ioread8(uart->port.membase + TIMBUART_ISR);
dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
if (!uart->usedma)
timbuart_handle_tx_port(&uart->port, isr, &ier);
timbuart_mctrl_check(&uart->port, isr, &ier);
if (!uart->usedma)
timbuart_handle_rx_port(&uart->port, isr, &ier);
iowrite8(ier, uart->port.membase + TIMBUART_IER);
spin_unlock(&uart->port.lock);
dev_dbg(uart->port.dev, "%s leaving\n", __func__);
}
static unsigned int timbuart_tx_empty(struct uart_port *port)
{
u8 isr = ioread8(port->membase + TIMBUART_ISR);
return (isr & TXBAE) ? TIOCSER_TEMT : 0;
}
static unsigned int timbuart_get_mctrl(struct uart_port *port)
{
u8 cts = ioread8(port->membase + TIMBUART_CTRL);
dev_dbg(port->dev, "%s - cts %x\n", __func__, cts);
if (cts & TIMBUART_CTRL_CTS)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
else
return TIOCM_DSR | TIOCM_CAR;
}
static void timbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
dev_dbg(port->dev, "%s - %x\n", __func__, mctrl);
if (mctrl & TIOCM_RTS)
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
else
iowrite8(TIMBUART_CTRL_RTS, port->membase + TIMBUART_CTRL);
}
static void timbuart_mctrl_check(struct uart_port *port, u8 isr, u8 *ier)
{
unsigned int cts;
if (isr & CTS_DELTA) {
/* ack */
iowrite8(CTS_DELTA, port->membase + TIMBUART_ISR);
cts = timbuart_get_mctrl(port);
uart_handle_cts_change(port, cts & TIOCM_CTS);
wake_up_interruptible(&port->info->delta_msr_wait);
}
*ier |= CTS_DELTA;
}
static void timbuart_enable_ms(struct uart_port *port)
{
/* N/A */
}
static void timbuart_break_ctl(struct uart_port *port, int ctl)
{
/* N/A */
}
static int timbuart_startup(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
dev_dbg(port->dev, "%s\n", __func__);
iowrite8(TIMBUART_CTRL_FLSHRX, port->membase + TIMBUART_CTRL);
iowrite8(0xff, port->membase + TIMBUART_ISR);
/* Enable all but TX interrupts */
iowrite8(RXBAF | RXBF | RXTT | CTS_DELTA,
port->membase + TIMBUART_IER);
return request_irq(port->irq, timbuart_handleinterrupt, IRQF_SHARED,
"timb-uart", uart);
}
static void timbuart_shutdown(struct uart_port *port)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
dev_dbg(port->dev, "%s\n", __func__);
free_irq(port->irq, uart);
iowrite8(0, port->membase + TIMBUART_IER);
}
static int get_bindex(int baud)
{
int i;
for (i = 0; i < ARRAY_SIZE(baudrates); i++)
if (baud <= baudrates[i])
return i;
return -1;
}
static void timbuart_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud;
short bindex;
unsigned long flags;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
bindex = get_bindex(baud);
dev_dbg(port->dev, "%s - bindex %d\n", __func__, bindex);
if (bindex < 0)
bindex = 0;
baud = baudrates[bindex];
/* The serial layer calls into this once with old = NULL when setting
up initially */
if (old)
tty_termios_copy_hw(termios, old);
tty_termios_encode_baud_rate(termios, baud, baud);
spin_lock_irqsave(&port->lock, flags);
iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *timbuart_type(struct uart_port *port)
{
return port->type == PORT_UNKNOWN ? "timbuart" : NULL;
}
/* We do not request/release mappings of the registers here,
* currently it's done in the proble function.
*/
static void timbuart_release_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
int size =
resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (port->flags & UPF_IOREMAP) {
iounmap(port->membase);
port->membase = NULL;
}
release_mem_region(port->mapbase, size);
}
static int timbuart_request_port(struct uart_port *port)
{
struct platform_device *pdev = to_platform_device(port->dev);
int size =
resource_size(platform_get_resource(pdev, IORESOURCE_MEM, 0));
if (!request_mem_region(port->mapbase, size, "timb-uart"))
return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (port->membase == NULL) {
release_mem_region(port->mapbase, size);
return -ENOMEM;
}
}
return 0;
}
static irqreturn_t timbuart_handleinterrupt(int irq, void *devid)
{
struct timbuart_port *uart = (struct timbuart_port *)devid;
if (ioread8(uart->port.membase + TIMBUART_IPR)) {
uart->last_ier = ioread8(uart->port.membase + TIMBUART_IER);
/* disable interrupts, the tasklet enables them again */
iowrite8(0, uart->port.membase + TIMBUART_IER);
/* fire off bottom half */
tasklet_schedule(&uart->tasklet);
return IRQ_HANDLED;
} else
return IRQ_NONE;
}
/*
* Configure/autoconfigure the port.
*/
static void timbuart_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
port->type = PORT_TIMBUART;
timbuart_request_port(port);
}
}
static int timbuart_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
/* we don't want the core code to modify any port params */
return -EINVAL;
}
static struct uart_ops timbuart_ops = {
.tx_empty = timbuart_tx_empty,
.set_mctrl = timbuart_set_mctrl,
.get_mctrl = timbuart_get_mctrl,
.stop_tx = timbuart_stop_tx,
.start_tx = timbuart_start_tx,
.flush_buffer = timbuart_flush_buffer,
.stop_rx = timbuart_stop_rx,
.enable_ms = timbuart_enable_ms,
.break_ctl = timbuart_break_ctl,
.startup = timbuart_startup,
.shutdown = timbuart_shutdown,
.set_termios = timbuart_set_termios,
.type = timbuart_type,
.release_port = timbuart_release_port,
.request_port = timbuart_request_port,
.config_port = timbuart_config_port,
.verify_port = timbuart_verify_port
};
static struct uart_driver timbuart_driver = {
.owner = THIS_MODULE,
.driver_name = "timberdale_uart",
.dev_name = "ttyTU",
.major = TIMBUART_MAJOR,
.minor = TIMBUART_MINOR,
.nr = 1
};
static int timbuart_probe(struct platform_device *dev)
{
int err;
struct timbuart_port *uart;
struct resource *iomem;
dev_dbg(&dev->dev, "%s\n", __func__);
uart = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart) {
err = -EINVAL;
goto err_mem;
}
uart->usedma = 0;
uart->port.uartclk = 3250000 * 16;
uart->port.fifosize = TIMBUART_FIFO_SIZE;
uart->port.regshift = 2;
uart->port.iotype = UPIO_MEM;
uart->port.ops = &timbuart_ops;
uart->port.irq = 0;
uart->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP;
uart->port.line = 0;
uart->port.dev = &dev->dev;
iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!iomem) {
err = -ENOMEM;
goto err_register;
}
uart->port.mapbase = iomem->start;
uart->port.membase = NULL;
uart->port.irq = platform_get_irq(dev, 0);
if (uart->port.irq < 0) {
err = -EINVAL;
goto err_register;
}
tasklet_init(&uart->tasklet, timbuart_tasklet, (unsigned long)uart);
err = uart_register_driver(&timbuart_driver);
if (err)
goto err_register;
err = uart_add_one_port(&timbuart_driver, &uart->port);
if (err)
goto err_add_port;
platform_set_drvdata(dev, uart);
return 0;
err_add_port:
uart_unregister_driver(&timbuart_driver);
err_register:
kfree(uart);
err_mem:
printk(KERN_ERR "timberdale: Failed to register Timberdale UART: %d\n",
err);
return err;
}
static int timbuart_remove(struct platform_device *dev)
{
struct timbuart_port *uart = platform_get_drvdata(dev);
tasklet_kill(&uart->tasklet);
uart_remove_one_port(&timbuart_driver, &uart->port);
uart_unregister_driver(&timbuart_driver);
kfree(uart);
return 0;
}
static struct platform_driver timbuart_platform_driver = {
.driver = {
.name = "timb-uart",
.owner = THIS_MODULE,
},
.probe = timbuart_probe,
.remove = timbuart_remove,
};
/*--------------------------------------------------------------------------*/
static int __init timbuart_init(void)
{
return platform_driver_register(&timbuart_platform_driver);
}
static void __exit timbuart_exit(void)
{
platform_driver_unregister(&timbuart_platform_driver);
}
module_init(timbuart_init);
module_exit(timbuart_exit);
MODULE_DESCRIPTION("Timberdale UART driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:timb-uart");

58
drivers/serial/timbuart.h Normal file
View File

@ -0,0 +1,58 @@
/*
* timbuart.c timberdale FPGA GPIO driver
* Copyright (c) 2009 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Timberdale FPGA UART
*/
#ifndef _TIMBUART_H
#define _TIMBUART_H
#define TIMBUART_FIFO_SIZE 2048
#define TIMBUART_RXFIFO 0x08
#define TIMBUART_TXFIFO 0x0c
#define TIMBUART_IER 0x10
#define TIMBUART_IPR 0x14
#define TIMBUART_ISR 0x18
#define TIMBUART_CTRL 0x1c
#define TIMBUART_BAUDRATE 0x20
#define TIMBUART_CTRL_RTS 0x01
#define TIMBUART_CTRL_CTS 0x02
#define TIMBUART_CTRL_FLSHTX 0x40
#define TIMBUART_CTRL_FLSHRX 0x80
#define TXBF 0x01
#define TXBAE 0x02
#define CTS_DELTA 0x04
#define RXDP 0x08
#define RXBAF 0x10
#define RXBF 0x20
#define RXTT 0x40
#define RXBNAE 0x80
#define TXBE 0x100
#define RXFLAGS (RXDP | RXBAF | RXBF | RXTT | RXBNAE)
#define TXFLAGS (TXBF | TXBAE)
#define TIMBUART_MAJOR 204
#define TIMBUART_MINOR 192
#endif /* _TIMBUART_H */

View File

@ -16,7 +16,8 @@
* v0.9 - thorough cleaning, URBification, almost a rewrite
* v0.10 - some more cleanups
* v0.11 - fixed flow control, read error doesn't stop reads
* v0.12 - added TIOCM ioctls, added break handling, made struct acm kmalloced
* v0.12 - added TIOCM ioctls, added break handling, made struct acm
* kmalloced
* v0.13 - added termios, added hangup
* v0.14 - sized down struct acm
* v0.15 - fixed flow control again - characters could be lost
@ -62,7 +63,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
@ -87,7 +88,10 @@ static struct acm *acm_table[ACM_TTY_MINORS];
static DEFINE_MUTEX(open_mutex);
#define ACM_READY(acm) (acm && acm->dev && acm->used)
#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
static const struct tty_port_operations acm_port_ops = {
};
#ifdef VERBOSE_DEBUG
#define verbose 1
@ -99,13 +103,15 @@ static DEFINE_MUTEX(open_mutex);
* Functions for ACM control messages.
*/
static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int len)
static int acm_ctrl_msg(struct acm *acm, int request, int value,
void *buf, int len)
{
int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),
request, USB_RT_ACM, value,
acm->control->altsetting[0].desc.bInterfaceNumber,
buf, len, 5000);
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d", request, value, len, retval);
dbg("acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d",
request, value, len, retval);
return retval < 0 ? retval : 0;
}
@ -150,9 +156,8 @@ static int acm_wb_is_avail(struct acm *acm)
n = ACM_NW;
spin_lock_irqsave(&acm->write_lock, flags);
for (i = 0; i < ACM_NW; i++) {
for (i = 0; i < ACM_NW; i++)
n -= acm->wb[i].use;
}
spin_unlock_irqrestore(&acm->write_lock, flags);
return n;
}
@ -183,7 +188,8 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)
wb->urb->transfer_buffer_length = wb->len;
wb->urb->dev = acm->dev;
if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
if (rc < 0) {
dbg("usb_submit_urb(write bulk) failed: %d", rc);
acm_write_done(acm, wb);
}
@ -262,6 +268,7 @@ static void acm_ctrl_irq(struct urb *urb)
{
struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer;
struct tty_struct *tty;
unsigned char *data;
int newctrl;
int retval;
@ -287,40 +294,45 @@ static void acm_ctrl_irq(struct urb *urb)
data = (unsigned char *)(dr + 1);
switch (dr->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
dbg("%s network", dr->wValue ?
"connected to" : "disconnected from");
break;
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
case USB_CDC_NOTIFY_SERIAL_STATE:
tty = tty_port_tty_get(&acm->port);
newctrl = get_unaligned_le16(data);
dbg("%s network", dr->wValue ? "connected to" : "disconnected from");
break;
case USB_CDC_NOTIFY_SERIAL_STATE:
newctrl = get_unaligned_le16(data);
if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
if (tty) {
if (!acm->clocal &&
(acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
dbg("calling hangup");
tty_hangup(acm->tty);
tty_hangup(tty);
}
tty_kref_put(tty);
}
acm->ctrlin = newctrl;
dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
acm->ctrlin = newctrl;
dbg("input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c",
acm->ctrlin & ACM_CTRL_DCD ? '+' : '-',
acm->ctrlin & ACM_CTRL_DSR ? '+' : '-',
acm->ctrlin & ACM_CTRL_BRK ? '+' : '-',
acm->ctrlin & ACM_CTRL_RI ? '+' : '-',
acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
break;
default:
dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
dr->bNotificationType, dr->wIndex,
dr->wLength, data[0], data[1]);
break;
default:
dbg("unknown notification %d received: index %d len %d data0 %d data1 %d",
dr->bNotificationType, dr->wIndex,
dr->wLength, data[0], data[1]);
break;
}
exit:
usb_mark_last_busy(acm->dev);
retval = usb_submit_urb (urb, GFP_ATOMIC);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with "
"result %d", __func__, retval);
@ -371,15 +383,14 @@ static void acm_rx_tasklet(unsigned long _acm)
{
struct acm *acm = (void *)_acm;
struct acm_rb *buf;
struct tty_struct *tty = acm->tty;
struct tty_struct *tty;
struct acm_ru *rcv;
unsigned long flags;
unsigned char throttled;
dbg("Entering acm_rx_tasklet");
if (!ACM_READY(acm))
{
if (!ACM_READY(acm)) {
dbg("acm_rx_tasklet: ACM not ready");
return;
}
@ -387,12 +398,13 @@ static void acm_rx_tasklet(unsigned long _acm)
spin_lock_irqsave(&acm->throttle_lock, flags);
throttled = acm->throttle;
spin_unlock_irqrestore(&acm->throttle_lock, flags);
if (throttled)
{
if (throttled) {
dbg("acm_rx_tasklet: throttled");
return;
}
tty = tty_port_tty_get(&acm->port);
next_buffer:
spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->filled_read_bufs)) {
@ -406,20 +418,22 @@ next_buffer:
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
tty_buffer_request_room(tty, buf->size);
spin_lock_irqsave(&acm->throttle_lock, flags);
throttled = acm->throttle;
spin_unlock_irqrestore(&acm->throttle_lock, flags);
if (!throttled)
tty_insert_flip_string(tty, buf->base, buf->size);
tty_flip_buffer_push(tty);
if (throttled) {
dbg("Throttling noticed");
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->filled_read_bufs);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
if (tty) {
spin_lock_irqsave(&acm->throttle_lock, flags);
throttled = acm->throttle;
spin_unlock_irqrestore(&acm->throttle_lock, flags);
if (!throttled) {
tty_buffer_request_room(tty, buf->size);
tty_insert_flip_string(tty, buf->base, buf->size);
tty_flip_buffer_push(tty);
} else {
tty_kref_put(tty);
dbg("Throttling noticed");
spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->filled_read_bufs);
spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
}
spin_lock_irqsave(&acm->read_lock, flags);
@ -428,6 +442,8 @@ next_buffer:
goto next_buffer;
urbs:
tty_kref_put(tty);
while (!list_empty(&acm->spare_read_bufs)) {
spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->spare_read_urbs)) {
@ -454,10 +470,11 @@ urbs:
rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* This shouldn't kill the driver as unsuccessful URBs are returned to the
free-urbs-pool and resubmited ASAP */
/* This shouldn't kill the driver as unsuccessful URBs are
returned to the free-urbs-pool and resubmited ASAP */
spin_lock_irqsave(&acm->read_lock, flags);
if (acm->susp_count || usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
if (acm->susp_count ||
usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
list_add(&buf->list, &acm->spare_read_bufs);
list_add(&rcv->list, &acm->spare_read_urbs);
acm->processing = 0;
@ -499,11 +516,14 @@ static void acm_write_bulk(struct urb *urb)
static void acm_softint(struct work_struct *work)
{
struct acm *acm = container_of(work, struct acm, work);
struct tty_struct *tty;
dev_vdbg(&acm->data->dev, "tx work\n");
if (!ACM_READY(acm))
return;
tty_wakeup(acm->tty);
tty = tty_port_tty_get(&acm->port);
tty_wakeup(tty);
tty_kref_put(tty);
}
static void acm_waker(struct work_struct *waker)
@ -543,8 +563,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
rv = 0;
set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
tty->driver_data = acm;
acm->tty = tty;
tty_port_tty_set(&acm->port, tty);
if (usb_autopm_get_interface(acm->control) < 0)
goto early_bail;
@ -552,11 +573,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->control->needs_remote_wakeup = 1;
mutex_lock(&acm->mutex);
if (acm->used++) {
if (acm->port.count++) {
usb_autopm_put_interface(acm->control);
goto done;
}
}
acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
@ -567,22 +587,22 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
(acm->ctrl_caps & USB_CDC_CAP_LINE))
goto full_bailout;
usb_autopm_put_interface(acm->control);
INIT_LIST_HEAD(&acm->spare_read_urbs);
INIT_LIST_HEAD(&acm->spare_read_bufs);
INIT_LIST_HEAD(&acm->filled_read_bufs);
for (i = 0; i < acm->rx_buflimit; i++) {
for (i = 0; i < acm->rx_buflimit; i++)
list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
}
for (i = 0; i < acm->rx_buflimit; i++) {
for (i = 0; i < acm->rx_buflimit; i++)
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
}
acm->throttle = 0;
tasklet_schedule(&acm->urb_task);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
done:
mutex_unlock(&acm->mutex);
err_out:
@ -593,16 +613,17 @@ full_bailout:
usb_kill_urb(acm->ctrlurb);
bail_out:
usb_autopm_put_interface(acm->control);
acm->used--;
acm->port.count--;
mutex_unlock(&acm->mutex);
early_bail:
mutex_unlock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
return -EIO;
}
static void acm_tty_unregister(struct acm *acm)
{
int i,nr;
int i, nr;
nr = acm->rx_buflimit;
tty_unregister_device(acm_tty_driver, acm->minor);
@ -619,41 +640,56 @@ static void acm_tty_unregister(struct acm *acm)
static int acm_tty_chars_in_buffer(struct tty_struct *tty);
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
static void acm_port_down(struct acm *acm, int drain)
{
struct acm *acm = tty->driver_data;
int i,nr;
if (!acm || !acm->used)
return;
nr = acm->rx_buflimit;
int i, nr = acm->rx_buflimit;
mutex_lock(&open_mutex);
if (!--acm->used) {
if (acm->dev) {
usb_autopm_get_interface(acm->control);
acm_set_control(acm, acm->ctrlout = 0);
/* try letting the last writes drain naturally */
if (acm->dev) {
usb_autopm_get_interface(acm->control);
acm_set_control(acm, acm->ctrlout = 0);
/* try letting the last writes drain naturally */
if (drain) {
wait_event_interruptible_timeout(acm->drain_wait,
(ACM_NW == acm_wb_is_avail(acm))
|| !acm->dev,
(ACM_NW == acm_wb_is_avail(acm)) || !acm->dev,
ACM_CLOSE_TIMEOUT * HZ);
usb_kill_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < nr; i++)
usb_kill_urb(acm->ru[i].urb);
acm->control->needs_remote_wakeup = 0;
usb_autopm_put_interface(acm->control);
} else
acm_tty_unregister(acm);
}
usb_kill_urb(acm->ctrlurb);
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < nr; i++)
usb_kill_urb(acm->ru[i].urb);
acm->control->needs_remote_wakeup = 0;
usb_autopm_put_interface(acm->control);
}
mutex_unlock(&open_mutex);
}
static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void acm_tty_hangup(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
tty_port_hangup(&acm->port);
acm_port_down(acm, 0);
}
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = tty->driver_data;
/* Perform the closing process and see if we need to do the hardware
shutdown */
if (tty_port_close_start(&acm->port, tty, filp) == 0)
return;
acm_port_down(acm, 0);
tty_port_close_end(&acm->port, tty);
mutex_lock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
if (!acm->dev)
acm_tty_unregister(acm);
mutex_unlock(&open_mutex);
}
static int acm_tty_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct acm *acm = tty->driver_data;
int stat;
@ -669,7 +705,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
return 0;
spin_lock_irqsave(&acm->write_lock, flags);
if ((wbn = acm_wb_alloc(acm)) < 0) {
wbn = acm_wb_alloc(acm);
if (wbn < 0) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0;
}
@ -681,7 +718,8 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
wb->len = count;
spin_unlock_irqrestore(&acm->write_lock, flags);
if ((stat = acm_write_start(acm, wbn)) < 0)
stat = acm_write_start(acm, wbn);
if (stat < 0)
return stat;
return count;
}
@ -767,8 +805,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
return -EINVAL;
newctrl = acm->ctrlout;
set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
(set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
(clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
newctrl = (newctrl & ~clear) | set;
@ -777,7 +817,8 @@ static int acm_tty_tiocmset(struct tty_struct *tty, struct file *file,
return acm_set_control(acm, acm->ctrlout = newctrl);
}
static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
static int acm_tty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct acm *acm = tty->driver_data;
@ -799,7 +840,8 @@ static const __u8 acm_tty_size[] = {
5, 6, 7, 8
};
static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old)
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old)
{
struct acm *acm = tty->driver_data;
struct ktermios *termios = tty->termios;
@ -809,19 +851,23 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios
if (!ACM_READY(acm))
return;
/* FIXME: Needs to support the tty_baud interface */
/* FIXME: Broken on sparc */
newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
newline.bParityType = termios->c_cflag & PARENB ?
(termios->c_cflag & PARODD ? 1 : 2) + (termios->c_cflag & CMSPAR ? 2 : 0) : 0;
(termios->c_cflag & PARODD ? 1 : 2) +
(termios->c_cflag & CMSPAR ? 2 : 0) : 0;
newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4];
/* FIXME: Needs to clear unsupported bits in the termios */
acm->clocal = ((termios->c_cflag & CLOCAL) != 0);
if (!newline.dwDTERate) {
newline.dwDTERate = acm->line.dwDTERate;
newctrl &= ~ACM_CTRL_DTR;
} else newctrl |= ACM_CTRL_DTR;
} else
newctrl |= ACM_CTRL_DTR;
if (newctrl != acm->ctrlout)
acm_set_control(acm, acm->ctrlout = newctrl);
@ -846,9 +892,8 @@ static void acm_write_buffers_free(struct acm *acm)
struct acm_wb *wb;
struct usb_device *usb_dev = interface_to_usbdev(acm->control);
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) {
for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++)
usb_buffer_free(usb_dev, acm->writesize, wb->buf, wb->dmah);
}
}
static void acm_read_buffers_free(struct acm *acm)
@ -857,7 +902,8 @@ static void acm_read_buffers_free(struct acm *acm)
int i, n = acm->rx_buflimit;
for (i = 0; i < n; i++)
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
usb_buffer_free(usb_dev, acm->readsize,
acm->rb[i].base, acm->rb[i].dma);
}
/* Little helper: write buffers allocate */
@ -882,8 +928,8 @@ static int acm_write_buffers_alloc(struct acm *acm)
return 0;
}
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
static int acm_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_cdc_union_desc *union_header = NULL;
struct usb_cdc_country_functional_desc *cfd = NULL;
@ -897,7 +943,7 @@ static int acm_probe (struct usb_interface *intf,
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct acm *acm;
int minor;
int ctrlsize,readsize;
int ctrlsize, readsize;
u8 *buf;
u8 ac_management_function = 0;
u8 call_management_function = 0;
@ -917,7 +963,7 @@ static int acm_probe (struct usb_interface *intf,
control_interface = usb_ifnum_to_if(usb_dev, 0);
goto skip_normal_probe;
}
/* normal probing*/
if (!buffer) {
dev_err(&intf->dev, "Weird descriptor references\n");
@ -925,8 +971,10 @@ static int acm_probe (struct usb_interface *intf,
}
if (!buflen) {
if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
if (intf->cur_altsetting->endpoint->extralen &&
intf->cur_altsetting->endpoint->extra) {
dev_dbg(&intf->dev,
"Seeking extra descriptors on endpoint\n");
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
@ -937,47 +985,43 @@ static int acm_probe (struct usb_interface *intf,
}
while (buflen > 0) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer [2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (union_header) {
dev_err(&intf->dev, "More than one "
"union descriptor, "
"skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)
buffer;
break;
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case USB_CDC_ACM_TYPE:
ac_management_function = buffer[3];
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((call_management_function & 3) != 3)
dev_err(&intf->dev, "This device "
"cannot do calls on its own. "
"It is no modem.\n");
break;
default:
/* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: "
"type %02x, length %d\n",
buffer[2], buffer[0]);
break;
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (union_header) {
dev_err(&intf->dev, "More than one "
"union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case USB_CDC_ACM_TYPE:
ac_management_function = buffer[3];
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((call_management_function & 3) != 3)
dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
break;
default:
/* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: "
"type %02x, length %d\n",
buffer[2], buffer[0]);
break;
}
next_desc:
buflen -= buffer[0];
buffer += buffer[0];
@ -985,33 +1029,36 @@ next_desc:
if (!union_header) {
if (call_interface_num > 0) {
dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
control_interface = intf;
} else {
dev_dbg(&intf->dev,"No union descriptor, giving up\n");
dev_dbg(&intf->dev,
"No union descriptor, giving up\n");
return -ENODEV;
}
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
if (!control_interface || !data_interface) {
dev_dbg(&intf->dev,"no interfaces\n");
dev_dbg(&intf->dev, "no interfaces\n");
return -ENODEV;
}
}
if (data_interface_num != call_interface_num)
dev_dbg(&intf->dev,"Separate call control interface. That is not fully supported.\n");
dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
skip_normal_probe:
/*workaround for switched interfaces */
if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
if (data_interface->cur_altsetting->desc.bInterfaceClass
!= CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass
== CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
dev_dbg(&intf->dev,
"Your device has switched interfaces.\n");
t = control_interface;
control_interface = data_interface;
data_interface = t;
@ -1023,9 +1070,9 @@ skip_normal_probe:
/* Accept probe requests only for the control interface */
if (intf != control_interface)
return -ENODEV;
if (usb_interface_claimed(data_interface)) { /* valid in this context */
dev_dbg(&intf->dev,"The data interface isn't available\n");
dev_dbg(&intf->dev, "The data interface isn't available\n");
return -EBUSY;
}
@ -1042,8 +1089,8 @@ skip_normal_probe:
if (!usb_endpoint_dir_in(epread)) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
dev_dbg(&intf->dev,
"The data interface has switched endpoints\n");
t = epread;
epread = epwrite;
epwrite = t;
@ -1056,13 +1103,15 @@ skip_normal_probe:
return -ENODEV;
}
if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
if (acm == NULL) {
dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
goto alloc_fail;
}
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2);
readsize = le16_to_cpu(epread->wMaxPacketSize) *
(quirks == SINGLE_RX_URB ? 1 : 2);
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
acm->control = control_interface;
acm->data = data_interface;
@ -1082,6 +1131,8 @@ skip_normal_probe:
spin_lock_init(&acm->read_lock);
mutex_init(&acm->mutex);
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
tty_port_init(&acm->port);
acm->port.ops = &acm_port_ops;
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
@ -1103,8 +1154,10 @@ skip_normal_probe:
for (i = 0; i < num_rx_buf; i++) {
struct acm_ru *rcv = &(acm->ru[i]);
if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
rcv->urb = usb_alloc_urb(0, GFP_KERNEL);
if (rcv->urb == NULL) {
dev_dbg(&intf->dev,
"out of memory (read urbs usb_alloc_urb)\n");
goto alloc_fail7;
}
@ -1117,26 +1170,29 @@ skip_normal_probe:
rb->base = usb_buffer_alloc(acm->dev, readsize,
GFP_KERNEL, &rb->dma);
if (!rb->base) {
dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
dev_dbg(&intf->dev,
"out of memory (read bufs usb_buffer_alloc)\n");
goto alloc_fail7;
}
}
for(i = 0; i < ACM_NW; i++)
{
for (i = 0; i < ACM_NW; i++) {
struct acm_wb *snd = &(acm->wb[i]);
if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (write urbs usb_alloc_urb)");
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
if (snd->urb == NULL) {
dev_dbg(&intf->dev,
"out of memory (write urbs usb_alloc_urb)");
goto alloc_fail7;
}
usb_fill_bulk_urb(snd->urb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
NULL, acm->writesize, acm_write_bulk, snd);
usb_fill_bulk_urb(snd->urb, usb_dev,
usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
NULL, acm->writesize, acm_write_bulk, snd);
snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
snd->instance = acm;
}
usb_set_intfdata (intf, acm);
usb_set_intfdata(intf, acm);
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
if (i < 0)
@ -1147,7 +1203,8 @@ skip_normal_probe:
if (!acm->country_codes)
goto skip_countries;
acm->country_code_size = cfd->bLength - 4;
memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, cfd->bLength - 4);
memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0,
cfd->bLength - 4);
acm->country_rel_date = cfd->iCountryCodeRelDate;
i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
@ -1156,7 +1213,8 @@ skip_normal_probe:
goto skip_countries;
}
i = device_create_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
i = device_create_file(&intf->dev,
&dev_attr_iCountryCodeRelDate);
if (i < 0) {
kfree(acm->country_codes);
goto skip_countries;
@ -1164,8 +1222,10 @@ skip_normal_probe:
}
skip_countries:
usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
usb_fill_int_urb(acm->ctrlurb, usb_dev,
usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
epctrl->bInterval);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
@ -1212,7 +1272,7 @@ static void stop_data_traffic(struct acm *acm)
tasklet_disable(&acm->urb_task);
usb_kill_urb(acm->ctrlurb);
for(i = 0; i < ACM_NW; i++)
for (i = 0; i < ACM_NW; i++)
usb_kill_urb(acm->wb[i].urb);
for (i = 0; i < acm->rx_buflimit; i++)
usb_kill_urb(acm->ru[i].urb);
@ -1227,13 +1287,14 @@ static void acm_disconnect(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct tty_struct *tty;
/* sibling interface is already cleaning up */
if (!acm)
return;
mutex_lock(&open_mutex);
if (acm->country_codes){
if (acm->country_codes) {
device_remove_file(&acm->control->dev,
&dev_attr_wCountryCodes);
device_remove_file(&acm->control->dev,
@ -1247,22 +1308,25 @@ static void acm_disconnect(struct usb_interface *intf)
stop_data_traffic(acm);
acm_write_buffers_free(acm);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
acm->ctrl_dma);
acm_read_buffers_free(acm);
usb_driver_release_interface(&acm_driver, intf == acm->control ?
acm->data : acm->control);
if (!acm->used) {
if (acm->port.count == 0) {
acm_tty_unregister(acm);
mutex_unlock(&open_mutex);
return;
}
mutex_unlock(&open_mutex);
if (acm->tty)
tty_hangup(acm->tty);
tty = tty_port_tty_get(&acm->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
#ifdef CONFIG_PM
@ -1297,7 +1361,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
*/
mutex_lock(&acm->mutex);
if (acm->used)
if (acm->port.count)
stop_data_traffic(acm);
mutex_unlock(&acm->mutex);
@ -1319,7 +1383,7 @@ static int acm_resume(struct usb_interface *intf)
return 0;
mutex_lock(&acm->mutex);
if (acm->used) {
if (acm->port.count) {
rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
if (rv < 0)
goto err_out;
@ -1398,7 +1462,7 @@ static struct usb_device_id acm_ids[] = {
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_GSM) },
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_3G ) },
USB_CDC_ACM_PROTO_AT_3G) },
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_CDMA) },
@ -1406,7 +1470,7 @@ static struct usb_device_id acm_ids[] = {
{ }
};
MODULE_DEVICE_TABLE (usb, acm_ids);
MODULE_DEVICE_TABLE(usb, acm_ids);
static struct usb_driver acm_driver = {
.name = "cdc_acm",
@ -1429,6 +1493,7 @@ static struct usb_driver acm_driver = {
static const struct tty_operations acm_ops = {
.open = acm_tty_open,
.close = acm_tty_close,
.hangup = acm_tty_hangup,
.write = acm_tty_write,
.write_room = acm_tty_write_room,
.ioctl = acm_tty_ioctl,
@ -1460,7 +1525,8 @@ static int __init acm_init(void)
acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
acm_tty_driver->init_termios = tty_std_termios;
acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
HUPCL | CLOCAL;
tty_set_operations(acm_tty_driver, &acm_ops);
retval = tty_register_driver(acm_tty_driver);
@ -1492,7 +1558,7 @@ static void __exit acm_exit(void)
module_init(acm_init);
module_exit(acm_exit);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR);

View File

@ -89,8 +89,8 @@ struct acm {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb; /* urbs */
struct tty_port port; /* our tty port data */
struct urb *ctrlurb; /* urbs */
u8 *ctrl_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma; /* dma handles of buffers */
u8 *country_codes; /* country codes from device */
@ -120,7 +120,6 @@ struct acm {
unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
unsigned int readsize,ctrlsize; /* buffer sizes for freeing */
unsigned int used; /* someone has this acm's device open */
unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */

View File

@ -93,8 +93,7 @@ static int belkin_sa_startup(struct usb_serial *serial);
static void belkin_sa_shutdown(struct usb_serial *serial);
static int belkin_sa_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close(struct usb_serial_port *port);
static void belkin_sa_read_int_callback(struct urb *urb);
static void belkin_sa_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios * old);
@ -244,8 +243,7 @@ exit:
} /* belkin_sa_open */
static void belkin_sa_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void belkin_sa_close(struct usb_serial_port *port)
{
dbg("%s port %d", __func__, port->number);

View File

@ -262,13 +262,33 @@ error: kfree(priv);
return r;
}
static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static int ch341_carrier_raised(struct usb_serial_port *port)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & CH341_BIT_DCD)
return 1;
return 0;
}
static void ch341_dtr_rts(struct usb_serial_port *port, int on)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
dbg("%s - port %d", __func__, port->number);
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR;
else
priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, priv->line_control);
wake_up_interruptible(&priv->delta_msr_wait);
}
static void ch341_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
/* shutdown our urbs */
@ -276,18 +296,6 @@ static void ch341_close(struct tty_struct *tty, struct usb_serial_port *port,
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
ch341_set_handshake(port->serial->dev, 0);
}
}
wake_up_interruptible(&priv->delta_msr_wait);
}
@ -302,7 +310,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
r = ch341_configure(serial->dev, priv);
if (r)
@ -322,7 +329,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port,
if (r) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
" error %d\n", __func__, r);
ch341_close(tty, port, NULL);
ch341_close(port);
return -EPROTO;
}
@ -343,9 +350,6 @@ static void ch341_set_termios(struct tty_struct *tty,
dbg("ch341_set_termios()");
if (!tty || !tty->termios)
return;
baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate;
@ -568,6 +572,8 @@ static struct usb_serial_driver ch341_device = {
.usb_driver = &ch341_driver,
.num_ports = 1,
.open = ch341_open,
.dtr_rts = ch341_dtr_rts,
.carrier_raised = ch341_carrier_raised,
.close = ch341_close,
.ioctl = ch341_ioctl,
.set_termios = ch341_set_termios,

View File

@ -169,7 +169,9 @@ static int usb_console_setup(struct console *co, char *options)
kfree(tty);
}
}
/* So we know not to kill the hardware on a hangup on this
port. We have also bumped the use count by one so it won't go
idle */
port->console = 1;
retval = 0;
@ -182,7 +184,7 @@ free_tty:
kfree(tty);
reset_open_count:
port->port.count = 0;
goto out;
goto out;
}
static void usb_console_write(struct console *co,

View File

@ -1,5 +1,5 @@
/*
* Silicon Laboratories CP2101/CP2102 USB to RS232 serial adaptor driver
* Silicon Laboratories CP210x USB to RS232 serial adaptor driver
*
* Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk)
*
@ -27,44 +27,46 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.08"
#define DRIVER_DESC "Silicon Labs CP2101/CP2102 RS232 serial adaptor driver"
#define DRIVER_VERSION "v0.09"
#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
/*
* Function Prototypes
*/
static int cp2101_open(struct tty_struct *, struct usb_serial_port *,
static int cp210x_open(struct tty_struct *, struct usb_serial_port *,
struct file *);
static void cp2101_cleanup(struct usb_serial_port *);
static void cp2101_close(struct tty_struct *, struct usb_serial_port *,
struct file*);
static void cp2101_get_termios(struct tty_struct *,
static void cp210x_cleanup(struct usb_serial_port *);
static void cp210x_close(struct usb_serial_port *);
static void cp210x_get_termios(struct tty_struct *,
struct usb_serial_port *port);
static void cp2101_get_termios_port(struct usb_serial_port *port,
static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int *cflagp, unsigned int *baudp);
static void cp2101_set_termios(struct tty_struct *, struct usb_serial_port *,
static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *,
struct ktermios*);
static int cp2101_tiocmget(struct tty_struct *, struct file *);
static int cp2101_tiocmset(struct tty_struct *, struct file *,
static int cp210x_tiocmget(struct tty_struct *, struct file *);
static int cp210x_tiocmset(struct tty_struct *, struct file *,
unsigned int, unsigned int);
static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *,
static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
unsigned int, unsigned int);
static void cp2101_break_ctl(struct tty_struct *, int);
static int cp2101_startup(struct usb_serial *);
static void cp2101_shutdown(struct usb_serial *);
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_startup(struct usb_serial *);
static void cp210x_shutdown(struct usb_serial *);
static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
{ USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
{ USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
{ USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
{ USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */
{ USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
@ -85,10 +87,12 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
{ USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
{ USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
{ USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
{ USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */
{ USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */
@ -99,7 +103,9 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
{ USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
{ USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
@ -108,53 +114,70 @@ static struct usb_device_id id_table [] = {
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver cp2101_driver = {
.name = "cp2101",
static struct usb_driver cp210x_driver = {
.name = "cp210x",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver cp2101_device = {
static struct usb_serial_driver cp210x_device = {
.driver = {
.owner = THIS_MODULE,
.name = "cp2101",
.name = "cp210x",
},
.usb_driver = &cp2101_driver,
.usb_driver = &cp210x_driver,
.id_table = id_table,
.num_ports = 1,
.open = cp2101_open,
.close = cp2101_close,
.break_ctl = cp2101_break_ctl,
.set_termios = cp2101_set_termios,
.tiocmget = cp2101_tiocmget,
.tiocmset = cp2101_tiocmset,
.attach = cp2101_startup,
.shutdown = cp2101_shutdown,
.open = cp210x_open,
.close = cp210x_close,
.break_ctl = cp210x_break_ctl,
.set_termios = cp210x_set_termios,
.tiocmget = cp210x_tiocmget,
.tiocmset = cp210x_tiocmset,
.attach = cp210x_startup,
.shutdown = cp210x_shutdown,
};
/* Config request types */
#define REQTYPE_HOST_TO_DEVICE 0x41
#define REQTYPE_DEVICE_TO_HOST 0xc1
/* Config SET requests. To GET, add 1 to the request number */
#define CP2101_UART 0x00 /* Enable / Disable */
#define CP2101_BAUDRATE 0x01 /* (BAUD_RATE_GEN_FREQ / baudrate) */
#define CP2101_BITS 0x03 /* 0x(0)(databits)(parity)(stopbits) */
#define CP2101_BREAK 0x05 /* On / Off */
#define CP2101_CONTROL 0x07 /* Flow control line states */
#define CP2101_MODEMCTL 0x13 /* Modem controls */
#define CP2101_CONFIG_6 0x19 /* 6 bytes of config data ??? */
/* Config request codes */
#define CP210X_IFC_ENABLE 0x00
#define CP210X_SET_BAUDDIV 0x01
#define CP210X_GET_BAUDDIV 0x02
#define CP210X_SET_LINE_CTL 0x03
#define CP210X_GET_LINE_CTL 0x04
#define CP210X_SET_BREAK 0x05
#define CP210X_IMM_CHAR 0x06
#define CP210X_SET_MHS 0x07
#define CP210X_GET_MDMSTS 0x08
#define CP210X_SET_XON 0x09
#define CP210X_SET_XOFF 0x0A
#define CP210X_SET_EVENTMASK 0x0B
#define CP210X_GET_EVENTMASK 0x0C
#define CP210X_SET_CHAR 0x0D
#define CP210X_GET_CHARS 0x0E
#define CP210X_GET_PROPS 0x0F
#define CP210X_GET_COMM_STATUS 0x10
#define CP210X_RESET 0x11
#define CP210X_PURGE 0x12
#define CP210X_SET_FLOW 0x13
#define CP210X_GET_FLOW 0x14
#define CP210X_EMBED_EVENTS 0x15
#define CP210X_GET_EVENTSTATE 0x16
#define CP210X_SET_CHARS 0x19
/* CP2101_UART */
/* CP210X_IFC_ENABLE */
#define UART_ENABLE 0x0001
#define UART_DISABLE 0x0000
/* CP2101_BAUDRATE */
/* CP210X_(SET|GET)_BAUDDIV */
#define BAUD_RATE_GEN_FREQ 0x384000
/* CP2101_BITS */
/* CP210X_(SET|GET)_LINE_CTL */
#define BITS_DATA_MASK 0X0f00
#define BITS_DATA_5 0X0500
#define BITS_DATA_6 0X0600
@ -174,11 +197,11 @@ static struct usb_serial_driver cp2101_device = {
#define BITS_STOP_1_5 0x0001
#define BITS_STOP_2 0x0002
/* CP2101_BREAK */
/* CP210X_SET_BREAK */
#define BREAK_ON 0x0000
#define BREAK_OFF 0x0001
/* CP2101_CONTROL */
/* CP210X_(SET_MHS|GET_MDMSTS) */
#define CONTROL_DTR 0x0001
#define CONTROL_RTS 0x0002
#define CONTROL_CTS 0x0010
@ -189,13 +212,13 @@ static struct usb_serial_driver cp2101_device = {
#define CONTROL_WRITE_RTS 0x0200
/*
* cp2101_get_config
* Reads from the CP2101 configuration registers
* cp210x_get_config
* Reads from the CP210x configuration registers
* 'size' is specified in bytes.
* 'data' is a pointer to a pre-allocated array of integers large
* enough to hold 'size' bytes (with 4 bytes to each integer)
*/
static int cp2101_get_config(struct usb_serial_port *port, u8 request,
static int cp210x_get_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
@ -211,9 +234,6 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request,
return -ENOMEM;
}
/* For get requests, the request number must be incremented */
request++;
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
request, REQTYPE_DEVICE_TO_HOST, 0x0000,
@ -236,12 +256,12 @@ static int cp2101_get_config(struct usb_serial_port *port, u8 request,
}
/*
* cp2101_set_config
* Writes to the CP2101 configuration registers
* cp210x_set_config
* Writes to the CP210x configuration registers
* Values less than 16 bits wide are sent directly
* 'size' is specified in bytes.
*/
static int cp2101_set_config(struct usb_serial_port *port, u8 request,
static int cp210x_set_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
@ -292,21 +312,21 @@ static int cp2101_set_config(struct usb_serial_port *port, u8 request,
}
/*
* cp2101_set_config_single
* Convenience function for calling cp2101_set_config on single data values
* cp210x_set_config_single
* Convenience function for calling cp210x_set_config on single data values
* without requiring an integer pointer
*/
static inline int cp2101_set_config_single(struct usb_serial_port *port,
static inline int cp210x_set_config_single(struct usb_serial_port *port,
u8 request, unsigned int data)
{
return cp2101_set_config(port, request, &data, 2);
return cp210x_set_config(port, request, &data, 2);
}
/*
* cp2101_quantise_baudrate
* cp210x_quantise_baudrate
* Quantises the baud rate as per AN205 Table 1
*/
static unsigned int cp2101_quantise_baudrate(unsigned int baud) {
static unsigned int cp210x_quantise_baudrate(unsigned int baud) {
if (baud <= 56) baud = 0;
else if (baud <= 300) baud = 300;
else if (baud <= 600) baud = 600;
@ -343,7 +363,7 @@ static unsigned int cp2101_quantise_baudrate(unsigned int baud) {
return baud;
}
static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
{
struct usb_serial *serial = port->serial;
@ -351,7 +371,7 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
dbg("%s - port %d", __func__, port->number);
if (cp2101_set_config_single(port, CP2101_UART, UART_ENABLE)) {
if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
dev_err(&port->dev, "%s - Unable to enable UART\n",
__func__);
return -EPROTO;
@ -373,17 +393,17 @@ static int cp2101_open(struct tty_struct *tty, struct usb_serial_port *port,
}
/* Configure the termios structure */
cp2101_get_termios(tty, port);
cp210x_get_termios(tty, port);
/* Set the DTR and RTS pins low */
cp2101_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
: port,
NULL, TIOCM_DTR | TIOCM_RTS, 0);
return 0;
}
static void cp2101_cleanup(struct usb_serial_port *port)
static void cp210x_cleanup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
@ -398,8 +418,7 @@ static void cp2101_cleanup(struct usb_serial_port *port)
}
}
static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void cp210x_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
@ -410,23 +429,23 @@ static void cp2101_close(struct tty_struct *tty, struct usb_serial_port *port,
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
mutex_unlock(&port->serial->disc_mutex);
}
/*
* cp2101_get_termios
* cp210x_get_termios
* Reads the baud rate, data bits, parity, stop bits and flow control mode
* from the device, corrects any unsupported values, and configures the
* termios structure to reflect the state of the device
*/
static void cp2101_get_termios(struct tty_struct *tty,
static void cp210x_get_termios(struct tty_struct *tty,
struct usb_serial_port *port)
{
unsigned int baud;
if (tty) {
cp2101_get_termios_port(tty->driver_data,
cp210x_get_termios_port(tty->driver_data,
&tty->termios->c_cflag, &baud);
tty_encode_baud_rate(tty, baud, baud);
}
@ -434,15 +453,15 @@ static void cp2101_get_termios(struct tty_struct *tty,
else {
unsigned int cflag;
cflag = 0;
cp2101_get_termios_port(port, &cflag, &baud);
cp210x_get_termios_port(port, &cflag, &baud);
}
}
/*
* cp2101_get_termios_port
* This is the heart of cp2101_get_termios which always uses a &usb_serial_port.
* cp210x_get_termios_port
* This is the heart of cp210x_get_termios which always uses a &usb_serial_port.
*/
static void cp2101_get_termios_port(struct usb_serial_port *port,
static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int *cflagp, unsigned int *baudp)
{
unsigned int cflag, modem_ctl[4];
@ -451,17 +470,17 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
dbg("%s - port %d", __func__, port->number);
cp2101_get_config(port, CP2101_BAUDRATE, &baud, 2);
cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2);
/* Convert to baudrate */
if (baud)
baud = cp2101_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud);
dbg("%s - baud rate = %d", __func__, baud);
*baudp = baud;
cflag = *cflagp;
cp2101_get_config(port, CP2101_BITS, &bits, 2);
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
cflag &= ~CSIZE;
switch (bits & BITS_DATA_MASK) {
case BITS_DATA_5:
@ -486,14 +505,14 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
default:
dbg("%s - Unknown number of data bits, using 8", __func__);
cflag |= CS8;
bits &= ~BITS_DATA_MASK;
bits |= BITS_DATA_8;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
}
@ -516,20 +535,20 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
__func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
case BITS_PARITY_SPACE:
dbg("%s - parity = SPACE (not supported, disabling parity)",
__func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
default:
dbg("%s - Unknown parity mode, disabling parity", __func__);
cflag &= ~PARENB;
bits &= ~BITS_PARITY_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
}
@ -542,7 +561,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)",
__func__);
bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
case BITS_STOP_2:
dbg("%s - stop bits = 2", __func__);
@ -552,11 +571,11 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
dbg("%s - Unknown number of stop bits, using 1 stop bit",
__func__);
bits &= ~BITS_STOP_MASK;
cp2101_set_config(port, CP2101_BITS, &bits, 2);
cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
break;
}
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
if (modem_ctl[0] & 0x0008) {
dbg("%s - flow control = CRTSCTS", __func__);
cflag |= CRTSCTS;
@ -568,7 +587,7 @@ static void cp2101_get_termios_port(struct usb_serial_port *port,
*cflagp = cflag;
}
static void cp2101_set_termios(struct tty_struct *tty,
static void cp210x_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned int cflag, old_cflag;
@ -583,13 +602,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
tty->termios->c_cflag &= ~CMSPAR;
cflag = tty->termios->c_cflag;
old_cflag = old_termios->c_cflag;
baud = cp2101_quantise_baudrate(tty_get_baud_rate(tty));
baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
/* If the baud rate is to be updated*/
if (baud != tty_termios_baud_rate(old_termios) && baud != 0) {
dbg("%s - Setting baud rate to %d baud", __func__,
baud);
if (cp2101_set_config_single(port, CP2101_BAUDRATE,
if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
dbg("Baud rate requested not supported by device\n");
baud = tty_termios_baud_rate(old_termios);
@ -600,7 +619,7 @@ static void cp2101_set_termios(struct tty_struct *tty,
/* If the number of data bits is to be updated */
if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
cp2101_get_config(port, CP2101_BITS, &bits, 2);
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
bits &= ~BITS_DATA_MASK;
switch (cflag & CSIZE) {
case CS5:
@ -624,19 +643,19 @@ static void cp2101_set_termios(struct tty_struct *tty,
dbg("%s - data bits = 9", __func__);
break;*/
default:
dbg("cp2101 driver does not "
dbg("cp210x driver does not "
"support the number of bits requested,"
" using 8 bit mode\n");
bits |= BITS_DATA_8;
break;
}
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of data bits requested "
"not supported by device\n");
}
if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
cp2101_get_config(port, CP2101_BITS, &bits, 2);
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
bits &= ~BITS_PARITY_MASK;
if (cflag & PARENB) {
if (cflag & PARODD) {
@ -647,13 +666,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
dbg("%s - parity = EVEN", __func__);
}
}
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Parity mode not supported "
"by device\n");
}
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
cp2101_get_config(port, CP2101_BITS, &bits, 2);
cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
bits &= ~BITS_STOP_MASK;
if (cflag & CSTOPB) {
bits |= BITS_STOP_2;
@ -662,13 +681,13 @@ static void cp2101_set_termios(struct tty_struct *tty,
bits |= BITS_STOP_1;
dbg("%s - stop bits = 1", __func__);
}
if (cp2101_set_config(port, CP2101_BITS, &bits, 2))
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of stop bits requested "
"not supported by device\n");
}
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
cp2101_get_config(port, CP2101_MODEMCTL, modem_ctl, 16);
cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16);
dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
__func__, modem_ctl[0], modem_ctl[1],
modem_ctl[2], modem_ctl[3]);
@ -688,19 +707,19 @@ static void cp2101_set_termios(struct tty_struct *tty,
dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x",
__func__, modem_ctl[0], modem_ctl[1],
modem_ctl[2], modem_ctl[3]);
cp2101_set_config(port, CP2101_MODEMCTL, modem_ctl, 16);
cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16);
}
}
static int cp2101_tiocmset (struct tty_struct *tty, struct file *file,
static int cp210x_tiocmset (struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
return cp2101_tiocmset_port(port, file, set, clear);
return cp210x_tiocmset_port(port, file, set, clear);
}
static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file,
static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear)
{
unsigned int control = 0;
@ -726,10 +745,10 @@ static int cp2101_tiocmset_port(struct usb_serial_port *port, struct file *file,
dbg("%s - control = 0x%.4x", __func__, control);
return cp2101_set_config(port, CP2101_CONTROL, &control, 2);
return cp210x_set_config(port, CP210X_SET_MHS, &control, 2);
}
static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
static int cp210x_tiocmget (struct tty_struct *tty, struct file *file)
{
struct usb_serial_port *port = tty->driver_data;
unsigned int control;
@ -737,7 +756,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
dbg("%s - port %d", __func__, port->number);
cp2101_get_config(port, CP2101_CONTROL, &control, 1);
cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
|((control & CONTROL_RTS) ? TIOCM_RTS : 0)
@ -751,7 +770,7 @@ static int cp2101_tiocmget (struct tty_struct *tty, struct file *file)
return result;
}
static void cp2101_break_ctl (struct tty_struct *tty, int break_state)
static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
unsigned int state;
@ -763,17 +782,17 @@ static void cp2101_break_ctl (struct tty_struct *tty, int break_state)
state = BREAK_ON;
dbg("%s - turning break %s", __func__,
state == BREAK_OFF ? "off" : "on");
cp2101_set_config(port, CP2101_BREAK, &state, 2);
cp210x_set_config(port, CP210X_SET_BREAK, &state, 2);
}
static int cp2101_startup(struct usb_serial *serial)
static int cp210x_startup(struct usb_serial *serial)
{
/* CP2101 buffers behave strangely unless device is reset */
/* cp210x buffers behave strangely unless device is reset */
usb_reset_device(serial->dev);
return 0;
}
static void cp2101_shutdown(struct usb_serial *serial)
static void cp210x_shutdown(struct usb_serial *serial)
{
int i;
@ -781,21 +800,21 @@ static void cp2101_shutdown(struct usb_serial *serial)
/* Stop reads and writes on all ports */
for (i = 0; i < serial->num_ports; ++i)
cp2101_cleanup(serial->port[i]);
cp210x_cleanup(serial->port[i]);
}
static int __init cp2101_init(void)
static int __init cp210x_init(void)
{
int retval;
retval = usb_serial_register(&cp2101_device);
retval = usb_serial_register(&cp210x_device);
if (retval)
return retval; /* Failed to register */
retval = usb_register(&cp2101_driver);
retval = usb_register(&cp210x_driver);
if (retval) {
/* Failed to register */
usb_serial_deregister(&cp2101_device);
usb_serial_deregister(&cp210x_device);
return retval;
}
@ -805,14 +824,14 @@ static int __init cp2101_init(void)
return 0;
}
static void __exit cp2101_exit(void)
static void __exit cp210x_exit(void)
{
usb_deregister(&cp2101_driver);
usb_serial_deregister(&cp2101_device);
usb_deregister(&cp210x_driver);
usb_serial_deregister(&cp210x_device);
}
module_init(cp2101_init);
module_exit(cp2101_exit);
module_init(cp210x_init);
module_exit(cp210x_exit);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);

View File

@ -61,8 +61,7 @@ static int cyberjack_startup(struct usb_serial *serial);
static void cyberjack_shutdown(struct usb_serial *serial);
static int cyberjack_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cyberjack_close(struct usb_serial_port *port);
static int cyberjack_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room(struct tty_struct *tty);
@ -185,8 +184,7 @@ static int cyberjack_open(struct tty_struct *tty,
return result;
}
static void cyberjack_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void cyberjack_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);

View File

@ -174,8 +174,8 @@ static int cypress_ca42v2_startup(struct usb_serial *serial);
static void cypress_shutdown(struct usb_serial *serial);
static int cypress_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void cypress_close(struct usb_serial_port *port);
static void cypress_dtr_rts(struct usb_serial_port *port, int on);
static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void cypress_send(struct usb_serial_port *port);
@ -218,6 +218,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
@ -244,6 +245,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
@ -270,6 +272,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.shutdown = cypress_shutdown,
.open = cypress_open,
.close = cypress_close,
.dtr_rts = cypress_dtr_rts,
.write = cypress_write,
.write_room = cypress_write_room,
.ioctl = cypress_ioctl,
@ -656,11 +659,7 @@ static int cypress_open(struct tty_struct *tty,
priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags);
/* raise both lines and set termios */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags);
/* Set termios */
result = cypress_write(tty, port, NULL, 0);
if (result) {
@ -694,76 +693,42 @@ static int cypress_open(struct tty_struct *tty,
__func__, result);
cypress_set_dead(port);
}
port->port.drain_delay = 256;
return result;
} /* cypress_open */
static void cypress_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void cypress_dtr_rts(struct usb_serial_port *port, int on)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
if (on == 0)
priv->line_control = 0;
else
priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(NULL, port, NULL, 0);
}
static void cypress_close(struct usb_serial_port *port)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
int bps;
long timeout;
wait_queue_t wait;
dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from buffer */
spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
/* without mutex, allowed due to harmless failure mode */
|| port->serial->disconnected)
break;
spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
spin_unlock_irq(&priv->lock);
/* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex);
return;
}
/* wait for characters to drain from device */
if (tty) {
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ * 2560) / bps, HZ / 10);
else
timeout = 2 * HZ;
schedule_timeout_interruptible(timeout);
}
cypress_buf_clear(priv->buf);
dbg("%s - stopping urbs", __func__);
usb_kill_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
spin_unlock_irq(&priv->lock);
cypress_write(tty, port, NULL, 0);
}
}
if (stats)
dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",

View File

@ -422,7 +422,6 @@ struct digi_port {
int dp_throttled;
int dp_throttle_restart;
wait_queue_head_t dp_flush_wait;
int dp_in_close; /* close in progress */
wait_queue_head_t dp_close_wait; /* wait queue for close */
struct work_struct dp_wakeup_work;
struct usb_serial_port *dp_port;
@ -456,8 +455,9 @@ static int digi_write_room(struct tty_struct *tty);
static int digi_chars_in_buffer(struct tty_struct *tty);
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void digi_close(struct usb_serial_port *port);
static int digi_carrier_raised(struct usb_serial_port *port);
static void digi_dtr_rts(struct usb_serial_port *port, int on);
static int digi_startup_device(struct usb_serial *serial);
static int digi_startup(struct usb_serial *serial);
static void digi_shutdown(struct usb_serial *serial);
@ -510,6 +510,8 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.num_ports = 3,
.open = digi_open,
.close = digi_close,
.dtr_rts = digi_dtr_rts,
.carrier_raised = digi_carrier_raised,
.write = digi_write,
.write_room = digi_write_room,
.write_bulk_callback = digi_write_bulk_callback,
@ -1328,6 +1330,19 @@ static int digi_chars_in_buffer(struct tty_struct *tty)
}
static void digi_dtr_rts(struct usb_serial_port *port, int on)
{
/* Adjust DTR and RTS */
digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1);
}
static int digi_carrier_raised(struct usb_serial_port *port)
{
struct digi_port *priv = usb_get_serial_port_data(port);
if (priv->dp_modem_signals & TIOCM_CD)
return 1;
return 0;
}
static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
@ -1336,7 +1351,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
unsigned long flags = 0;
dbg("digi_open: TOP: port=%d, open_count=%d",
priv->dp_port_num, port->port.count);
@ -1345,26 +1359,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
if (digi_startup_device(port->serial) != 0)
return -ENXIO;
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* don't wait on a close in progress for non-blocking opens */
if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return -EAGAIN;
}
/* wait for a close in progress to finish */
while (priv->dp_in_close) {
cond_wait_interruptible_timeout_irqrestore(
&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
&priv->dp_port_lock, flags);
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&priv->dp_port_lock, flags);
}
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
/* read modem signals automatically whenever they change */
buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
buf[1] = priv->dp_port_num;
@ -1387,16 +1381,11 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port,
not_termios.c_iflag = ~tty->termios->c_iflag;
digi_set_termios(tty, port, &not_termios);
}
/* set DTR and RTS */
digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1);
return 0;
}
static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void digi_close(struct usb_serial_port *port)
{
DEFINE_WAIT(wait);
int ret;
@ -1411,28 +1400,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
if (port->serial->disconnected)
goto exit;
/* do cleanup only after final close on this port */
spin_lock_irq(&priv->dp_port_lock);
priv->dp_in_close = 1;
spin_unlock_irq(&priv->dp_port_lock);
/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
/* wait for output to drain */
if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
/* wait for transmit idle */
if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
/* drop DTR and RTS */
digi_set_modem_signals(port, 0, 0);
/* FIXME: Transmit idle belongs in the wait_unti_sent path */
digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
/* disable input flow control */
buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
@ -1477,11 +1447,9 @@ static void digi_close(struct tty_struct *tty, struct usb_serial_port *port,
/* shutdown any outstanding bulk writes */
usb_kill_urb(port->write_urb);
}
tty->closing = 0;
exit:
spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
@ -1560,7 +1528,6 @@ static int digi_startup(struct usb_serial *serial)
priv->dp_throttled = 0;
priv->dp_throttle_restart = 0;
init_waitqueue_head(&priv->dp_flush_wait);
priv->dp_in_close = 0;
init_waitqueue_head(&priv->dp_close_wait);
INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
priv->dp_port = serial->port[i];

View File

@ -81,8 +81,7 @@ static int debug;
/* function prototypes for an empeg-car player */
static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void empeg_close(struct usb_serial_port *port);
static int empeg_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf,
int count);
@ -181,8 +180,7 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
}
static void empeg_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void empeg_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);

View File

@ -89,6 +89,7 @@ struct ftdi_private {
int force_rtscts; /* if non-zero, force RTS-CTS to always
be enabled */
unsigned int latency; /* latency setting in use */
spinlock_t tx_lock; /* spinlock for transmit state */
unsigned long tx_bytes;
unsigned long tx_outstanding_bytes;
@ -719,8 +720,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port);
static int ftdi_sio_port_remove(struct usb_serial_port *port);
static int ftdi_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ftdi_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ftdi_close(struct usb_serial_port *port);
static void ftdi_dtr_rts(struct usb_serial_port *port, int on);
static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int ftdi_write_room(struct tty_struct *tty);
@ -758,6 +759,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.port_remove = ftdi_sio_port_remove,
.open = ftdi_open,
.close = ftdi_close,
.dtr_rts = ftdi_dtr_rts,
.throttle = ftdi_throttle,
.unthrottle = ftdi_unthrottle,
.write = ftdi_write,
@ -1037,7 +1039,54 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
return rv;
}
static int write_latency_timer(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
char buf[1];
int rv = 0;
int l = priv->latency;
if (priv->flags & ASYNC_LOW_LATENCY)
l = 1;
dbg("%s: setting latency timer = %i", __func__, l);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
l, priv->interface,
buf, 0, WDR_TIMEOUT);
if (rv < 0)
dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
return rv;
}
static int read_latency_timer(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
unsigned short latency = 0;
int rv = 0;
dbg("%s", __func__);
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
0, priv->interface,
(char *) &latency, 1, WDR_TIMEOUT);
if (rv < 0) {
dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
return -EIO;
}
return latency;
}
static int get_serial_info(struct usb_serial_port *port,
struct serial_struct __user *retinfo)
@ -1097,6 +1146,7 @@ static int set_serial_info(struct tty_struct *tty,
priv->custom_divisor = new_serial.custom_divisor;
tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
check_and_exit:
if ((old_priv.flags & ASYNC_SPD_MASK) !=
@ -1192,27 +1242,13 @@ static ssize_t show_latency_timer(struct device *dev,
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
unsigned short latency = 0;
int rv = 0;
dbg("%s", __func__);
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
0, priv->interface,
(char *) &latency, 1, WDR_TIMEOUT);
if (rv < 0) {
dev_err(dev, "Unable to read latency timer: %i\n", rv);
return -EIO;
}
return sprintf(buf, "%i\n", latency);
if (priv->flags & ASYNC_LOW_LATENCY)
return sprintf(buf, "1\n");
else
return sprintf(buf, "%i\n", priv->latency);
}
/* Write a new value of the latency timer, in units of milliseconds. */
static ssize_t store_latency_timer(struct device *dev,
struct device_attribute *attr, const char *valbuf,
@ -1220,25 +1256,13 @@ static ssize_t store_latency_timer(struct device *dev,
{
struct usb_serial_port *port = to_usb_serial_port(dev);
struct ftdi_private *priv = usb_get_serial_port_data(port);
struct usb_device *udev = port->serial->dev;
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
dbg("%s: setting latency timer = %i", __func__, v);
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
v, priv->interface,
buf, 0, WDR_TIMEOUT);
if (rv < 0) {
dev_err(dev, "Unable to write latency timer: %i\n", rv);
priv->latency = v;
rv = write_latency_timer(port);
if (rv < 0)
return -EIO;
}
return count;
}
@ -1392,6 +1416,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
usb_set_serial_port_data(port, priv);
ftdi_determine_type(port);
read_latency_timer(port);
create_sysfs_attrs(port);
return 0;
}
@ -1514,6 +1539,8 @@ static int ftdi_open(struct tty_struct *tty,
if (tty)
tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@ -1529,11 +1556,6 @@ static int ftdi_open(struct tty_struct *tty,
if (tty)
ftdi_set_termios(tty, port, tty->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 */
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
/* Not throttled */
spin_lock_irqsave(&priv->rx_lock, flags);
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
@ -1558,6 +1580,30 @@ static int ftdi_open(struct tty_struct *tty,
} /* ftdi_open */
static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* Disable flow control */
if (!on && usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
/* drop RTS and DTR */
if (on)
set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
else
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
mutex_unlock(&port->serial->disc_mutex);
}
/*
* usbserial:__serial_close only calls ftdi_close if the point is open
@ -1567,31 +1613,12 @@ static int ftdi_open(struct tty_struct *tty,
*
*/
static void ftdi_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void ftdi_close(struct usb_serial_port *port)
{ /* ftdi_close */
unsigned int c_cflag = tty->termios->c_cflag;
struct ftdi_private *priv = usb_get_serial_port_data(port);
char buf[1];
dbg("%s", __func__);
mutex_lock(&port->serial->disc_mutex);
if (c_cflag & HUPCL && !port->serial->disconnected) {
/* Disable flow control */
if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
dev_err(&port->dev, "error from flowcontrol urb\n");
}
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} /* Note change no line if hupcl is off */
mutex_unlock(&port->serial->disc_mutex);
/* cancel any scheduled reading */
cancel_delayed_work_sync(&priv->rx_work);

View File

@ -993,8 +993,7 @@ static int garmin_open(struct tty_struct *tty,
}
static void garmin_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void garmin_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);

View File

@ -184,8 +184,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_resume);
void usb_serial_generic_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
void usb_serial_generic_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
generic_cleanup(port);

View File

@ -207,8 +207,7 @@ static void edge_bulk_out_cmd_callback(struct urb *urb);
/* function prototypes for the usbserial callbacks */
static int edge_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void edge_close(struct usb_serial_port *port);
static int edge_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int edge_write_room(struct tty_struct *tty);
@ -965,7 +964,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->txfifo.fifo) {
dbg("%s - no memory", __func__);
edge_close(tty, port, filp);
edge_close(port);
return -ENOMEM;
}
@ -975,7 +974,7 @@ static int edge_open(struct tty_struct *tty,
if (!edge_port->write_urb) {
dbg("%s - no memory", __func__);
edge_close(tty, port, filp);
edge_close(port);
return -ENOMEM;
}
@ -1099,8 +1098,7 @@ static void block_until_tx_empty(struct edgeport_port *edge_port)
* edge_close
* this function is called by the tty driver when a port is closed
*****************************************************************************/
static void edge_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;

View File

@ -2009,8 +2009,7 @@ release_es_lock:
return status;
}
static void edge_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;

View File

@ -76,8 +76,7 @@ static int initial_wait;
/* Function prototypes for an ipaq */
static int ipaq_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ipaq_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void ipaq_close(struct usb_serial_port *port);
static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
static void ipaq_shutdown(struct usb_serial *serial);
@ -714,8 +713,7 @@ error:
}
static void ipaq_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void ipaq_close(struct usb_serial_port *port)
{
struct ipaq_private *priv = usb_get_serial_port_data(port);

View File

@ -302,23 +302,17 @@ static int ipw_open(struct tty_struct *tty,
return 0;
}
static void ipw_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void ipw_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_device *dev = port->serial->dev;
int result;
if (tty_hung_up_p(filp)) {
dbg("%s: tty_hung_up_p ...", __func__);
return;
}
/*--1: drop the dtr */
dbg("%s:dropping dtr", __func__);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN,
USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
IPW_PIN_CLRDTR,
on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR,
0,
NULL,
0,
@ -332,7 +326,7 @@ static void ipw_close(struct tty_struct *tty,
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
IPW_SIO_SET_PIN, USB_TYPE_VENDOR |
USB_RECIP_INTERFACE | USB_DIR_OUT,
IPW_PIN_CLRRTS,
on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS,
0,
NULL,
0,
@ -340,7 +334,12 @@ static void ipw_close(struct tty_struct *tty,
if (result < 0)
dev_err(&port->dev,
"dropping rts failed (error = %d)\n", result);
}
static void ipw_close(struct usb_serial_port *port)
{
struct usb_device *dev = port->serial->dev;
int result;
/*--3: purge */
dbg("%s:sending purge", __func__);
@ -461,6 +460,7 @@ static struct usb_serial_driver ipw_device = {
.num_ports = 1,
.open = ipw_open,
.close = ipw_close,
.dtr_rts = ipw_dtr_rts,
.port_probe = ipw_probe,
.port_remove = ipw_disconnect,
.write = ipw_write,

View File

@ -88,8 +88,7 @@ static int xbof = -1;
static int ir_startup (struct usb_serial *serial);
static int ir_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filep);
static void ir_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filep);
static void ir_close(struct usb_serial_port *port);
static int ir_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static void ir_write_bulk_callback (struct urb *urb);
@ -346,8 +345,7 @@ static int ir_open(struct tty_struct *tty,
return result;
}
static void ir_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file * filp)
static void ir_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);

View File

@ -40,7 +40,7 @@ static int debug;
/*
* Version Information
*/
#define DRIVER_VERSION "v0.5"
#define DRIVER_VERSION "v0.10"
#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
static struct usb_device_id id_table[] = {
@ -70,7 +70,6 @@ static void read_rxcmd_callback(struct urb *urb);
struct iuu_private {
spinlock_t lock; /* store irq state */
wait_queue_head_t delta_msr_wait;
u8 line_control;
u8 line_status;
u8 termios_initialized;
int tiostatus; /* store IUART SIGNAL for tiocmget call */
@ -651,32 +650,33 @@ static int iuu_bulk_write(struct usb_serial_port *port)
unsigned long flags;
int result;
int i;
int buf_len;
char *buf_ptr = port->write_urb->transfer_buffer;
dbg("%s - enter", __func__);
spin_lock_irqsave(&priv->lock, flags);
*buf_ptr++ = IUU_UART_ESC;
*buf_ptr++ = IUU_UART_TX;
*buf_ptr++ = priv->writelen;
memcpy(buf_ptr, priv->writebuf,
priv->writelen);
memcpy(buf_ptr, priv->writebuf, priv->writelen);
buf_len = priv->writelen;
priv->writelen = 0;
spin_unlock_irqrestore(&priv->lock, flags);
if (debug == 1) {
for (i = 0; i < priv->writelen; i++)
for (i = 0; i < buf_len; i++)
sprintf(priv->dbgbuf + i*2 ,
"%02X", priv->writebuf[i]);
priv->dbgbuf[priv->writelen+i*2] = 0;
priv->dbgbuf[buf_len+i*2] = 0;
dbg("%s - writing %i chars : %s", __func__,
priv->writelen, priv->dbgbuf);
buf_len, priv->dbgbuf);
}
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer, priv->writelen + 3,
port->write_urb->transfer_buffer, buf_len + 3,
iuu_rxcmd, port);
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
spin_lock_irqsave(&priv->lock, flags);
priv->writelen = 0;
spin_unlock_irqrestore(&priv->lock, flags);
usb_serial_port_softint(port);
return result;
}
@ -770,14 +770,10 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port,
return -ENOMEM;
spin_lock_irqsave(&priv->lock, flags);
if (priv->writelen > 0) {
/* buffer already filled but not commited */
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
/* fill the buffer */
memcpy(priv->writebuf, buf, count);
priv->writelen = count;
memcpy(priv->writebuf + priv->writelen, buf, count);
priv->writelen += count;
spin_unlock_irqrestore(&priv->lock, flags);
return count;
@ -819,7 +815,7 @@ static int iuu_uart_on(struct usb_serial_port *port)
buf[0] = IUU_UART_ENABLE;
buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN);
status = bulk_immediate(port, buf, 4);
if (status != IUU_OPERATION_OK) {
@ -946,19 +942,59 @@ static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
return status;
}
static int set_control_lines(struct usb_device *dev, u8 value)
static void iuu_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
return 0;
const u32 supported_mask = CMSPAR|PARENB|PARODD;
unsigned int cflag = tty->termios->c_cflag;
int status;
u32 actual;
u32 parity;
int csize = CS7;
int baud = 9600; /* Fixed for the moment */
u32 newval = cflag & supported_mask;
/* compute the parity parameter */
parity = 0;
if (cflag & CMSPAR) { /* Using mark space */
if (cflag & PARODD)
parity |= IUU_PARITY_SPACE;
else
parity |= IUU_PARITY_MARK;
} else if (!(cflag & PARENB)) {
parity |= IUU_PARITY_NONE;
csize = CS8;
} else if (cflag & PARODD)
parity |= IUU_PARITY_ODD;
else
parity |= IUU_PARITY_EVEN;
parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT);
/* set it */
status = iuu_uart_baud(port,
(clockmode == 2) ? 16457 : 9600 * boost / 100,
&actual, parity);
/* set the termios value to the real one, so the user now what has
* changed. We support few fields so its easies to copy the old hw
* settings back over and then adjust them
*/
if (old_termios)
tty_termios_copy_hw(tty->termios, old_termios);
if (status != 0) /* Set failed - return old bits */
return;
/* Re-encode speed, parity and csize */
tty_encode_baud_rate(tty, baud, baud);
tty->termios->c_cflag &= ~(supported_mask|CSIZE);
tty->termios->c_cflag |= newval | csize;
}
static void iuu_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void iuu_close(struct usb_serial_port *port)
{
/* iuu_led (port,255,0,0,0); */
struct usb_serial *serial;
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
serial = port->serial;
if (!serial)
@ -968,17 +1004,6 @@ static void iuu_close(struct tty_struct *tty,
iuu_uart_off(port);
if (serial->dev) {
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
priv = usb_get_serial_port_data(port);
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines(port->serial->dev, 0);
}
}
/* free writebuf */
/* shutdown our urbs */
dbg("%s - shutting down urbs", __func__);
@ -1154,7 +1179,7 @@ static int iuu_open(struct tty_struct *tty,
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb,"
" error %d\n", __func__, result);
iuu_close(tty, port, NULL);
iuu_close(port);
return -EPROTO;
} else {
dbg("%s - rxcmd OK", __func__);
@ -1175,6 +1200,7 @@ static struct usb_serial_driver iuu_device = {
.read_bulk_callback = iuu_uart_read_callback,
.tiocmget = iuu_tiocmget,
.tiocmset = iuu_tiocmset,
.set_termios = iuu_set_termios,
.attach = iuu_startup,
.shutdown = iuu_shutdown,
};

View File

@ -1298,8 +1298,16 @@ static inline void stop_urb(struct urb *urb)
usb_kill_urb(urb);
}
static void keyspan_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void keyspan_dtr_rts(struct usb_serial_port *port, int on)
{
struct keyspan_port_private *p_priv = usb_get_serial_port_data(port);
p_priv->rts_state = on;
p_priv->dtr_state = on;
keyspan_send_setup(port, 0);
}
static void keyspan_close(struct usb_serial_port *port)
{
int i;
struct usb_serial *serial = port->serial;
@ -1336,7 +1344,6 @@ static void keyspan_close(struct tty_struct *tty,
stop_urb(p_priv->out_urbs[i]);
}
}
tty_port_tty_set(&port->port, NULL);
}
/* download the firmware to a pre-renumeration device */

View File

@ -38,9 +38,8 @@
static int keyspan_open (struct tty_struct *tty,
struct usb_serial_port *port,
struct file *filp);
static void keyspan_close (struct tty_struct *tty,
struct usb_serial_port *port,
struct file *filp);
static void keyspan_close (struct usb_serial_port *port);
static void keyspan_dtr_rts (struct usb_serial_port *port, int on);
static int keyspan_startup (struct usb_serial *serial);
static void keyspan_shutdown (struct usb_serial *serial);
static int keyspan_write_room (struct tty_struct *tty);
@ -562,6 +561,7 @@ static struct usb_serial_driver keyspan_1port_device = {
.num_ports = 1,
.open = keyspan_open,
.close = keyspan_close,
.dtr_rts = keyspan_dtr_rts,
.write = keyspan_write,
.write_room = keyspan_write_room,
.set_termios = keyspan_set_termios,
@ -582,6 +582,7 @@ static struct usb_serial_driver keyspan_2port_device = {
.num_ports = 2,
.open = keyspan_open,
.close = keyspan_close,
.dtr_rts = keyspan_dtr_rts,
.write = keyspan_write,
.write_room = keyspan_write_room,
.set_termios = keyspan_set_termios,
@ -602,6 +603,7 @@ static struct usb_serial_driver keyspan_4port_device = {
.num_ports = 4,
.open = keyspan_open,
.close = keyspan_close,
.dtr_rts = keyspan_dtr_rts,
.write = keyspan_write,
.write_room = keyspan_write_room,
.set_termios = keyspan_set_termios,

View File

@ -651,6 +651,35 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
}
static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
if (serial->dev) {
if (on)
keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2));
else
keyspan_pda_set_modem_info(serial, 0);
}
}
static int keyspan_pda_carrier_raised(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
unsigned char modembits;
/* If we can read the modem status and the DCD is low then
carrier is not raised yet */
if (keyspan_pda_get_modem_info(serial, &modembits) >= 0) {
if (!(modembits & (1>>6)))
return 0;
}
/* Carrier raised, or we failed (eg disconnected) so
progress accordingly */
return 1;
}
static int keyspan_pda_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
@ -682,13 +711,6 @@ static int keyspan_pda_open(struct tty_struct *tty,
priv->tx_room = room;
priv->tx_throttled = room ? 0 : 1;
/* the normal serial device seems to always turn on DTR and RTS here,
so do the same */
if (tty && (tty->termios->c_cflag & CBAUD))
keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2));
else
keyspan_pda_set_modem_info(serial, 0);
/*Start reading from the device*/
port->interrupt_in_urb->dev = serial->dev;
rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
@ -700,19 +722,11 @@ static int keyspan_pda_open(struct tty_struct *tty,
error:
return rc;
}
static void keyspan_pda_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void keyspan_pda_close(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
if (serial->dev) {
/* the normal serial device seems to always shut
off DTR and RTS now */
if (tty->termios->c_cflag & HUPCL)
keyspan_pda_set_modem_info(serial, 0);
/* shutdown our bulk reads and writes */
usb_kill_urb(port->write_urb);
usb_kill_urb(port->interrupt_in_urb);
@ -839,6 +853,8 @@ static struct usb_serial_driver keyspan_pda_device = {
.usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
.num_ports = 1,
.dtr_rts = keyspan_pda_dtr_rts,
.carrier_raised = keyspan_pda_carrier_raised,
.open = keyspan_pda_open,
.close = keyspan_pda_close,
.write = keyspan_pda_write,

View File

@ -76,8 +76,7 @@ static int klsi_105_startup(struct usb_serial *serial);
static void klsi_105_shutdown(struct usb_serial *serial);
static int klsi_105_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void klsi_105_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void klsi_105_close(struct usb_serial_port *port);
static int klsi_105_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
static void klsi_105_write_bulk_callback(struct urb *urb);
@ -447,8 +446,7 @@ exit:
} /* klsi_105_open */
static void klsi_105_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void klsi_105_close(struct usb_serial_port *port)
{
struct klsi_105_private *priv = usb_get_serial_port_data(port);
int rc;

View File

@ -72,8 +72,7 @@ static int kobil_startup(struct usb_serial *serial);
static void kobil_shutdown(struct usb_serial *serial);
static int kobil_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void kobil_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void kobil_close(struct usb_serial_port *port);
static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int kobil_write_room(struct tty_struct *tty);
@ -209,7 +208,7 @@ static void kobil_shutdown(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
while (serial->port[i]->port.count > 0)
kobil_close(NULL, serial->port[i], NULL);
kobil_close(serial->port[i]);
kfree(usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
}
@ -346,11 +345,11 @@ static int kobil_open(struct tty_struct *tty,
}
static void kobil_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void kobil_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
/* FIXME: Add rts/dtr methods */
if (port->write_urb) {
usb_kill_urb(port->write_urb);
usb_free_urb(port->write_urb);

View File

@ -95,8 +95,8 @@ static int mct_u232_startup(struct usb_serial *serial);
static void mct_u232_shutdown(struct usb_serial *serial);
static int mct_u232_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void mct_u232_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void mct_u232_close(struct usb_serial_port *port);
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on);
static void mct_u232_read_int_callback(struct urb *urb);
static void mct_u232_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
@ -140,6 +140,7 @@ static struct usb_serial_driver mct_u232_device = {
.num_ports = 1,
.open = mct_u232_open,
.close = mct_u232_close,
.dtr_rts = mct_u232_dtr_rts,
.throttle = mct_u232_throttle,
.unthrottle = mct_u232_unthrottle,
.read_int_callback = mct_u232_read_int_callback,
@ -496,29 +497,29 @@ error:
return retval;
} /* mct_u232_open */
static void mct_u232_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
{
unsigned int c_cflag;
unsigned int control_state;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
dbg("%s port %d", __func__, port->number);
if (tty) {
c_cflag = tty->termios->c_cflag;
mutex_lock(&port->serial->disc_mutex);
if (c_cflag & HUPCL && !port->serial->disconnected) {
/* drop DTR and RTS */
spin_lock_irq(&priv->lock);
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* drop DTR and RTS */
spin_lock_irq(&priv->lock);
if (on)
priv->control_state |= TIOCM_DTR | TIOCM_RTS;
else
priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
control_state = priv->control_state;
spin_unlock_irq(&priv->lock);
mct_u232_set_modem_ctrl(port->serial, control_state);
}
mutex_unlock(&port->serial->disc_mutex);
control_state = priv->control_state;
spin_unlock_irq(&priv->lock);
mct_u232_set_modem_ctrl(port->serial, control_state);
}
mutex_unlock(&port->serial->disc_mutex);
}
static void mct_u232_close(struct usb_serial_port *port)
{
dbg("%s port %d", __func__, port->number);
if (port->serial->dev) {
/* shutdown our urbs */

View File

@ -533,8 +533,7 @@ static int mos7720_chars_in_buffer(struct tty_struct *tty)
return chars;
}
static void mos7720_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void mos7720_close(struct usb_serial_port *port)
{
struct usb_serial *serial;
struct moschip_port *mos7720_port;

View File

@ -1135,54 +1135,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
}
/************************************************************************
*
* mos7840_block_until_tx_empty
*
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The mos7840 has stopped
* 3. A timeout of 3 seconds without activity has expired
*
************************************************************************/
static void mos7840_block_until_tx_empty(struct tty_struct *tty,
struct moschip_port *mos7840_port)
{
int timeout = HZ / 10;
int wait = 30;
int count;
while (1) {
count = mos7840_chars_in_buffer(tty);
/* Check for Buffer status */
if (count <= 0)
return;
/* Block the thread for a while */
interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
timeout);
/* No activity.. count down section */
wait--;
if (wait == 0) {
dbg("%s - TIMEOUT", __func__);
return;
} else {
/* Reset timeout value back to seconds */
wait = 30;
}
}
}
/*****************************************************************************
* mos7840_close
* this function is called by the tty driver when a port is closed
*****************************************************************************/
static void mos7840_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void mos7840_close(struct usb_serial_port *port)
{
struct usb_serial *serial;
struct moschip_port *mos7840_port;
@ -1223,10 +1181,6 @@ static void mos7840_close(struct tty_struct *tty,
}
}
if (serial->dev)
/* flush and block until tx is empty */
mos7840_block_until_tx_empty(tty, mos7840_port);
/* While closing port, shutdown all bulk read, write *
* and interrupt read if they exists */
if (serial->dev) {

View File

@ -98,8 +98,7 @@ static int navman_open(struct tty_struct *tty,
return result;
}
static void navman_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void navman_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);

View File

@ -66,8 +66,7 @@ static int debug;
/* function prototypes */
static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void omninet_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void omninet_close(struct usb_serial_port *port);
static void omninet_read_bulk_callback(struct urb *urb);
static void omninet_write_bulk_callback(struct urb *urb);
static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
@ -189,8 +188,7 @@ static int omninet_open(struct tty_struct *tty,
return result;
}
static void omninet_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void omninet_close(struct usb_serial_port *port)
{
dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);

View File

@ -173,8 +173,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port,
return result;
}
static void opticon_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void opticon_close(struct usb_serial_port *port)
{
struct opticon_private *priv = usb_get_serial_data(port->serial);

View File

@ -45,8 +45,9 @@
/* Function prototypes */
static int option_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void option_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void option_close(struct usb_serial_port *port);
static void option_dtr_rts(struct usb_serial_port *port, int on);
static int option_startup(struct usb_serial *serial);
static void option_shutdown(struct usb_serial *serial);
static int option_write_room(struct tty_struct *tty);
@ -61,7 +62,7 @@ static void option_set_termios(struct tty_struct *tty,
static int option_tiocmget(struct tty_struct *tty, struct file *file);
static int option_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
static int option_send_setup(struct usb_serial_port *port);
static int option_suspend(struct usb_serial *serial, pm_message_t message);
static int option_resume(struct usb_serial *serial);
@ -551,6 +552,7 @@ static struct usb_serial_driver option_1port_device = {
.num_ports = 1,
.open = option_open,
.close = option_close,
.dtr_rts = option_dtr_rts,
.write = option_write,
.write_room = option_write_room,
.chars_in_buffer = option_chars_in_buffer,
@ -630,7 +632,7 @@ static void option_set_termios(struct tty_struct *tty,
dbg("%s", __func__);
/* Doesn't support option setting */
tty_termios_copy_hw(tty->termios, old_termios);
option_send_setup(tty, port);
option_send_setup(port);
}
static int option_tiocmget(struct tty_struct *tty, struct file *file)
@ -669,7 +671,7 @@ static int option_tiocmset(struct tty_struct *tty, struct file *file,
portdata->rts_state = 0;
if (clear & TIOCM_DTR)
portdata->dtr_state = 0;
return option_send_setup(tty, port);
return option_send_setup(port);
}
/* Write */
@ -897,10 +899,6 @@ static int option_open(struct tty_struct *tty,
dbg("%s", __func__);
/* Set some sane defaults */
portdata->rts_state = 1;
portdata->dtr_state = 1;
/* Reset low level data toggle and start reading from endpoints */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
@ -936,13 +934,28 @@ static int option_open(struct tty_struct *tty,
usb_pipeout(urb->pipe), 0); */
}
option_send_setup(tty, port);
option_send_setup(port);
return 0;
}
static void option_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void option_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
mutex_lock(&serial->disc_mutex);
portdata->rts_state = on;
portdata->dtr_state = on;
if (serial->dev)
option_send_setup(port);
mutex_unlock(&serial->disc_mutex);
}
static void option_close(struct usb_serial_port *port)
{
int i;
struct usb_serial *serial = port->serial;
@ -951,22 +964,13 @@ static void option_close(struct tty_struct *tty,
dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
portdata->dtr_state = 0;
if (serial->dev) {
mutex_lock(&serial->disc_mutex);
if (!serial->disconnected)
option_send_setup(tty, port);
mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
usb_kill_urb(portdata->in_urbs[i]);
for (i = 0; i < N_OUT_URB; i++)
usb_kill_urb(portdata->out_urbs[i]);
}
tty_port_tty_set(&port->port, NULL);
}
/* Helper functions used by option_setup_urbs */
@ -1032,28 +1036,24 @@ static void option_setup_urbs(struct usb_serial *serial)
* This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN
* CDC.
*/
static int option_send_setup(struct tty_struct *tty,
struct usb_serial_port *port)
static int option_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct option_port_private *portdata;
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
if (tty) {
int val = 0;
if (portdata->dtr_state)
val |= 0x01;
if (portdata->rts_state)
val |= 0x02;
if (portdata->dtr_state)
val |= 0x01;
if (portdata->rts_state)
val |= 0x02;
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
return 0;
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
static int option_startup(struct usb_serial *serial)

View File

@ -143,8 +143,7 @@ struct oti6858_control_pkt {
/* function prototypes */
static int oti6858_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void oti6858_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void oti6858_close(struct usb_serial_port *port);
static void oti6858_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
@ -622,67 +621,30 @@ static int oti6858_open(struct tty_struct *tty,
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result);
oti6858_close(tty, port, NULL);
oti6858_close(port);
return -EPROTO;
}
/* setup termios */
if (tty)
oti6858_set_termios(tty, port, &tmp_termios);
port->port.drain_delay = 256; /* FIXME: check the FIFO length */
return 0;
}
static void oti6858_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void oti6858_close(struct usb_serial_port *port)
{
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
long timeout;
wait_queue_t wait;
dbg("%s(port = %d)", __func__, port->number);
/* wait for data to drain from the buffer */
spin_lock_irqsave(&priv->lock, flags);
timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
dbg("%s(): entering wait loop", __func__);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (oti6858_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
|| port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
spin_lock_irqsave(&priv->lock, flags);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
dbg("%s(): after wait loop", __func__);
/* clear out any remaining data in the buffer */
oti6858_buf_clear(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
/* wait for characters to drain from the device */
/* (this is long enough for the entire 256 byte */
/* pl2303 hardware buffer to drain with no flow */
/* control for data rates of 1200 bps or more, */
/* for lower rates we should really know how much */
/* data is in the buffer to compute a delay */
/* that is not unnecessarily long) */
/* FIXME
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ*2560)/bps,HZ/10);
else
*/
timeout = 2*HZ;
schedule_timeout_interruptible(timeout);
dbg("%s(): after schedule_timeout_interruptible()", __func__);
dbg("%s(): after buf_clear()", __func__);
/* cancel scheduled setup */
cancel_delayed_work(&priv->delayed_setup_work);
@ -694,15 +656,6 @@ static void oti6858_close(struct tty_struct *tty,
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
/*
if (tty && (tty->termios->c_cflag) & HUPCL) {
// drop DTR and RTS
spin_lock_irqsave(&priv->lock, flags);
priv->pending_setup.control &= ~CONTROL_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
}
*/
}
static int oti6858_tiocmset(struct tty_struct *tty, struct file *file,

View File

@ -652,69 +652,41 @@ static void pl2303_set_termios(struct tty_struct *tty,
kfree(buf);
}
static void pl2303_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
spin_lock_irqsave(&priv->lock, flags);
/* Change DTR and RTS */
if (on)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
else
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines(port->serial->dev, control);
}
static void pl2303_close(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
int bps;
long timeout;
wait_queue_t wait;
dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from the buffer */
spin_lock_irqsave(&priv->lock, flags);
timeout = PL2303_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (pl2303_buf_data_avail(priv->buf) == 0 ||
timeout == 0 || signal_pending(current) ||
port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
spin_lock_irqsave(&priv->lock, flags);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
pl2303_buf_clear(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
/* wait for characters to drain from the device */
/* (this is long enough for the entire 256 byte */
/* pl2303 hardware buffer to drain with no flow */
/* control for data rates of 1200 bps or more, */
/* for lower rates we should really know how much */
/* data is in the buffer to compute a delay */
/* that is not unnecessarily long) */
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ*2560)/bps, HZ/10);
else
timeout = 2*HZ;
schedule_timeout_interruptible(timeout);
/* shutdown our urbs */
dbg("%s - shutting down urbs", __func__);
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
set_control_lines(port->serial->dev, 0);
}
}
}
static int pl2303_open(struct tty_struct *tty,
@ -748,7 +720,7 @@ static int pl2303_open(struct tty_struct *tty,
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb,"
" error %d\n", __func__, result);
pl2303_close(tty, port, NULL);
pl2303_close(port);
return -EPROTO;
}
@ -758,9 +730,10 @@ static int pl2303_open(struct tty_struct *tty,
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
" error %d\n", __func__, result);
pl2303_close(tty, port, NULL);
pl2303_close(port);
return -EPROTO;
}
port->port.drain_delay = 256;
return 0;
}
@ -821,6 +794,14 @@ static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
return result;
}
static int pl2303_carrier_raised(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & UART_DCD)
return 1;
return 0;
}
static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
@ -1125,6 +1106,8 @@ static struct usb_serial_driver pl2303_device = {
.num_ports = 1,
.open = pl2303_open,
.close = pl2303_close,
.dtr_rts = pl2303_dtr_rts,
.carrier_raised = pl2303_carrier_raised,
.write = pl2303_write,
.ioctl = pl2303_ioctl,
.break_ctl = pl2303_break_ctl,

View File

@ -26,12 +26,10 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/usb/ch9.h>
#define SWIMS_USB_REQUEST_SetPower 0x00
#define SWIMS_USB_REQUEST_SetNmea 0x07
/* per port private data */
#define N_IN_URB 4
#define N_OUT_URB 4
#define IN_BUFLEN 4096
@ -39,6 +37,12 @@
static int debug;
static int nmea;
/* Used in interface blacklisting */
struct sierra_iface_info {
const u32 infolen; /* number of interface numbers on blacklist */
const u8 *ifaceinfo; /* pointer to the array holding the numbers */
};
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
{
int result;
@ -85,6 +89,23 @@ static int sierra_calc_num_ports(struct usb_serial *serial)
return result;
}
static int is_blacklisted(const u8 ifnum,
const struct sierra_iface_info *blacklist)
{
const u8 *info;
int i;
if (blacklist) {
info = blacklist->ifaceinfo;
for (i = 0; i < blacklist->infolen; i++) {
if (info[i] == ifnum)
return 1;
}
}
return 0;
}
static int sierra_calc_interface(struct usb_serial *serial)
{
int interface;
@ -153,9 +174,25 @@ static int sierra_probe(struct usb_serial *serial,
*/
usb_set_serial_data(serial, (void *)num_ports);
/* ifnum could have changed - by calling usb_set_interface */
ifnum = sierra_calc_interface(serial);
if (is_blacklisted(ifnum,
(struct sierra_iface_info *)id->driver_info)) {
dev_dbg(&serial->dev->dev,
"Ignoring blacklisted interface #%d\n", ifnum);
return -ENODEV;
}
return result;
}
static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
static const struct sierra_iface_info direct_ip_interface_blacklist = {
.infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces),
.ifaceinfo = direct_ip_non_serial_ifaces,
};
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
@ -188,9 +225,11 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
{ USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
{ USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
{ USB_DEVICE(0x1199, 0x683C) }, /* Sierra Wireless MC8790 */
{ USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8790 */
{ USB_DEVICE(0x1199, 0x683E) }, /* Sierra Wireless MC8790 */
/* Sierra Wireless MC8790, MC8791, MC8792 Composite */
{ USB_DEVICE(0x1199, 0x683C) },
{ USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */
/* Sierra Wireless MC8790, MC8791, MC8792 */
{ USB_DEVICE(0x1199, 0x683E) },
{ USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
{ USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
{ USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
@ -211,6 +250,10 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
{ USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
@ -229,7 +272,6 @@ struct sierra_port_private {
/* Input endpoints and buffers for this port */
struct urb *in_urbs[N_IN_URB];
char *in_buffer[N_IN_URB];
/* Settings for the port */
int rts_state; /* Handshaking pins (outputs) */
@ -240,57 +282,50 @@ struct sierra_port_private {
int ri_state;
};
static int sierra_send_setup(struct tty_struct *tty,
struct usb_serial_port *port)
static int sierra_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
__u16 interface = 0;
int val = 0;
dev_dbg(&port->dev, "%s", __func__);
portdata = usb_get_serial_port_data(port);
if (tty) {
int val = 0;
if (portdata->dtr_state)
val |= 0x01;
if (portdata->rts_state)
val |= 0x02;
/* If composite device then properly report interface */
if (serial->num_ports == 1) {
interface = sierra_calc_interface(serial);
/* Control message is sent only to interfaces with
* interrupt_in endpoints
*/
if (port->interrupt_in_urb) {
/* send control message */
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22, 0x21, val, interface,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
}
/* Otherwise the need to do non-composite mapping */
else {
if (port->bulk_out_endpointAddress == 2)
interface = 0;
else if (port->bulk_out_endpointAddress == 4)
interface = 1;
else if (port->bulk_out_endpointAddress == 5)
interface = 2;
if (portdata->dtr_state)
val |= 0x01;
if (portdata->rts_state)
val |= 0x02;
/* If composite device then properly report interface */
if (serial->num_ports == 1) {
interface = sierra_calc_interface(serial);
/* Control message is sent only to interfaces with
* interrupt_in endpoints
*/
if (port->interrupt_in_urb) {
/* send control message */
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22, 0x21, val, interface,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
}
/* Otherwise the need to do non-composite mapping */
else {
if (port->bulk_out_endpointAddress == 2)
interface = 0;
else if (port->bulk_out_endpointAddress == 4)
interface = 1;
else if (port->bulk_out_endpointAddress == 5)
interface = 2;
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
0x22, 0x21, val, interface,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
return 0;
}
@ -299,7 +334,7 @@ static void sierra_set_termios(struct tty_struct *tty,
{
dev_dbg(&port->dev, "%s", __func__);
tty_termios_copy_hw(tty->termios, old_termios);
sierra_send_setup(tty, port);
sierra_send_setup(port);
}
static int sierra_tiocmget(struct tty_struct *tty, struct file *file)
@ -338,7 +373,18 @@ static int sierra_tiocmset(struct tty_struct *tty, struct file *file,
portdata->rts_state = 0;
if (clear & TIOCM_DTR)
portdata->dtr_state = 0;
return sierra_send_setup(tty, port);
return sierra_send_setup(port);
}
static void sierra_release_urb(struct urb *urb)
{
struct usb_serial_port *port;
if (urb) {
port = urb->context;
dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
}
static void sierra_outdat_callback(struct urb *urb)
@ -465,7 +511,7 @@ static void sierra_indat_callback(struct urb *urb)
" received", __func__);
/* Resubmit urb so we continue receiving */
if (port->port.count && status != -ESHUTDOWN) {
if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
dev_err(&port->dev, "resubmit read urb failed."
@ -557,14 +603,129 @@ static int sierra_write_room(struct tty_struct *tty)
return 2048;
}
static void sierra_stop_rx_urbs(struct usb_serial_port *port)
{
int i;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++)
usb_kill_urb(portdata->in_urbs[i]);
usb_kill_urb(port->interrupt_in_urb);
}
static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags)
{
int ok_cnt;
int err = -EINVAL;
int i;
struct urb *urb;
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
ok_cnt = 0;
for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
urb = portdata->in_urbs[i];
if (!urb)
continue;
err = usb_submit_urb(urb, mem_flags);
if (err) {
dev_err(&port->dev, "%s: submit urb failed: %d\n",
__func__, err);
} else {
ok_cnt++;
}
}
if (ok_cnt && port->interrupt_in_urb) {
err = usb_submit_urb(port->interrupt_in_urb, mem_flags);
if (err) {
dev_err(&port->dev, "%s: submit intr urb failed: %d\n",
__func__, err);
}
}
if (ok_cnt > 0) /* at least one rx urb submitted */
return 0;
else
return err;
}
static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
int dir, void *ctx, int len,
gfp_t mem_flags,
usb_complete_t callback)
{
struct urb *urb;
u8 *buf;
if (endpoint == -1)
return NULL;
urb = usb_alloc_urb(0, mem_flags);
if (urb == NULL) {
dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n",
__func__, endpoint);
return NULL;
}
buf = kmalloc(len, mem_flags);
if (buf) {
/* Fill URB using supplied data */
usb_fill_bulk_urb(urb, serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx);
/* debug */
dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,
dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
} else {
dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__,
dir == USB_DIR_IN ? 'i' : 'o', urb, buf);
sierra_release_urb(urb);
urb = NULL;
}
return urb;
}
static void sierra_close(struct usb_serial_port *port)
{
int i;
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
dev_dbg(&port->dev, "%s\n", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
portdata->dtr_state = 0;
if (serial->dev) {
mutex_lock(&serial->disc_mutex);
if (!serial->disconnected)
sierra_send_setup(port);
mutex_unlock(&serial->disc_mutex);
/* Stop reading urbs */
sierra_stop_rx_urbs(port);
/* .. and release them */
for (i = 0; i < N_IN_URB; i++) {
sierra_release_urb(portdata->in_urbs[i]);
portdata->in_urbs[i] = NULL;
}
}
}
static int sierra_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
{
struct sierra_port_private *portdata;
struct usb_serial *serial = port->serial;
int i;
int err;
int endpoint;
struct urb *urb;
int result;
portdata = usb_get_serial_port_data(port);
@ -574,77 +735,52 @@ static int sierra_open(struct tty_struct *tty,
portdata->rts_state = 1;
portdata->dtr_state = 1;
/* Reset low level data toggle and start reading from endpoints */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
if (!urb)
continue;
if (urb->dev != serial->dev) {
dev_dbg(&port->dev, "%s: dev %p != %p",
__func__, urb->dev, serial->dev);
continue;
}
/*
* make sure endpoint data toggle is synchronized with the
* device
*/
usb_clear_halt(urb->dev, urb->pipe);
result = usb_submit_urb(urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
i, result, urb->transfer_buffer_length);
}
endpoint = port->bulk_in_endpointAddress;
for (i = 0; i < ARRAY_SIZE(portdata->in_urbs); i++) {
urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
IN_BUFLEN, GFP_KERNEL,
sierra_indat_callback);
portdata->in_urbs[i] = urb;
}
/* clear halt condition */
usb_clear_halt(serial->dev,
usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
sierra_send_setup(tty, port);
/* start up the interrupt endpoint if we have one */
if (port->interrupt_in_urb) {
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev, "submit irq_in urb failed %d\n",
result);
err = sierra_submit_rx_urbs(port, GFP_KERNEL);
if (err) {
/* get rid of everything as in close */
sierra_close(port);
return err;
}
sierra_send_setup(port);
return 0;
}
static void sierra_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void sierra_dtr_rts(struct usb_serial_port *port, int on)
{
int i;
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
dev_dbg(&port->dev, "%s", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
portdata->dtr_state = 0;
portdata->rts_state = on;
portdata->dtr_state = on;
if (serial->dev) {
mutex_lock(&serial->disc_mutex);
if (!serial->disconnected)
sierra_send_setup(tty, port);
sierra_send_setup(port);
mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
usb_kill_urb(portdata->in_urbs[i]);
}
usb_kill_urb(port->interrupt_in_urb);
tty_port_tty_set(&port->port, NULL);
}
static int sierra_startup(struct usb_serial *serial)
{
struct usb_serial_port *port;
struct sierra_port_private *portdata;
struct urb *urb;
int i;
int j;
dev_dbg(&serial->dev->dev, "%s", __func__);
@ -666,34 +802,8 @@ static int sierra_startup(struct usb_serial *serial)
return -ENOMEM;
}
spin_lock_init(&portdata->lock);
for (j = 0; j < N_IN_URB; j++) {
portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL);
if (!portdata->in_buffer[j]) {
for (--j; j >= 0; j--)
kfree(portdata->in_buffer[j]);
kfree(portdata);
return -ENOMEM;
}
}
/* Set the port private data pointer */
usb_set_serial_port_data(port, portdata);
/* initialize the in urbs */
for (j = 0; j < N_IN_URB; ++j) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL) {
dev_dbg(&port->dev, "%s: alloc for in "
"port failed.", __func__);
continue;
}
/* Fill URB using supplied data. */
usb_fill_bulk_urb(urb, serial->dev,
usb_rcvbulkpipe(serial->dev,
port->bulk_in_endpointAddress),
portdata->in_buffer[j], IN_BUFLEN,
sierra_indat_callback, port);
portdata->in_urbs[j] = urb;
}
}
return 0;
@ -701,7 +811,7 @@ static int sierra_startup(struct usb_serial *serial)
static void sierra_shutdown(struct usb_serial *serial)
{
int i, j;
int i;
struct usb_serial_port *port;
struct sierra_port_private *portdata;
@ -714,12 +824,6 @@ static void sierra_shutdown(struct usb_serial *serial)
portdata = usb_get_serial_port_data(port);
if (!portdata)
continue;
for (j = 0; j < N_IN_URB; j++) {
usb_kill_urb(portdata->in_urbs[j]);
usb_free_urb(portdata->in_urbs[j]);
kfree(portdata->in_buffer[j]);
}
kfree(portdata);
usb_set_serial_port_data(port, NULL);
}
@ -737,6 +841,7 @@ static struct usb_serial_driver sierra_device = {
.probe = sierra_probe,
.open = sierra_open,
.close = sierra_close,
.dtr_rts = sierra_dtr_rts,
.write = sierra_write,
.write_room = sierra_write_room,
.set_termios = sierra_set_termios,

View File

@ -446,66 +446,47 @@ static void spcp8x5_set_workMode(struct usb_device *dev, u16 value,
"RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret);
}
/* close the serial port. We should wait for data sending to device 1st and
* then kill all urb. */
static void spcp8x5_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static int spcp8x5_carrier_raised(struct usb_serial_port *port)
{
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
if (priv->line_status & MSR_STATUS_LINE_DCD)
return 1;
return 0;
}
static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
{
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
spin_lock_irqsave(&priv->lock, flags);
if (on)
priv->line_control = MCR_CONTROL_LINE_DTR
| MCR_CONTROL_LINE_RTS;
else
priv->line_control &= ~ (MCR_CONTROL_LINE_DTR
| MCR_CONTROL_LINE_RTS);
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type);
}
/* close the serial port. We should wait for data sending to device 1st and
* then kill all urb. */
static void spcp8x5_close(struct usb_serial_port *port)
{
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int c_cflag;
int bps;
long timeout;
wait_queue_t wait;
int result;
dbg("%s - port %d", __func__, port->number);
/* wait for data to drain from the buffer */
spin_lock_irqsave(&priv->lock, flags);
timeout = SPCP8x5_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&tty->write_wait, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (ringbuf_avail_data(priv->buf) == 0 ||
timeout == 0 || signal_pending(current))
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
spin_lock_irqsave(&priv->lock, flags);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
clear_ringbuf(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
/* wait for characters to drain from the device (this is long enough
* for the entire all byte spcp8x5 hardware buffer to drain with no
* flow control for data rates of 1200 bps or more, for lower rates we
* should really know how much data is in the buffer to compute a delay
* that is not unnecessarily long) */
bps = tty_get_baud_rate(tty);
if (bps > 1200)
timeout = max((HZ*2560) / bps, HZ/10);
else
timeout = 2*HZ;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(timeout);
/* clear control lines */
if (tty) {
c_cflag = tty->termios->c_cflag;
if (c_cflag & HUPCL) {
spin_lock_irqsave(&priv->lock, flags);
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
spcp8x5_set_ctrlLine(port->serial->dev, 0 , priv->type);
}
}
/* kill urb */
if (port->write_urb != NULL) {
result = usb_unlink_urb(port->write_urb);
@ -665,13 +646,6 @@ static int spcp8x5_open(struct tty_struct *tty,
if (ret)
return ret;
spin_lock_irqsave(&priv->lock, flags);
if (tty && (tty->termios->c_cflag & CBAUD))
priv->line_control = MCR_DTR | MCR_RTS;
else
priv->line_control = 0;
spin_unlock_irqrestore(&priv->lock, flags);
spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type);
/* Setup termios */
@ -691,9 +665,10 @@ static int spcp8x5_open(struct tty_struct *tty,
port->read_urb->dev = serial->dev;
ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (ret) {
spcp8x5_close(tty, port, NULL);
spcp8x5_close(port);
return -EPROTO;
}
port->port.drain_delay = 256;
return 0;
}
@ -1033,6 +1008,8 @@ static struct usb_serial_driver spcp8x5_device = {
.num_ports = 1,
.open = spcp8x5_open,
.close = spcp8x5_close,
.dtr_rts = spcp8x5_dtr_rts,
.carrier_raised = spcp8x5_carrier_raised,
.write = spcp8x5_write,
.set_termios = spcp8x5_set_termios,
.ioctl = spcp8x5_ioctl,

View File

@ -152,8 +152,7 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port,
return result;
}
static void symbol_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp)
static void symbol_close(struct usb_serial_port *port)
{
struct symbol_private *priv = usb_get_serial_data(port->serial);

View File

@ -100,8 +100,7 @@ static int ti_startup(struct usb_serial *serial);
static void ti_shutdown(struct usb_serial *serial);
static int ti_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *file);
static void ti_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *file);
static void ti_close(struct usb_serial_port *port);
static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
static int ti_write_room(struct tty_struct *tty);
@ -647,8 +646,7 @@ release_lock:
}
static void ti_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *file)
static void ti_close(struct usb_serial_port *port)
{
struct ti_device *tdev;
struct ti_port *tport;

View File

@ -238,9 +238,11 @@ static int serial_open (struct tty_struct *tty, struct file *filp)
goto bailout_interface_put;
mutex_unlock(&serial->disc_mutex);
}
mutex_unlock(&port->mutex);
return 0;
/* Now do the correct tty layer semantics */
retval = tty_port_block_til_ready(&port->port, tty, filp);
if (retval == 0)
return 0;
bailout_interface_put:
usb_autopm_put_interface(serial->interface);
@ -259,64 +261,89 @@ bailout_serial_put:
return retval;
}
static void serial_close(struct tty_struct *tty, struct file *filp)
/**
* serial_do_down - shut down hardware
* @port: port to shut down
*
* Shut down a USB port unless it is the console. We never shut down the
* console hardware as it will always be in use.
*
* Don't free any resources at this point
*/
static void serial_do_down(struct usb_serial_port *port)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial_driver *drv = port->serial->type;
struct usb_serial *serial;
struct module *owner;
int count;
if (!port)
/* The console is magical, do not hang up the console hardware
or there will be tears */
if (port->console)
return;
dbg("%s - port %d", __func__, port->number);
mutex_lock(&port->mutex);
serial = port->serial;
owner = serial->type->driver.owner;
if (port->port.count == 0) {
mutex_unlock(&port->mutex);
return;
}
if (drv->close)
drv->close(port);
if (port->port.count == 1)
/* only call the device specific close if this
* port is being closed by the last owner. Ensure we do
* this before we drop the port count. The call is protected
* by the port mutex
*/
serial->type->close(tty, port, filp);
if (port->port.count == (port->console ? 2 : 1)) {
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) {
/* We must do this before we drop the port count to
zero. */
if (tty->driver_data)
tty->driver_data = NULL;
tty_port_tty_set(&port->port, NULL);
tty_kref_put(tty);
}
}
--port->port.count;
count = port->port.count;
mutex_unlock(&port->mutex);
}
/**
* serial_do_free - free resources post close/hangup
* @port: port to free up
*
* Do the resource freeing and refcount dropping for the port. We must
* be careful about ordering and we must avoid freeing up the console.
*/
static void serial_do_free(struct usb_serial_port *port)
{
struct usb_serial *serial;
struct module *owner;
/* The console is magical, do not hang up the console hardware
or there will be tears */
if (port->console)
return;
serial = port->serial;
owner = serial->type->driver.owner;
put_device(&port->dev);
/* Mustn't dereference port any more */
if (count == 0) {
mutex_lock(&serial->disc_mutex);
if (!serial->disconnected)
usb_autopm_put_interface(serial->interface);
mutex_unlock(&serial->disc_mutex);
}
mutex_lock(&serial->disc_mutex);
if (!serial->disconnected)
usb_autopm_put_interface(serial->interface);
mutex_unlock(&serial->disc_mutex);
usb_serial_put(serial);
/* Mustn't dereference serial any more */
if (count == 0)
module_put(owner);
module_put(owner);
}
static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
dbg("%s - port %d", __func__, port->number);
if (tty_port_close_start(&port->port, tty, filp) == 0)
return;
serial_do_down(port);
tty_port_close_end(&port->port, tty);
tty_port_tty_set(&port->port, NULL);
serial_do_free(port);
}
static void serial_hangup(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
serial_do_down(port);
tty_port_hangup(&port->port);
serial_do_free(port);
}
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
@ -648,6 +675,29 @@ static struct usb_serial_driver *search_serial_device(
return NULL;
}
static int serial_carrier_raised(struct tty_port *port)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
if (drv->carrier_raised)
return drv->carrier_raised(p);
/* No carrier control - don't block */
return 1;
}
static void serial_dtr_rts(struct tty_port *port, int on)
{
struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
struct usb_serial_driver *drv = p->serial->type;
if (drv->dtr_rts)
drv->dtr_rts(p, on);
}
static const struct tty_port_operations serial_port_ops = {
.carrier_raised = serial_carrier_raised,
.dtr_rts = serial_dtr_rts,
};
int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@ -841,6 +891,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (!port)
goto probe_error;
tty_port_init(&port->port);
port->port.ops = &serial_port_ops;
port->serial = serial;
spin_lock_init(&port->lock);
mutex_init(&port->mutex);
@ -1071,6 +1122,9 @@ void usb_serial_disconnect(struct usb_interface *interface)
if (port) {
struct tty_struct *tty = tty_port_tty_get(&port->port);
if (tty) {
/* The hangup will occur asynchronously but
the object refcounts will sort out all the
cleanup */
tty_hangup(tty);
tty_kref_put(tty);
}
@ -1135,6 +1189,7 @@ static const struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
.write = serial_write,
.hangup = serial_hangup,
.write_room = serial_write_room,
.ioctl = serial_ioctl,
.set_termios = serial_set_termios,
@ -1147,6 +1202,7 @@ static const struct tty_operations serial_ops = {
.proc_fops = &serial_proc_fops,
};
struct tty_driver *usb_serial_tty_driver;
static int __init usb_serial_init(void)

View File

@ -38,8 +38,7 @@
/* function prototypes for a handspring visor */
static int visor_open(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void visor_close(struct tty_struct *tty, struct usb_serial_port *port,
struct file *filp);
static void visor_close(struct usb_serial_port *port);
static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
static int visor_write_room(struct tty_struct *tty);
@ -324,8 +323,7 @@ exit:
}
static void visor_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void visor_close(struct usb_serial_port *port)
{
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned char *transfer_buffer;

View File

@ -147,8 +147,7 @@ static int whiteheat_attach(struct usb_serial *serial);
static void whiteheat_shutdown(struct usb_serial *serial);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void whiteheat_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
static void whiteheat_close(struct usb_serial_port *port);
static int whiteheat_write(struct tty_struct *tty,
struct usb_serial_port *port,
const unsigned char *buf, int count);
@ -712,8 +711,7 @@ exit:
}
static void whiteheat_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp)
static void whiteheat_close(struct usb_serial_port *port)
{
struct whiteheat_private *info = usb_get_serial_port_data(port);
struct whiteheat_urb_wrap *wrap;
@ -723,31 +721,7 @@ static void whiteheat_close(struct tty_struct *tty,
dbg("%s - port %d", __func__, port->number);
mutex_lock(&port->serial->disc_mutex);
/* filp is NULL when called from usb_serial_disconnect */
if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
mutex_unlock(&port->serial->disc_mutex);
return;
}
mutex_unlock(&port->serial->disc_mutex);
tty->closing = 1;
/*
* Not currently in use; tty_wait_until_sent() calls
* serial_chars_in_buffer() which deadlocks on the second semaphore
* acquisition. This should be fixed at some point. Greg's been
* notified.
if ((filp->f_flags & (O_NDELAY | O_NONBLOCK)) == 0) {
tty_wait_until_sent(tty, CLOSING_DELAY);
}
*/
tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
firm_report_tx_done(port);
firm_close(port);
/* shutdown our bulk reads and writes */
@ -775,10 +749,7 @@ static void whiteheat_close(struct tty_struct *tty,
}
spin_unlock_irq(&info->lock);
mutex_unlock(&info->deathwarrant);
stop_command_port(port->serial);
tty->closing = 0;
}

View File

@ -557,8 +557,10 @@ static int __init init_devpts_fs(void)
int err = register_filesystem(&devpts_fs_type);
if (!err) {
devpts_mnt = kern_mount(&devpts_fs_type);
if (IS_ERR(devpts_mnt))
if (IS_ERR(devpts_mnt)) {
err = PTR_ERR(devpts_mnt);
unregister_filesystem(&devpts_fs_type);
}
}
return err;
}

View File

@ -142,19 +142,6 @@ struct CYZ_BOOT_CTRL {
#ifndef DP_WINDOW_SIZE
/* #include "cyclomz.h" */
/****************** ****************** *******************/
/*
* The data types defined below are used in all ZFIRM interface
* data structures. They accomodate differences between HW
* architectures and compilers.
*/
typedef __u64 ucdouble; /* 64 bits, unsigned */
typedef __u32 uclong; /* 32 bits, unsigned */
typedef __u16 ucshort; /* 16 bits, unsigned */
typedef __u8 ucchar; /* 8 bits, unsigned */
/*
* Memory Window Sizes
*/
@ -507,16 +494,20 @@ struct ZFW_CTRL {
/* Per card data structure */
struct cyclades_card {
void __iomem *base_addr;
void __iomem *ctl_addr;
int irq;
unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */
unsigned int first_line; /* minor number of first channel on card */
unsigned int nports; /* Number of ports in the card */
int bus_index; /* address shift - 0 for ISA, 1 for PCI */
int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */
spinlock_t card_lock;
struct cyclades_port *ports;
void __iomem *base_addr;
union {
void __iomem *p9050;
struct RUNTIME_9060 __iomem *p9060;
} ctl_addr;
int irq;
unsigned int num_chips; /* 0 if card absent, -1 if Z/PCI, else Y */
unsigned int first_line; /* minor number of first channel on card */
unsigned int nports; /* Number of ports in the card */
int bus_index; /* address shift - 0 for ISA, 1 for PCI */
int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */
u32 hw_ver;
spinlock_t card_lock;
struct cyclades_port *ports;
};
/***************************************

View File

@ -1996,10 +1996,12 @@
#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118
#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C
#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
#define PCI_DEVICE_ID_OXSEMI_C950 0x950B
#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513
#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523
#define PCI_SUBDEVICE_ID_OXSEMI_C950 0x0001
#define PCI_VENDOR_ID_CHELSIO 0x1425

19
include/linux/rational.h Normal file
View File

@ -0,0 +1,19 @@
/*
* rational fractions
*
* Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
*
* helper functions when coping with rational numbers,
* e.g. when calculating optimum numerator/denominator pairs for
* pll configuration taking into account restricted register size
*/
#ifndef _LINUX_RATIONAL_H
#define _LINUX_RATIONAL_H
void rational_best_approximation(
unsigned long given_numerator, unsigned long given_denominator,
unsigned long max_numerator, unsigned long max_denominator,
unsigned long *best_numerator, unsigned long *best_denominator);
#endif /* _LINUX_RATIONAL_H */

View File

@ -96,54 +96,76 @@ struct serial_uart_config {
/*
* Definitions for async_struct (and serial_struct) flags field
*
* Define ASYNCB_* for convenient use with {test,set,clear}_bit.
*/
#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
on the callout port */
#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */
#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes
* on the callout port */
#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */
#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */
#define ASYNCB_SPLIT_TERMIOS 3 /* Separate termios for dialin/callout */
#define ASYNCB_SPD_HI 4 /* Use 56000 instead of 38400 bps */
#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */
#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */
#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during
* autoconfiguration */
#define ASYNCB_SESSION_LOCKOUT 8 /* Lock out cua opens based on session */
#define ASYNCB_PGRP_LOCKOUT 9 /* Lock out cua opens based on pgrp */
#define ASYNCB_CALLOUT_NOHUP 10 /* Don't do hangups for cua device */
#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */
#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */
#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */
#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety
* checks. Note: can be dangerous! */
#define ASYNCB_AUTOPROBE 15 /* Port was autoprobed by PCI or PNP code */
#define ASYNCB_LAST_USER 15
#define ASYNC_SPD_MASK 0x1030
#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
/* Internal flags used only by kernel */
#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */
#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */
#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */
#define ASYNCB_CLOSING 27 /* Serial port is closing */
#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */
#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */
#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */
#define ASYNCB_CONS_FLOW 23 /* flow control for console */
#define ASYNCB_BOOT_ONLYMCA 22 /* Probe only if MCA bus */
#define ASYNCB_FIRST_KERNEL 22
#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */
#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT)
#define ASYNC_SAK (1U << ASYNCB_SAK)
#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS)
#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI)
#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI)
#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST)
#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ)
#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT)
#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT)
#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP)
#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD)
#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI)
#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY)
#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART)
#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE)
#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
#define ASYNC_FLAGS ((1U << ASYNCB_LAST_USER) - 1)
#define ASYNC_USR_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI| \
ASYNC_CALLOUT_NOHUP|ASYNC_SPD_SHI|ASYNC_LOW_LATENCY)
#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI)
#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI)
#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI)
#define ASYNC_HARDPPS_CD 0x0800 /* Call hardpps when CD goes high */
#define ASYNC_SPD_SHI 0x1000 /* Use 230400 instead of 38400 bps */
#define ASYNC_SPD_WARP 0x1010 /* Use 460800 instead of 38400 bps */
#define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
#define ASYNC_BUGGY_UART 0x4000 /* This is a buggy UART, skip some safety
* checks. Note: can be dangerous! */
#define ASYNC_AUTOPROBE 0x8000 /* Port was autoprobed by PCI or PNP code */
#define ASYNC_FLAGS 0x7FFF /* Possible legal async flags */
#define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged
* users can set or reset */
/* Internal flags used only by kernel/chr_drv/serial.c */
#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */
#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define ASYNC_SHARE_IRQ 0x01000000 /* for multifunction cards
--- no longer used */
#define ASYNC_CONS_FLOW 0x00800000 /* flow control for console */
#define ASYNC_BOOT_ONLYMCA 0x00400000 /* Probe only if MCA bus */
#define ASYNC_INTERNAL_FLAGS 0xFFC00000 /* Internal flags */
#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED)
#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE)
#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF)
#define ASYNC_CLOSING (1U << ASYNCB_CLOSING)
#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW)
#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD)
#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ)
#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW)
#define ASYNC_BOOT_ONLYMCA (1U << ASYNCB_BOOT_ONLYMCA)
#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1))
/*
* Multiport serial configuration structure --- external structure

View File

@ -41,7 +41,8 @@
#define PORT_XSCALE 15
#define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */
#define PORT_OCTEON 17 /* Cavium OCTEON internal UART */
#define PORT_MAX_8250 17 /* max port ID */
#define PORT_AR7 18 /* Texas Instruments AR7 internal UART */
#define PORT_MAX_8250 18 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@ -167,6 +168,9 @@
/* MAX3100 */
#define PORT_MAX3100 86
/* Timberdale UART */
#define PORT_TIMBUART 87
#ifdef __KERNEL__
#include <linux/compiler.h>

View File

@ -185,7 +185,7 @@ struct tty_port;
struct tty_port_operations {
/* Return 1 if the carrier is raised */
int (*carrier_raised)(struct tty_port *port);
void (*raise_dtr_rts)(struct tty_port *port);
void (*dtr_rts)(struct tty_port *port, int raise);
};
struct tty_port {
@ -201,6 +201,9 @@ struct tty_port {
unsigned char *xmit_buf; /* Optional buffer */
int close_delay; /* Close port delay */
int closing_wait; /* Delay for output */
int drain_delay; /* Set to zero if no pure time
based drain is needed else
set to size of fifo */
};
/*
@ -223,8 +226,11 @@ struct tty_struct {
struct tty_driver *driver;
const struct tty_operations *ops;
int index;
/* The ldisc objects are protected by tty_ldisc_lock at the moment */
struct tty_ldisc ldisc;
/* Protects ldisc changes: Lock tty not pty */
struct mutex ldisc_mutex;
struct tty_ldisc *ldisc;
struct mutex termios_mutex;
spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */
@ -311,6 +317,7 @@ struct tty_struct {
#define TTY_CLOSING 7 /* ->close() in progress */
#define TTY_LDISC 9 /* Line discipline attached */
#define TTY_LDISC_CHANGING 10 /* Line discipline changing */
#define TTY_LDISC_OPEN 11 /* Line discipline is open */
#define TTY_HW_COOK_OUT 14 /* Hardware can do output cooking */
#define TTY_HW_COOK_IN 15 /* Hardware can do input cooking */
#define TTY_PTY_LOCK 16 /* pty private */
@ -403,6 +410,7 @@ extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b);
extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *);
extern void tty_ldisc_deref(struct tty_ldisc *);
extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *);
extern void tty_ldisc_hangup(struct tty_struct *tty);
extern const struct file_operations tty_ldiscs_proc_fops;
extern void tty_wakeup(struct tty_struct *tty);
@ -425,6 +433,9 @@ extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
extern void tty_release_dev(struct file *filp);
extern int tty_init_termios(struct tty_struct *tty);
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
extern struct mutex tty_mutex;
extern void tty_write_unlock(struct tty_struct *tty);
@ -438,6 +449,7 @@ extern struct tty_struct *tty_port_tty_get(struct tty_port *port);
extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
extern int tty_port_carrier_raised(struct tty_port *port);
extern void tty_port_raise_dtr_rts(struct tty_port *port);
extern void tty_port_lower_dtr_rts(struct tty_port *port);
extern void tty_port_hangup(struct tty_port *port);
extern int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp);

View File

@ -127,7 +127,8 @@
* the line discipline are close to full, and it should somehow
* signal that no more characters should be sent to the tty.
*
* Optional: Always invoke via tty_throttle();
* Optional: Always invoke via tty_throttle(), called under the
* termios lock.
*
* void (*unthrottle)(struct tty_struct * tty);
*
@ -135,7 +136,8 @@
* that characters can now be sent to the tty without fear of
* overrunning the input buffers of the line disciplines.
*
* Optional: Always invoke via tty_unthrottle();
* Optional: Always invoke via tty_unthrottle(), called under the
* termios lock.
*
* void (*stop)(struct tty_struct *tty);
*

View File

@ -224,8 +224,7 @@ struct usb_serial_driver {
/* Called by console with tty = NULL and by tty */
int (*open)(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
void (*close)(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
void (*close)(struct usb_serial_port *port);
int (*write)(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count);
/* Called only by the tty layer */
@ -241,6 +240,10 @@ struct usb_serial_driver {
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
/* Called by the tty layer for port level work. There may or may not
be an attached tty at this point */
void (*dtr_rts)(struct usb_serial_port *port, int on);
int (*carrier_raised)(struct usb_serial_port *port);
/* USB events */
void (*read_int_callback)(struct urb *urb);
void (*write_int_callback)(struct urb *urb);
@ -283,8 +286,7 @@ extern int usb_serial_generic_open(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write(struct tty_struct *tty,
struct usb_serial_port *port, const unsigned char *buf, int count);
extern void usb_serial_generic_close(struct tty_struct *tty,
struct usb_serial_port *port, struct file *filp);
extern void usb_serial_generic_close(struct usb_serial_port *port);
extern int usb_serial_generic_resume(struct usb_serial *serial);
extern int usb_serial_generic_write_room(struct tty_struct *tty);
extern int usb_serial_generic_chars_in_buffer(struct tty_struct *tty);

View File

@ -10,6 +10,9 @@ menu "Library routines"
config BITREVERSE
tristate
config RATIONAL
boolean
config GENERIC_FIND_FIRST_BIT
bool

View File

@ -50,6 +50,7 @@ ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
endif
obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_RATIONAL) += rational.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o

62
lib/rational.c Normal file
View File

@ -0,0 +1,62 @@
/*
* rational fractions
*
* Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
*
* helper functions when coping with rational numbers
*/
#include <linux/rational.h>
/*
* calculate best rational approximation for a given fraction
* taking into account restricted register size, e.g. to find
* appropriate values for a pll with 5 bit denominator and
* 8 bit numerator register fields, trying to set up with a
* frequency ratio of 3.1415, one would say:
*
* rational_best_approximation(31415, 10000,
* (1 << 8) - 1, (1 << 5) - 1, &n, &d);
*
* you may look at given_numerator as a fixed point number,
* with the fractional part size described in given_denominator.
*
* for theoretical background, see:
* http://en.wikipedia.org/wiki/Continued_fraction
*/
void rational_best_approximation(
unsigned long given_numerator, unsigned long given_denominator,
unsigned long max_numerator, unsigned long max_denominator,
unsigned long *best_numerator, unsigned long *best_denominator)
{
unsigned long n, d, n0, d0, n1, d1;
n = given_numerator;
d = given_denominator;
n0 = d1 = 0;
n1 = d0 = 1;
for (;;) {
unsigned long t, a;
if ((n1 > max_numerator) || (d1 > max_denominator)) {
n1 = n0;
d1 = d0;
break;
}
if (d == 0)
break;
t = d;
a = n / d;
d = n % d;
n = t;
t = n0 + a * n1;
n0 = n1;
n1 = t;
t = d0 + a * d1;
d0 = d1;
d1 = t;
}
*best_numerator = n1;
*best_denominator = d1;
}
EXPORT_SYMBOL(rational_best_approximation);