Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
0deb87aa
Commit
0deb87aa
authored
Mar 15, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
eb9d0aa4
c4ab9d78
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1866 additions
and
1026 deletions
+1866
-1026
drivers/char/tty_io.c
drivers/char/tty_io.c
+7
-2
drivers/serial/8250.c
drivers/serial/8250.c
+27
-1
drivers/serial/8250.h
drivers/serial/8250.h
+2
-0
drivers/serial/8250_acorn.c
drivers/serial/8250_acorn.c
+40
-36
drivers/serial/8250_pci.c
drivers/serial/8250_pci.c
+1290
-483
drivers/serial/core.c
drivers/serial/core.c
+448
-498
drivers/serial/sa1100.c
drivers/serial/sa1100.c
+43
-0
include/linux/pci_ids.h
include/linux/pci_ids.h
+1
-0
include/linux/serial_core.h
include/linux/serial_core.h
+8
-6
No files found.
drivers/char/tty_io.c
View file @
0deb87aa
...
...
@@ -2235,14 +2235,19 @@ struct device_class tty_devclass = {
};
EXPORT_SYMBOL
(
tty_devclass
);
static
int
__init
tty_devclass_init
(
void
)
{
return
devclass_register
(
&
tty_devclass
);
}
postcore_initcall
(
tty_devclass_init
);
/*
* Ok, now we can initialize the rest of the tty devices and can count
* on memory allocations, interrupts etc..
*/
void
__init
tty_init
(
void
)
{
devclass_register
(
&
tty_devclass
);
/*
* dev_tty_driver and dev_console_driver are actually magic
* devices which get redirected at open time. Nevertheless,
...
...
drivers/serial/8250.c
View file @
0deb87aa
...
...
@@ -93,13 +93,15 @@ unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
#ifdef CONFIG_SERIAL_8250_MULTIPORT
#define CONFIG_SERIAL_MULTIPORT 1
#endif
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
#define CONFIG_SERIAL_MANY_PORTS 1
#endif
/*
* HUB6 is always on. This will be removed once the header
* files have been cleaned.
*/
#define CONFIG_HUB6 1
#define CONFIG_SERIAL_MANY_PORTS 1
#include <asm/serial.h>
...
...
@@ -2095,6 +2097,28 @@ void serial8250_get_irq_map(unsigned int *map)
}
}
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
*
* Suspend one serial port.
*/
void
serial8250_suspend_port
(
int
line
,
u32
level
)
{
uart_suspend_port
(
&
serial8250_reg
,
&
serial8250_ports
[
line
].
port
,
level
);
}
/**
* serial8250_resume_port - resume one serial port
* @line: serial line number
*
* Resume one serial port.
*/
void
serial8250_resume_port
(
int
line
,
u32
level
)
{
uart_resume_port
(
&
serial8250_reg
,
&
serial8250_ports
[
line
].
port
,
level
);
}
static
int
__init
serial8250_init
(
void
)
{
int
ret
,
i
;
...
...
@@ -2128,6 +2152,8 @@ module_exit(serial8250_exit);
EXPORT_SYMBOL
(
register_serial
);
EXPORT_SYMBOL
(
unregister_serial
);
EXPORT_SYMBOL
(
serial8250_get_irq_map
);
EXPORT_SYMBOL
(
serial8250_suspend_port
);
EXPORT_SYMBOL
(
serial8250_resume_port
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"Generic 8250/16x50 serial driver $Revision: 1.90 $"
);
...
...
drivers/serial/8250.h
View file @
0deb87aa
...
...
@@ -27,6 +27,8 @@ struct serial8250_probe {
int
serial8250_register_probe
(
struct
serial8250_probe
*
probe
);
void
serial8250_unregister_probe
(
struct
serial8250_probe
*
probe
);
void
serial8250_get_irq_map
(
unsigned
int
*
map
);
void
serial8250_suspend_port
(
int
line
,
u32
level
);
void
serial8250_resume_port
(
int
line
,
u32
level
);
struct
old_serial_port
{
unsigned
int
uart
;
...
...
drivers/serial/8250_acorn.c
View file @
0deb87aa
/*
* linux/drivers/serial/acorn.c
*
* Copyright (C) 1996-200
2
Russell King.
* Copyright (C) 1996-200
3
Russell King.
*
* 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
...
...
@@ -9,6 +9,8 @@
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/errno.h>
#include <linux/ioport.h>
...
...
@@ -16,6 +18,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/ecard.h>
#include <asm/string.h>
...
...
@@ -24,36 +27,41 @@
struct
serial_card_type
{
unsigned
int
num_ports
;
unsigned
int
baud_base
;
int
type
;
int
speed
;
int
offset
[
MAX_PORTS
];
unsigned
int
type
;
unsigned
int
offset
[
MAX_PORTS
];
};
struct
serial_card_info
{
unsigned
int
num_ports
;
int
ports
[
MAX_PORTS
];
unsigned
long
base
[
MAX_PORTS
];
};
static
inline
int
serial_register_onedev
(
unsigned
long
port
,
int
irq
,
unsigned
int
baud_base
)
static
inline
int
serial_register_onedev
(
unsigned
long
baddr
,
void
*
vaddr
,
int
irq
,
unsigned
int
baud_base
)
{
struct
serial_struct
req
;
memset
(
&
req
,
0
,
sizeof
(
req
));
req
.
baud_base
=
baud_base
;
req
.
irq
=
irq
;
req
.
port
=
port
;
req
.
flags
=
0
;
req
.
irq
=
irq
;
req
.
flags
=
UPF_AUTOPROBE
|
UPF_RESOURCES
|
UPF_SHARE_IRQ
;
req
.
baud_base
=
baud_base
;
req
.
io_type
=
UPIO_MEM
;
req
.
iomem_base
=
vaddr
;
req
.
iomem_reg_shift
=
2
;
req
.
iomap_base
=
baddr
;
return
register_serial
(
&
req
);
}
static
int
__devinit
serial_card_probe
(
struct
expansion_card
*
ec
,
const
struct
ecard_id
*
id
)
static
int
__devinit
serial_card_probe
(
struct
expansion_card
*
ec
,
const
struct
ecard_id
*
id
)
{
struct
serial_card_info
*
info
;
struct
serial_card_type
*
type
=
id
->
data
;
unsigned
long
cardaddr
,
address
;
int
port
;
unsigned
long
bus_addr
;
unsigned
char
*
virt_addr
;
unsigned
int
port
;
info
=
kmalloc
(
sizeof
(
struct
serial_card_info
),
GFP_KERNEL
);
if
(
!
info
)
...
...
@@ -64,20 +72,19 @@ static int __devinit serial_card_probe(struct expansion_card *ec, const struct e
ecard_set_drvdata
(
ec
,
info
);
cardaddr
=
ecard_address
(
ec
,
type
->
type
,
type
->
speed
);
bus_addr
=
ec
->
resource
[
type
->
type
].
start
;
virt_addr
=
ioremap
(
bus_addr
,
ec
->
resource
[
type
->
type
].
end
-
bus_addr
+
1
);
if
(
!
virt_addr
)
{
kfree
(
info
);
return
-
ENOMEM
;
}
for
(
port
=
0
;
port
<
info
->
num_ports
;
port
++
)
{
address
=
cardaddr
+
type
->
offset
[
port
];
info
->
ports
[
port
]
=
-
1
;
info
->
base
[
port
]
=
address
;
unsigned
long
baddr
=
bus_addr
+
type
->
offset
[
port
];
unsigned
char
*
vaddr
=
virt_addr
+
type
->
offset
[
port
];
if
(
!
request_region
(
address
,
8
,
"acornserial"
))
continue
;
info
->
ports
[
port
]
=
serial_register_onedev
(
address
,
ec
->
irq
,
type
->
baud_base
);
if
(
info
->
ports
[
port
]
<
0
)
break
;
info
->
ports
[
port
]
=
serial_register_onedev
(
baddr
,
vaddr
,
ec
->
irq
,
type
->
baud_base
);
}
return
0
;
...
...
@@ -90,12 +97,9 @@ static void __devexit serial_card_remove(struct expansion_card *ec)
ecard_set_drvdata
(
ec
,
NULL
);
for
(
i
=
0
;
i
<
info
->
num_ports
;
i
++
)
{
if
(
info
->
ports
[
i
]
>
0
)
{
for
(
i
=
0
;
i
<
info
->
num_ports
;
i
++
)
if
(
info
->
ports
[
i
]
>
0
)
unregister_serial
(
info
->
ports
[
i
]);
release_region
(
info
->
base
[
i
],
8
);
}
}
kfree
(
info
);
}
...
...
@@ -103,17 +107,15 @@ static void __devexit serial_card_remove(struct expansion_card *ec)
static
struct
serial_card_type
atomwide_type
=
{
.
num_ports
=
3
,
.
baud_base
=
7372800
/
16
,
.
type
=
ECARD_IOC
,
.
speed
=
ECARD_SLOW
,
.
offset
=
{
0xa00
,
0x900
,
0x800
},
.
type
=
ECARD_RES_IOCSLOW
,
.
offset
=
{
0x2800
,
0x2400
,
0x2000
},
};
static
struct
serial_card_type
serport_type
=
{
.
num_ports
=
2
,
.
baud_base
=
3686400
/
16
,
.
type
=
ECARD_IOC
,
.
speed
=
ECARD_SLOW
,
.
offset
=
{
0x800
,
0x808
},
.
type
=
ECARD_RES_IOCSLOW
,
.
offset
=
{
0x2000
,
0x2020
},
};
static
const
struct
ecard_id
serial_cids
[]
=
{
...
...
@@ -127,7 +129,8 @@ static struct ecard_driver serial_card_driver = {
.
remove
=
__devexit_p
(
serial_card_remove
),
.
id_table
=
serial_cids
,
.
drv
=
{
.
name
=
"acornserial"
,
.
devclass
=
&
tty_devclass
,
.
name
=
"8250_acorn"
,
},
};
...
...
@@ -142,6 +145,7 @@ static void __exit serial_card_exit(void)
}
MODULE_AUTHOR
(
"Russell King"
);
MODULE_DESCRIPTION
(
"Acorn 8250-compatible serial port expansion card driver"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
serial_card_init
);
...
...
drivers/serial/8250_pci.c
View file @
0deb87aa
...
...
@@ -20,8 +20,9 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial
P
.h>
#include <linux/serial
_core
.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
...
...
@@ -30,174 +31,213 @@
#include "8250.h"
/*
* Definitions for PCI support.
*/
#define FL_BASE_MASK 0x0007
#define FL_BASE0 0x0000
#define FL_BASE1 0x0001
#define FL_BASE2 0x0002
#define FL_BASE3 0x0003
#define FL_BASE4 0x0004
#define FL_GET_BASE(x) (x & FL_BASE_MASK)
#define FL_IRQ_MASK (0x0007 << 4)
#define FL_IRQBASE0 (0x0000 << 4)
#define FL_IRQBASE1 (0x0001 << 4)
#define FL_IRQBASE2 (0x0002 << 4)
#define FL_IRQBASE3 (0x0003 << 4)
#define FL_IRQBASE4 (0x0004 << 4)
#define FL_GET_IRQBASE(x) ((x & FL_IRQ_MASK) >> 4)
/* Use successive BARs (PCI base address registers),
else use offset into some specified BAR */
#define FL_BASE_BARS 0x0008
/* Use the irq resource table instead of dev->irq */
#define FL_IRQRESOURCE 0x0080
/* Use the Base address register size to cap number of ports */
#define FL_REGION_SZ_CAP 0x0100
#ifndef IS_PCI_REGION_IOPORT
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_IO)
#endif
#ifndef IS_PCI_REGION_IOMEM
#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_MEM)
#endif
#ifndef PCI_IRQ_RESOURCE
#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
#endif
#ifndef pci_get_subvendor
#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
#define pci_get_subdevice(dev) ((dev)->subsystem_device)
#endif
struct
serial_private
{
unsigned
int
nr
;
struct
pci_board
*
board
;
int
line
[
0
];
struct
pci_board
{
unsigned
int
flags
;
unsigned
int
num_ports
;
unsigned
int
base_baud
;
unsigned
int
uart_offset
;
unsigned
int
reg_shift
;
unsigned
int
first_offset
;
};
/*
* init
_f
n returns:
* init
functio
n returns:
* > 0 - number of ports
* = 0 - use board->num_ports
* < 0 - error
*/
struct
pci_board
{
int
flags
;
int
num_ports
;
int
base_baud
;
int
uart_offset
;
int
reg_shift
;
int
(
*
init_fn
)(
struct
pci_dev
*
dev
,
int
enable
);
int
first_uart_offset
;
struct
pci_serial_quirk
{
u32
vendor
;
u32
device
;
u32
subvendor
;
u32
subdevice
;
int
(
*
init
)(
struct
pci_dev
*
dev
);
int
(
*
setup
)(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
);
void
(
*
exit
)(
struct
pci_dev
*
dev
);
};
#define PCI_NUM_BAR_RESOURCES 6
struct
serial_private
{
unsigned
int
nr
;
void
*
remapped_bar
[
PCI_NUM_BAR_RESOURCES
];
struct
pci_serial_quirk
*
quirk
;
int
line
[
0
];
};
static
void
moan_device
(
const
char
*
str
,
struct
pci_dev
*
dev
)
{
printk
(
KERN_WARNING
"%s: %s
\n
"
KERN_WARNING
"Please send the output of lspci -vv, this
\n
"
KERN_WARNING
"message (0x%04x,0x%04x,0x%04x,0x%04x), the
\n
"
KERN_WARNING
"manufacturer and name of serial board or
\n
"
KERN_WARNING
"modem board to rmk+serial@arm.linux.org.uk.
\n
"
,
dev
->
slot_name
,
str
,
dev
->
vendor
,
dev
->
device
,
dev
->
subsystem_vendor
,
dev
->
subsystem_device
);
}
static
int
get_pci_port
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
setup_port
(
struct
pci_dev
*
dev
,
struct
serial_struct
*
req
,
int
bar
,
int
offset
,
int
regshift
)
{
unsigned
long
port
;
int
base_idx
;
int
max_port
;
int
offset
;
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
unsigned
long
port
,
len
;
base_idx
=
SPCI_FL_GET_BASE
(
board
->
flags
);
if
(
board
->
flags
&
SPCI_FL_BASE_TABLE
)
base_idx
+=
idx
;
if
(
bar
>=
PCI_NUM_BAR_RESOURCES
)
return
-
EINVAL
;
if
(
board
->
flags
&
SPCI_FL_REGION_SZ_CAP
)
{
max_port
=
pci_resource_len
(
dev
,
base_idx
)
/
8
;
if
(
idx
>=
max_port
)
return
1
;
}
offset
=
board
->
first_uart_offset
;
if
(
pci_resource_flags
(
dev
,
bar
)
&
IORESOURCE_MEM
)
{
port
=
pci_resource_start
(
dev
,
bar
);
len
=
pci_resource_len
(
dev
,
bar
);
/*
* Timedia/SUNIX uses a mixture of BARs and offsets
* Ugh, this is ugly as all hell --- TYT
*/
if
(
dev
->
vendor
==
PCI_VENDOR_ID_TIMEDIA
)
switch
(
idx
)
{
case
0
:
base_idx
=
0
;
break
;
case
1
:
base_idx
=
0
;
offset
=
8
;
break
;
case
2
:
base_idx
=
1
;
break
;
case
3
:
base_idx
=
1
;
offset
=
8
;
break
;
case
4
:
/* BAR 2 */
case
5
:
/* BAR 3 */
case
6
:
/* BAR 4 */
case
7
:
/* BAR 5 */
base_idx
=
idx
-
2
;
}
if
(
!
priv
->
remapped_bar
[
bar
])
priv
->
remapped_bar
[
bar
]
=
ioremap
(
port
,
len
);
if
(
!
priv
->
remapped_bar
[
bar
])
return
-
ENOMEM
;
/* AFAVLAB uses a different mixture of BARs and offsets */
/* Not that ugly ;) -- HW */
if
(
dev
->
vendor
==
PCI_VENDOR_ID_AFAVLAB
&&
idx
>=
4
)
{
base_idx
=
4
;
offset
=
(
idx
-
4
)
*
8
;
req
->
io_type
=
UPIO_MEM
;
req
->
iomap_base
=
port
;
req
->
iomem_base
=
priv
->
remapped_bar
[
bar
]
+
offset
;
req
->
iomem_reg_shift
=
regshift
;
}
else
{
port
=
pci_resource_start
(
dev
,
bar
)
+
offset
;
req
->
io_type
=
UPIO_PORT
;
req
->
port
=
port
;
if
(
HIGH_BITS_OFFSET
)
req
->
port_high
=
port
>>
HIGH_BITS_OFFSET
;
}
return
0
;
}
/* Some Titan cards are also a little weird */
if
(
dev
->
vendor
==
PCI_VENDOR_ID_TITAN
&&
(
dev
->
device
==
PCI_DEVICE_ID_TITAN_400L
||
dev
->
device
==
PCI_DEVICE_ID_TITAN_800L
))
{
switch
(
idx
)
{
case
0
:
base_idx
=
1
;
break
;
case
1
:
base_idx
=
2
;
break
;
default:
base_idx
=
4
;
offset
=
8
*
(
idx
-
2
);
}
}
/*
* AFAVLAB uses a different mixture of BARs and offsets
* Not that ugly ;) -- HW
*/
static
int
afavlab_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
;
bar
=
FL_GET_BASE
(
board
->
flags
);
if
(
idx
<
4
)
bar
+=
idx
;
else
offset
+=
(
idx
-
4
)
*
board
->
uart_offset
;
/* HP's Diva chip puts the 4th/5th serial port further out, and
* some serial ports are supposed to be hidden on certain models.
*/
if
(
dev
->
vendor
==
PCI_VENDOR_ID_HP
&&
dev
->
device
==
PCI_DEVICE_ID_HP_DIVA
)
{
switch
(
dev
->
subsystem_device
)
{
case
PCI_DEVICE_ID_HP_DIVA_MAESTRO
:
if
(
idx
==
3
)
idx
++
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_EVEREST
:
if
(
idx
>
0
)
idx
++
;
if
(
idx
>
2
)
idx
++
;
break
;
}
if
(
idx
>
2
)
{
offset
=
0x18
;
}
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
* HP's Remote Management Console. The Diva chip came in several
* different versions. N-class, L2000 and A500 have two Diva chips, each
* with 3 UARTs (the third UART on the second chip is unused). Superdome
* and Keystone have one Diva chip with 3 UARTs. Some later machines have
* one Diva chip, but it has been expanded to 5 UARTs.
*/
static
int
__devinit
pci_hp_diva_init
(
struct
pci_dev
*
dev
)
{
int
rc
=
0
;
switch
(
dev
->
subsystem_device
)
{
case
PCI_DEVICE_ID_HP_DIVA_TOSCA1
:
case
PCI_DEVICE_ID_HP_DIVA_HALFDOME
:
case
PCI_DEVICE_ID_HP_DIVA_KEYSTONE
:
case
PCI_DEVICE_ID_HP_DIVA_EVEREST
:
rc
=
3
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_TOSCA2
:
rc
=
2
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_MAESTRO
:
rc
=
4
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_POWERBAR
:
rc
=
1
;
break
;
}
port
=
pci_resource_start
(
dev
,
base_idx
)
+
offset
;
return
rc
;
}
if
((
board
->
flags
&
SPCI_FL_BASE_TABLE
)
==
0
)
port
+=
idx
*
(
board
->
uart_offset
?
board
->
uart_offset
:
8
);
/*
* HP's Diva chip puts the 4th/5th serial port further out, and
* some serial ports are supposed to be hidden on certain models.
*/
static
int
pci_hp_diva_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
{
unsigned
int
offset
=
board
->
first_offset
;
unsigned
int
bar
=
FL_GET_BASE
(
board
->
flags
);
if
(
IS_PCI_REGION_IOPORT
(
dev
,
base_idx
))
{
req
->
port
=
port
;
if
(
HIGH_BITS_OFFSET
)
req
->
port_high
=
port
>>
HIGH_BITS_OFFSET
;
else
req
->
port_high
=
0
;
return
0
;
switch
(
dev
->
subsystem_device
)
{
case
PCI_DEVICE_ID_HP_DIVA_MAESTRO
:
if
(
idx
==
3
)
idx
++
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_EVEREST
:
if
(
idx
>
0
)
idx
++
;
if
(
idx
>
2
)
idx
++
;
break
;
}
req
->
io_type
=
SERIAL_IO_MEM
;
req
->
iomap_base
=
port
;
req
->
iomem_base
=
ioremap
(
port
,
board
->
uart_offset
);
if
(
req
->
iomem_base
==
NULL
)
return
-
ENOMEM
;
req
->
iomem_reg_shift
=
board
->
reg_shift
;
req
->
port
=
0
;
return
0
;
if
(
idx
>
2
)
offset
=
0x18
;
offset
+=
idx
*
board
->
uart_offset
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
}
static
_INLINE_
int
get_pci_irq
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
int
idx
)
/*
* Added for EKF Intel i960 serial boards
*/
static
int
__devinit
pci_inteli960ni_init
(
struct
pci_dev
*
dev
)
{
int
base_idx
;
unsigned
long
oldval
;
if
(
(
board
->
flags
&
SPCI_FL_IRQRESOURCE
)
==
0
)
return
dev
->
irq
;
if
(
!
(
dev
->
subsystem_device
&
0x1000
)
)
return
-
ENODEV
;
base_idx
=
SPCI_FL_GET_IRQBASE
(
board
->
flags
);
if
(
board
->
flags
&
SPCI_FL_IRQ_TABLE
)
base_idx
+=
idx
;
return
PCI_IRQ_RESOURCE
(
dev
,
base_idx
);
/* is firmware started? */
pci_read_config_dword
(
dev
,
0x44
,
(
void
*
)
&
oldval
);
if
(
oldval
==
0x00001000L
)
{
/* RESET value */
printk
(
KERN_DEBUG
"Local i960 firmware missing"
);
return
-
ENODEV
;
}
return
0
;
}
/*
...
...
@@ -206,26 +246,29 @@ get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx)
* seems to be mainly needed on card using the PLX which also use I/O
* mapped memory.
*/
static
int
__devinit
pci_plx9050_
fn
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
__devinit
pci_plx9050_
init
(
struct
pci_dev
*
dev
)
{
u8
*
p
,
irq_config
=
0
;
if
(
enable
)
{
irq_config
=
0x41
;
if
(
dev
->
vendor
==
PCI_VENDOR_ID_PANACOM
)
irq_config
=
0x43
;
if
((
dev
->
vendor
==
PCI_VENDOR_ID_PLX
)
&&
(
dev
->
device
==
PCI_DEVICE_ID_PLX_ROMULUS
))
{
/*
* As the megawolf cards have the int pins active
* high, and have 2 UART chips, both ints must be
* enabled on the 9050. Also, the UARTS are set in
* 16450 mode by default, so we have to enable the
* 16C950 'enhanced' mode so that we can use the
* deep FIFOs
*/
irq_config
=
0x5b
;
}
u8
*
p
,
irq_config
;
if
((
pci_resource_flags
(
dev
,
0
)
&
IORESOURCE_MEM
)
==
0
)
{
moan_device
(
"no memory in bar 0"
,
dev
);
return
0
;
}
irq_config
=
0x41
;
if
(
dev
->
vendor
==
PCI_VENDOR_ID_PANACOM
)
irq_config
=
0x43
;
if
((
dev
->
vendor
==
PCI_VENDOR_ID_PLX
)
&&
(
dev
->
device
==
PCI_DEVICE_ID_PLX_ROMULUS
))
{
/*
* As the megawolf cards have the int pins active
* high, and have 2 UART chips, both ints must be
* enabled on the 9050. Also, the UARTS are set in
* 16450 mode by default, so we have to enable the
* 16C950 'enhanced' mode so that we can use the
* deep FIFOs
*/
irq_config
=
0x5b
;
}
/*
...
...
@@ -245,6 +288,27 @@ static int __devinit pci_plx9050_fn(struct pci_dev *dev, int enable)
return
0
;
}
static
void
__devexit
pci_plx9050_exit
(
struct
pci_dev
*
dev
)
{
u8
*
p
;
if
((
pci_resource_flags
(
dev
,
0
)
&
IORESOURCE_MEM
)
==
0
)
return
;
/*
* disable interrupts
*/
p
=
ioremap
(
pci_resource_start
(
dev
,
0
),
0x80
);
if
(
p
!=
NULL
)
{
writel
(
0
,
p
+
0x4c
);
/*
* Read the register back to ensure that it took effect.
*/
readl
(
p
+
0x4c
);
iounmap
(
p
);
}
}
/*
* SIIG serial cards have an PCI interface chip which also controls
...
...
@@ -270,23 +334,20 @@ static int __devinit pci_plx9050_fn(struct pci_dev *dev, int enable)
#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
int
pci_siig10x_fn
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
pci_siig10x_init
(
struct
pci_dev
*
dev
)
{
u16
data
,
*
p
;
if
(
!
enable
)
return
0
;
switch
(
dev
->
device
&
0xfff8
)
{
case
PCI_DEVICE_ID_SIIG_1S_10x
:
/* 1S */
data
=
0xffdf
;
break
;
case
PCI_DEVICE_ID_SIIG_2S_10x
:
/* 2S, 2S1P */
data
=
0xf7ff
;
break
;
default:
/* 1S1P, 4S */
data
=
0xfffb
;
break
;
case
PCI_DEVICE_ID_SIIG_1S_10x
:
/* 1S */
data
=
0xffdf
;
break
;
case
PCI_DEVICE_ID_SIIG_2S_10x
:
/* 2S, 2S1P */
data
=
0xf7ff
;
break
;
default:
/* 1S1P, 4S */
data
=
0xfffb
;
break
;
}
p
=
ioremap
(
pci_resource_start
(
dev
,
0
),
0x80
);
...
...
@@ -294,22 +355,18 @@ int pci_siig10x_fn(struct pci_dev *dev, int enable)
return
-
ENOMEM
;
writew
(
readw
((
unsigned
long
)
p
+
0x28
)
&
data
,
(
unsigned
long
)
p
+
0x28
);
readw
((
unsigned
long
)
p
+
0x28
);
iounmap
(
p
);
return
0
;
}
EXPORT_SYMBOL
(
pci_siig10x_fn
);
#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
int
pci_siig20x_fn
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
pci_siig20x_init
(
struct
pci_dev
*
dev
)
{
u8
data
;
if
(
!
enable
)
return
0
;
/* Change clock frequency for the first UART. */
pci_read_config_byte
(
dev
,
0x6f
,
&
data
);
pci_write_config_byte
(
dev
,
0x6f
,
data
&
0xef
);
...
...
@@ -323,28 +380,25 @@ int pci_siig20x_fn(struct pci_dev *dev, int enable)
return
0
;
}
EXPORT_SYMBOL
(
pci_siig20x_fn
);
/* Added for EKF Intel i960 serial boards */
static
int
__devinit
pci_inteli960ni_fn
(
struct
pci_dev
*
dev
,
int
enable
)
int
pci_siig10x_fn
(
struct
pci_dev
*
dev
,
int
enable
)
{
unsigned
long
oldval
;
if
(
!
(
pci_get_subdevice
(
dev
)
&
0x1000
))
return
-
ENODEV
;
int
ret
=
0
;
if
(
enable
)
ret
=
pci_siig10x_init
(
dev
);
return
ret
;
}
if
(
!
enable
)
/* is there something to deinit? */
return
0
;
/* is firmware started? */
pci_read_config_dword
(
dev
,
0x44
,
(
void
*
)
&
oldval
);
if
(
oldval
==
0x00001000L
)
{
/* RESET value */
printk
(
KERN_DEBUG
"Local i960 firmware missing"
);
return
-
ENODEV
;
}
return
0
;
int
pci_siig20x_fn
(
struct
pci_dev
*
dev
,
int
enable
)
{
int
ret
=
0
;
if
(
enable
)
ret
=
pci_siig20x_init
(
dev
);
return
ret
;
}
EXPORT_SYMBOL
(
pci_siig10x_fn
);
EXPORT_SYMBOL
(
pci_siig20x_fn
);
/*
* Timedia has an explosion of boards, and to avoid the PCI table from
* growing *huge*, we use this function to collapse some 70 entries
...
...
@@ -385,78 +439,453 @@ static struct timedia_struct {
{
0
,
0
}
};
static
int
__devinit
pci_timedia_
fn
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
__devinit
pci_timedia_
init
(
struct
pci_dev
*
dev
)
{
int
i
,
j
;
unsigned
short
*
ids
;
if
(
!
enable
)
return
0
;
int
i
,
j
;
for
(
i
=
0
;
timedia_data
[
i
].
num
;
i
++
)
{
ids
=
timedia_data
[
i
].
ids
;
for
(
j
=
0
;
ids
[
j
];
j
++
)
if
(
pci_get_subdevice
(
dev
)
==
ids
[
j
])
if
(
dev
->
subsystem_device
==
ids
[
j
])
return
timedia_data
[
i
].
num
;
}
return
0
;
}
/*
* HP's Remote Management Console. The Diva chip came in several
* different versions. N-class, L2000 and A500 have two Diva chips, each
* with 3 UARTs (the third UART on the second chip is unused). Superdome
* and Keystone have one Diva chip with 3 UARTs. Some later machines have
* one Diva chip, but it has been expanded to 5 UARTs.
* Timedia/SUNIX uses a mixture of BARs and offsets
* Ugh, this is ugly as all hell --- TYT
*/
static
int
__devinit
pci_hp_diva
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
pci_timedia_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
{
int
rc
=
0
;
if
(
!
enable
)
return
0
;
unsigned
int
bar
=
0
,
offset
=
board
->
first_offset
;
switch
(
dev
->
subsystem_device
)
{
case
PCI_DEVICE_ID_HP_DIVA_TOSCA1
:
case
PCI_DEVICE_ID_HP_DIVA_HALFDOME
:
case
PCI_DEVICE_ID_HP_DIVA_KEYSTONE
:
case
PCI_DEVICE_ID_HP_DIVA_EVEREST
:
rc
=
3
;
switch
(
idx
)
{
case
0
:
bar
=
0
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_TOSCA2
:
rc
=
2
;
case
1
:
offset
=
board
->
uart_offset
;
bar
=
0
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_MAESTRO
:
rc
=
4
;
break
;
case
PCI_DEVICE_ID_HP_DIVA_POWERBAR
:
rc
=
1
;
case
2
:
bar
=
1
;
break
;
case
3
:
offset
=
board
->
uart_offset
;
bar
=
1
;
case
4
:
/* BAR 2 */
case
5
:
/* BAR 3 */
case
6
:
/* BAR 4 */
case
7
:
/* BAR 5 */
bar
=
idx
-
2
;
}
return
rc
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
)
;
}
/*
* Some Titan cards are also a little weird
*/
static
int
titan_400l_800l_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
;
switch
(
idx
)
{
case
0
:
bar
=
1
;
break
;
case
1
:
bar
=
2
;
break
;
default:
bar
=
4
;
offset
=
(
idx
-
2
)
*
board
->
uart_offset
;
}
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
}
static
int
__devinit
pci_xircom_
fn
(
struct
pci_dev
*
dev
,
int
enable
)
static
int
__devinit
pci_xircom_
init
(
struct
pci_dev
*
dev
)
{
__set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
HZ
/
10
);
return
0
;
}
static
int
pci_default_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
,
maxnr
;
bar
=
FL_GET_BASE
(
board
->
flags
);
if
(
board
->
flags
&
FL_BASE_BARS
)
bar
+=
idx
;
else
offset
+=
idx
*
board
->
uart_offset
;
maxnr
=
(
pci_resource_len
(
dev
,
bar
)
-
board
->
uart_offset
)
/
(
8
<<
board
->
reg_shift
);
if
(
board
->
flags
&
FL_REGION_SZ_CAP
&&
idx
>=
maxnr
)
return
1
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
* Master list of serial port init/setup/exit quirks.
* This does not describe the general nature of the port.
* (ie, baud base, number and location of ports, etc)
*
* This list is ordered alphabetically by vendor then device.
* Specific entries must come before more generic entries.
*/
static
struct
pci_serial_quirk
pci_serial_quirks
[]
=
{
/*
* AFAVLAB cards.
* It is not clear whether this applies to all products.
*/
{
.
vendor
=
PCI_VENDOR_ID_AFAVLAB
,
.
device
=
PCI_ANY_ID
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
setup
=
afavlab_setup
,
},
/*
* HP Diva
*/
{
.
vendor
=
PCI_VENDOR_ID_HP
,
.
device
=
PCI_DEVICE_ID_HP_DIVA
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_hp_diva_init
,
.
setup
=
pci_hp_diva_setup
,
},
/*
* Intel
*/
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_80960_RP
,
.
subvendor
=
0xe4bf
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_inteli960ni_init
,
.
setup
=
pci_default_setup
,
},
/*
* Panacom
*/
{
.
vendor
=
PCI_VENDOR_ID_PANACOM
,
.
device
=
PCI_DEVICE_ID_PANACOM_QUADMODEM
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_plx9050_init
,
.
setup
=
pci_default_setup
,
.
exit
=
__devexit_p
(
pci_plx9050_exit
),
},
{
.
vendor
=
PCI_VENDOR_ID_PANACOM
,
.
device
=
PCI_DEVICE_ID_PANACOM_DUALMODEM
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_plx9050_init
,
.
setup
=
pci_default_setup
,
.
exit
=
__devexit_p
(
pci_plx9050_exit
),
},
/*
* PLX
*/
{
.
vendor
=
PCI_VENDOR_ID_PLX
,
.
device
=
PCI_DEVICE_ID_PLX_9050
,
.
subvendor
=
PCI_SUBVENDOR_ID_KEYSPAN
,
.
subdevice
=
PCI_SUBDEVICE_ID_KEYSPAN_SX2
,
.
init
=
pci_plx9050_init
,
.
setup
=
pci_default_setup
,
.
exit
=
__devexit_p
(
pci_plx9050_exit
),
},
{
.
vendor
=
PCI_VENDOR_ID_PLX
,
.
device
=
PCI_DEVICE_ID_PLX_ROMULUS
,
.
subvendor
=
PCI_VENDOR_ID_PLX
,
.
subdevice
=
PCI_DEVICE_ID_PLX_ROMULUS
,
.
init
=
pci_plx9050_init
,
.
setup
=
pci_default_setup
,
.
exit
=
__devexit_p
(
pci_plx9050_exit
),
},
/*
* SIIG cards.
* It is not clear whether these could be collapsed.
*/
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_10x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_10x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_10x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_10x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_10x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_10x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_10x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_10x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_10x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig10x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_20x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_20x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_1S_20x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_20x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_20x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_2S_20x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_20x_550
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_20x_650
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_SIIG
,
.
device
=
PCI_DEVICE_ID_SIIG_4S_20x_850
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_siig20x_init
,
.
setup
=
pci_default_setup
,
},
/*
* Titan cards
*/
{
.
vendor
=
PCI_VENDOR_ID_TITAN
,
.
device
=
PCI_DEVICE_ID_TITAN_400L
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
setup
=
titan_400l_800l_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_TITAN
,
.
device
=
PCI_DEVICE_ID_TITAN_800L
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
setup
=
titan_400l_800l_setup
,
},
/*
* Timedia cards
*/
{
.
vendor
=
PCI_VENDOR_ID_TIMEDIA
,
.
device
=
PCI_DEVICE_ID_TIMEDIA_1889
,
.
subvendor
=
PCI_VENDOR_ID_TIMEDIA
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_timedia_init
,
.
setup
=
pci_timedia_setup
,
},
{
.
vendor
=
PCI_VENDOR_ID_TIMEDIA
,
.
device
=
PCI_ANY_ID
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
setup
=
pci_timedia_setup
,
},
/*
* Xircom cards
*/
{
.
vendor
=
PCI_VENDOR_ID_XIRCOM
,
.
device
=
PCI_DEVICE_ID_XIRCOM_X3201_MDM
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
init
=
pci_xircom_init
,
.
setup
=
pci_default_setup
,
},
/*
* Default "match everything" terminator entry
*/
{
.
vendor
=
PCI_ANY_ID
,
.
device
=
PCI_ANY_ID
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
setup
=
pci_default_setup
,
}
};
static
inline
int
quirk_id_matches
(
u32
quirk_id
,
u32
dev_id
)
{
return
quirk_id
==
PCI_ANY_ID
||
quirk_id
==
dev_id
;
}
static
struct
pci_serial_quirk
*
find_quirk
(
struct
pci_dev
*
dev
)
{
struct
pci_serial_quirk
*
quirk
;
for
(
quirk
=
pci_serial_quirks
;
;
quirk
++
)
if
(
quirk_id_matches
(
quirk
->
vendor
,
dev
->
vendor
)
&&
quirk_id_matches
(
quirk
->
device
,
dev
->
device
)
&&
quirk_id_matches
(
quirk
->
subvendor
,
dev
->
subsystem_vendor
)
&&
quirk_id_matches
(
quirk
->
subdevice
,
dev
->
subsystem_device
))
break
;
return
quirk
;
}
static
_INLINE_
int
get_pci_irq
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
int
idx
)
{
int
base_idx
;
if
((
board
->
flags
&
FL_IRQRESOURCE
)
==
0
)
return
dev
->
irq
;
base_idx
=
FL_GET_IRQBASE
(
board
->
flags
);
if
(
base_idx
>
DEVICE_COUNT_IRQ
)
return
0
;
return
dev
->
irq_resource
[
base_idx
].
start
;
}
/*
* This is the configuration table for all of the PCI serial boards
* which we support. It is directly indexed by the pci_board_num_t enum
* value, which is encoded in the pci_device_id PCI probe table's
* driver_data member.
*
* The makeup of these names are:
* pbn_bn{_bt}_n_baud
*
* bn = PCI BAR number
* bt = Index using PCI BARs
* n = number of serial ports
* baud = baud rate
*
* Please note: in theory if n = 1, _bt infix should make no difference.
* ie, pbn_b0_1_115200 is the same as pbn_b0_bt_1_115200
*/
enum
pci_board_num_t
{
pbn_b0_1_115200
,
pbn_default
=
0
,
pbn_b0_1_115200
,
pbn_b0_2_115200
,
pbn_b0_4_115200
,
pbn_b0_5_115200
,
pbn_b0_1_921600
,
pbn_b0_2_921600
,
...
...
@@ -465,171 +894,465 @@ enum pci_board_num_t {
pbn_b0_bt_1_115200
,
pbn_b0_bt_2_115200
,
pbn_b0_bt_8_115200
,
pbn_b0_bt_1_460800
,
pbn_b0_bt_2_460800
,
pbn_b0_bt_1_921600
,
pbn_b0_bt_2_921600
,
pbn_b0_bt_4_921600
,
pbn_b0_bt_8_921600
,
pbn_b1_1_115200
,
pbn_b1_2_115200
,
pbn_b1_4_115200
,
pbn_b1_8_115200
,
pbn_b1_1_921600
,
pbn_b1_2_921600
,
pbn_b1_4_921600
,
pbn_b1_8_921600
,
pbn_b1_bt_2_921600
,
pbn_b1_2_1382400
,
pbn_b1_4_1382400
,
pbn_b1_8_1382400
,
pbn_b2_1_115200
,
pbn_b2_8_115200
,
pbn_b2_1_460800
,
pbn_b2_4_460800
,
pbn_b2_8_460800
,
pbn_b2_16_460800
,
pbn_b2_1_921600
,
pbn_b2_4_921600
,
pbn_b2_8_921600
,
pbn_b2_bt_1_115200
,
pbn_b2_bt_2_115200
,
pbn_b2_bt_4_115200
,
pbn_b2_bt_2_921600
,
pbn_b2_bt_4_921600
,
pbn_b3_4_115200
,
pbn_b3_8_115200
,
/*
* Board-specific versions.
*/
pbn_panacom
,
pbn_panacom2
,
pbn_panacom4
,
pbn_plx_romulus
,
pbn_oxsemi
,
pbn_timedia
,
pbn_intel_i960
,
pbn_sgi_ioc3
,
pbn_hp_diva
,
pbn_nec_nile4
,
pbn_dci_pccom4
,
pbn_dci_pccom8
,
pbn_xircom_combo
,
pbn_siig10x_0
,
pbn_siig10x_1
,
pbn_siig10x_2
,
pbn_siig10x_4
,
pbn_siig20x_0
,
pbn_siig20x_2
,
pbn_siig20x_4
,
pbn_computone_4
,
pbn_computone_6
,
pbn_computone_8
,
};
static
struct
pci_board
pci_boards
[]
__devinitdata
=
{
[
pbn_default
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_1_115200
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_2_115200
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
2
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_4_115200
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
4
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_5_115200
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
5
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_1_921600
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
1
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_2_921600
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_4_921600
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_1_115200
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_2_115200
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_8_115200
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
8
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_1_460800
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
1
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_2_460800
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_1_921600
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
1
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_2_921600
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_4_921600
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b0_bt_8_921600
]
=
{
.
flags
=
FL_BASE0
|
FL_BASE_BARS
,
.
num_ports
=
8
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_1_115200
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b1_2_115200
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
2
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b1_4_115200
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
4
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b1_8_115200
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
8
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b1_1_921600
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
1
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_2_921600
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_4_921600
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_8_921600
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
8
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_bt_2_921600
]
=
{
.
flags
=
FL_BASE1
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b1_2_1382400
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
2
,
.
base_baud
=
1382400
,
.
uart_offset
=
8
,
},
[
pbn_b1_4_1382400
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
4
,
.
base_baud
=
1382400
,
.
uart_offset
=
8
,
},
[
pbn_b1_8_1382400
]
=
{
.
flags
=
FL_BASE1
,
.
num_ports
=
8
,
.
base_baud
=
1382400
,
.
uart_offset
=
8
,
},
[
pbn_b2_1_115200
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b2_8_115200
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
8
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b2_1_460800
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
1
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b2_4_460800
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
4
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b2_8_460800
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
8
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b2_16_460800
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
16
,
.
base_baud
=
460800
,
.
uart_offset
=
8
,
},
[
pbn_b2_1_921600
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
1
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b2_4_921600
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b2_8_921600
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
8
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b2_bt_1_115200
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
1
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b2_bt_2_115200
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b2_bt_4_115200
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
4
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b2_bt_2_921600
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b2_bt_4_921600
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
,
},
[
pbn_b3_4_115200
]
=
{
.
flags
=
FL_BASE3
,
.
num_ports
=
4
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
[
pbn_b3_8_115200
]
=
{
.
flags
=
FL_BASE3
,
.
num_ports
=
8
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
/*
* PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
* Offset to get to next UART's registers,
* Register shift to use for memory-mapped I/O,
* Initialization function, first UART offset
* Entries following this are board-specific.
*/
/* Generic serial board, pbn_b0_1_115200, pbn_default */
{
SPCI_FL_BASE0
,
1
,
115200
},
/* pbn_b0_1_115200,
pbn_default */
{
SPCI_FL_BASE0
,
2
,
115200
},
/* pbn_b0_2_115200 */
{
SPCI_FL_BASE0
,
4
,
115200
},
/* pbn_b0_4_115200 */
{
SPCI_FL_BASE0
,
1
,
921600
},
/* pbn_b0_1_921600 */
{
SPCI_FL_BASE0
,
2
,
921600
},
/* pbn_b0_2_921600 */
{
SPCI_FL_BASE0
,
4
,
921600
},
/* pbn_b0_4_921600 */
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
1
,
115200
},
/* pbn_b0_bt_1_115200 */
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
2
,
115200
},
/* pbn_b0_bt_2_115200 */
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
8
,
115200
},
/* pbn_b0_bt_8_115200 */
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
1
,
460800
},
/* pbn_b0_bt_1_460800 */
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
2
,
460800
},
/* pbn_b0_bt_2_460800 */
{
SPCI_FL_BASE1
,
1
,
115200
},
/* pbn_b1_1_115200 */
{
SPCI_FL_BASE1
,
2
,
115200
},
/* pbn_b1_2_115200 */
{
SPCI_FL_BASE1
,
4
,
115200
},
/* pbn_b1_4_115200 */
{
SPCI_FL_BASE1
,
8
,
115200
},
/* pbn_b1_8_115200 */
{
SPCI_FL_BASE1
,
2
,
921600
},
/* pbn_b1_2_921600 */
{
SPCI_FL_BASE1
,
4
,
921600
},
/* pbn_b1_4_921600 */
{
SPCI_FL_BASE1
,
8
,
921600
},
/* pbn_b1_8_921600 */
{
SPCI_FL_BASE1
,
2
,
1382400
},
/* pbn_b1_2_1382400 */
{
SPCI_FL_BASE1
,
4
,
1382400
},
/* pbn_b1_4_1382400 */
{
SPCI_FL_BASE1
,
8
,
1382400
},
/* pbn_b1_8_1382400 */
{
SPCI_FL_BASE2
,
1
,
115200
},
/* pbn_b2_1_115200 */
{
SPCI_FL_BASE2
,
8
,
115200
},
/* pbn_b2_8_115200 */
{
SPCI_FL_BASE2
,
4
,
460800
},
/* pbn_b2_4_460800 */
{
SPCI_FL_BASE2
,
8
,
460800
},
/* pbn_b2_8_460800 */
{
SPCI_FL_BASE2
,
16
,
460800
},
/* pbn_b2_16_460800 */
{
SPCI_FL_BASE2
,
4
,
921600
},
/* pbn_b2_4_921600 */
{
SPCI_FL_BASE2
,
8
,
921600
},
/* pbn_b2_8_921600 */
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
1
,
115200
},
/* pbn_b2_bt_1_115200 */
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
2
,
115200
},
/* pbn_b2_bt_2_115200 */
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
4
,
115200
},
/* pbn_b2_bt_4_115200 */
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
2
,
921600
},
/* pbn_b2_bt_2_921600 */
{
SPCI_FL_BASE2
,
2
,
921600
,
/* IOMEM */
/* pbn_panacom */
0x400
,
7
,
pci_plx9050_fn
},
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
2
,
921600
,
/* pbn_panacom2 */
0x400
,
7
,
pci_plx9050_fn
},
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
4
,
921600
,
/* pbn_panacom4 */
0x400
,
7
,
pci_plx9050_fn
},
{
SPCI_FL_BASE2
,
4
,
921600
,
/* pbn_plx_romulus */
0x20
,
2
,
pci_plx9050_fn
,
0x03
},
/*
* Panacom - IOMEM
*/
[
pbn_panacom
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
0x400
,
.
reg_shift
=
7
,
},
[
pbn_panacom2
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
2
,
.
base_baud
=
921600
,
.
uart_offset
=
0x400
,
.
reg_shift
=
7
,
},
[
pbn_panacom4
]
=
{
.
flags
=
FL_BASE2
|
FL_BASE_BARS
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
0x400
,
.
reg_shift
=
7
,
},
/* I think this entry is broken - the first_offset looks wrong --rmk */
[
pbn_plx_romulus
]
=
{
.
flags
=
FL_BASE2
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
8
<<
2
,
.
reg_shift
=
2
,
.
first_offset
=
0x03
,
},
/*
* This board uses the size of PCI Base region 0 to
* signal now many ports are available
*/
{
SPCI_FL_BASE0
|
SPCI_FL_REGION_SZ_CAP
,
32
,
115200
},
/* pbn_oxsemi */
{
SPCI_FL_BASE_TABLE
,
1
,
921600
,
/* pbn_timedia */
0
,
0
,
pci_timedia_fn
},
/* EKF addition for i960 Boards form EKF with serial port */
{
SPCI_FL_BASE0
,
32
,
921600
,
/* max 256 ports */
/* pbn_intel_i960 */
8
<<
2
,
2
,
pci_inteli960ni_fn
,
0x10000
},
{
SPCI_FL_BASE0
|
SPCI_FL_IRQRESOURCE
,
/* pbn_sgi_ioc3 */
1
,
458333
,
0
,
0
,
0
,
0x20178
},
{
SPCI_FL_BASE0
,
5
,
115200
,
8
,
0
,
pci_hp_diva
,
0
},
/* pbn_hp_diva */
[
pbn_oxsemi
]
=
{
.
flags
=
FL_BASE0
|
FL_REGION_SZ_CAP
,
.
num_ports
=
32
,
.
base_baud
=
115200
,
.
uart_offset
=
8
,
},
/*
* EKF addition for i960 Boards form EKF with serial port.
* Max 256 ports.
*/
[
pbn_intel_i960
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
32
,
.
base_baud
=
921600
,
.
uart_offset
=
8
<<
2
,
.
reg_shift
=
2
,
.
first_offset
=
0x10000
,
},
[
pbn_sgi_ioc3
]
=
{
.
flags
=
FL_BASE0
|
FL_IRQRESOURCE
,
.
num_ports
=
1
,
.
base_baud
=
458333
,
.
uart_offset
=
8
,
.
reg_shift
=
0
,
.
first_offset
=
0x20178
,
},
/*
* NEC Vrc-5074 (Nile 4) builtin UART.
*/
{
SPCI_FL_BASE0
,
1
,
520833
,
/* pbn_nec_nile4 */
64
,
3
,
NULL
,
0x300
},
{
SPCI_FL_BASE3
,
4
,
115200
,
8
},
/* pbn_dci_pccom4 */
{
SPCI_FL_BASE3
,
8
,
115200
,
8
},
/* pbn_dci_pccom8 */
{
SPCI_FL_BASE0
,
1
,
115200
,
/* pbn_xircom_combo */
0
,
0
,
pci_xircom_fn
},
{
SPCI_FL_BASE2
,
1
,
460800
,
/* pbn_siig10x_0 */
0
,
0
,
pci_siig10x_fn
},
{
SPCI_FL_BASE2
,
1
,
921600
,
/* pbn_siig10x_1 */
0
,
0
,
pci_siig10x_fn
},
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
2
,
921600
,
/* pbn_siig10x_2 */
0
,
0
,
pci_siig10x_fn
},
{
SPCI_FL_BASE2
|
SPCI_FL_BASE_TABLE
,
4
,
921600
,
/* pbn_siig10x_4 */
0
,
0
,
pci_siig10x_fn
},
{
SPCI_FL_BASE0
,
1
,
921600
,
/* pbn_siix20x_0 */
0
,
0
,
pci_siig20x_fn
},
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
2
,
921600
,
/* pbn_siix20x_2 */
0
,
0
,
pci_siig20x_fn
},
{
SPCI_FL_BASE0
|
SPCI_FL_BASE_TABLE
,
4
,
921600
,
/* pbn_siix20x_4 */
0
,
0
,
pci_siig20x_fn
},
{
SPCI_FL_BASE0
,
4
,
921600
,
/* IOMEM */
/* pbn_computone_4 */
0x40
,
2
,
NULL
,
0x200
},
{
SPCI_FL_BASE0
,
6
,
921600
,
/* IOMEM */
/* pbn_computone_6 */
0x40
,
2
,
NULL
,
0x200
},
{
SPCI_FL_BASE0
,
8
,
921600
,
/* IOMEM */
/* pbn_computone_8 */
0x40
,
2
,
NULL
,
0x200
},
[
pbn_nec_nile4
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
1
,
.
base_baud
=
520833
,
.
uart_offset
=
8
<<
3
,
.
reg_shift
=
3
,
.
first_offset
=
0x300
,
},
/*
* Computone - uses IOMEM.
*/
[
pbn_computone_4
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
4
,
.
base_baud
=
921600
,
.
uart_offset
=
0x40
,
.
reg_shift
=
2
,
.
first_offset
=
0x200
,
},
[
pbn_computone_6
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
6
,
.
base_baud
=
921600
,
.
uart_offset
=
0x40
,
.
reg_shift
=
2
,
.
first_offset
=
0x200
,
},
[
pbn_computone_8
]
=
{
.
flags
=
FL_BASE0
,
.
num_ports
=
8
,
.
base_baud
=
921600
,
.
uart_offset
=
0x40
,
.
reg_shift
=
2
,
.
first_offset
=
0x200
,
},
};
/*
...
...
@@ -640,8 +1363,7 @@ static struct pci_board pci_boards[] __devinitdata = {
static
int
__devinit
serial_pci_guess_board
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
)
{
int
num_iomem
=
0
,
num_port
=
0
,
first_port
=
-
1
;
int
i
;
int
num_iomem
,
num_port
,
first_port
=
-
1
,
i
;
/*
* If it is not a communications device or the programming
...
...
@@ -655,36 +1377,63 @@ serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board)
(
dev
->
class
&
0xff
)
>
6
)
return
-
ENODEV
;
for
(
i
=
0
;
i
<
6
;
i
++
)
{
if
(
IS_PCI_REGION_IOPORT
(
dev
,
i
))
{
num_iomem
=
num_port
=
0
;
for
(
i
=
0
;
i
<
PCI_NUM_BAR_RESOURCES
;
i
++
)
{
if
(
pci_resource_flags
(
dev
,
i
)
&
IORESOURCE_IO
)
{
num_port
++
;
if
(
first_port
==
-
1
)
first_port
=
i
;
}
if
(
IS_PCI_REGION_IOMEM
(
dev
,
i
)
)
if
(
pci_resource_flags
(
dev
,
i
)
&
IORESOURCE_MEM
)
num_iomem
++
;
}
/*
* If there is 1 or 0 iomem regions, and exactly one port, use
* it.
* If there is 1 or 0 iomem regions, and exactly one port,
* use it. We guess the number of ports based on the IO
* region size.
*/
if
(
num_iomem
<=
1
&&
num_port
==
1
)
{
board
->
flags
=
first_port
;
board
->
num_ports
=
pci_resource_len
(
dev
,
first_port
)
/
8
;
return
0
;
}
/*
* Now guess if we've got a board which indexes by BARs.
* Each IO BAR should be 8 bytes, and they should follow
* consecutively.
*/
first_port
=
-
1
;
num_port
=
0
;
for
(
i
=
0
;
i
<
PCI_NUM_BAR_RESOURCES
;
i
++
)
{
if
(
pci_resource_flags
(
dev
,
i
)
&
IORESOURCE_IO
&&
pci_resource_len
(
dev
,
i
)
==
8
&&
(
first_port
==
-
1
||
(
first_port
+
num_port
)
==
i
))
{
num_port
++
;
if
(
first_port
==
-
1
)
first_port
=
i
;
}
}
if
(
num_port
>
1
)
{
board
->
flags
=
first_port
|
FL_BASE_BARS
;
board
->
num_ports
=
num_port
;
return
0
;
}
return
-
ENODEV
;
}
static
inline
int
serial_pci_matches
(
struct
pci_board
*
board
,
int
index
)
serial_pci_matches
(
struct
pci_board
*
board
,
struct
pci_board
*
guessed
)
{
return
board
->
base_baud
==
pci_boards
[
index
].
base_baud
&&
board
->
num_ports
==
pci_boards
[
index
].
num_ports
&&
board
->
uart_offset
==
pci_boards
[
index
].
uart_offset
&&
board
->
reg_shift
==
pci_boards
[
index
].
reg_shift
&&
board
->
first_
uart_offset
==
pci_boards
[
index
].
first_uar
t_offset
;
board
->
num_ports
==
guessed
->
num_ports
&&
board
->
base_baud
==
guessed
->
base_baud
&&
board
->
uart_offset
==
guessed
->
uart_offset
&&
board
->
reg_shift
==
guessed
->
reg_shift
&&
board
->
first_
offset
==
guessed
->
firs
t_offset
;
}
/*
...
...
@@ -692,10 +1441,11 @@ serial_pci_matches(struct pci_board *board, int index)
* to the arrangement of serial ports on a PCI card.
*/
static
int
__devinit
pci_init_one
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
ent
)
pci
serial
_init_one
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
ent
)
{
struct
serial_private
*
priv
;
struct
pci_board
*
board
,
tmp
;
struct
pci_serial_quirk
*
quirk
;
struct
serial_struct
serial_req
;
int
base_baud
,
rc
,
nr_ports
,
i
;
...
...
@@ -732,92 +1482,109 @@ pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
* detect this boards settings with our heuristic,
* then we no longer need this entry.
*/
memcpy
(
&
tmp
,
&
pci_boards
[
pbn_default
],
sizeof
(
struct
pci_board
));
rc
=
serial_pci_guess_board
(
dev
,
&
tmp
);
if
(
rc
==
0
&&
serial_pci_matches
(
board
,
pbn_default
))
{
printk
(
KERN_INFO
"Redundant entry in serial pci_table. Please send the output
\n
"
"of lspci -vv, this message (0x%04x,0x%04x,0x%04x,0x%04x),
\n
"
"the manufacturer and name of serial board or modem board to
\n
"
"rmk@arm.linux.org.uk.
\n
"
,
dev
->
vendor
,
dev
->
device
,
pci_get_subvendor
(
dev
),
pci_get_subdevice
(
dev
));
}
if
(
rc
==
0
&&
serial_pci_matches
(
board
,
&
tmp
))
moan_device
(
"Redundant entry in serial pci_table."
,
dev
);
}
nr_ports
=
board
->
num_ports
;
/*
* Run the initialization function, if any. The initialization
* function returns:
* Find an init and setup quirks.
*/
quirk
=
find_quirk
(
dev
);
/*
* Run the new-style initialization function.
* The initialization function returns:
* <0 - error
* 0 - use board->num_ports
* >0 - number of ports
*/
if
(
board
->
init_fn
)
{
rc
=
board
->
init_fn
(
dev
,
1
);
if
(
quirk
->
init
)
{
rc
=
quirk
->
init
(
dev
);
if
(
rc
<
0
)
goto
disable
;
if
(
rc
)
nr_ports
=
rc
;
}
priv
=
kmalloc
(
sizeof
(
struct
serial_private
)
+
sizeof
(
unsigned
int
)
*
nr_ports
,
GFP_KERNEL
);
sizeof
(
unsigned
int
)
*
nr_ports
,
GFP_KERNEL
);
if
(
!
priv
)
{
rc
=
-
ENOMEM
;
goto
deinit
;
}
memset
(
priv
,
0
,
sizeof
(
struct
serial_private
)
+
sizeof
(
unsigned
int
)
*
nr_ports
);
priv
->
quirk
=
quirk
;
pci_set_drvdata
(
dev
,
priv
);
base_baud
=
board
->
base_baud
;
if
(
!
base_baud
)
if
(
!
base_baud
)
{
moan_device
(
"Board entry does not specify baud rate."
,
dev
);
base_baud
=
BASE_BAUD
;
memset
(
&
serial_req
,
0
,
sizeof
(
serial_req
));
}
for
(
i
=
0
;
i
<
nr_ports
;
i
++
)
{
memset
(
&
serial_req
,
0
,
sizeof
(
serial_req
));
serial_req
.
flags
=
UPF_SKIP_TEST
|
UPF_AUTOPROBE
|
UPF_RESOURCES
|
UPF_SHARE_IRQ
;
serial_req
.
baud_base
=
base_baud
;
serial_req
.
irq
=
get_pci_irq
(
dev
,
board
,
i
);
if
(
get_pci_port
(
dev
,
board
,
&
serial_req
,
i
))
if
(
quirk
->
setup
(
dev
,
board
,
&
serial_req
,
i
))
break
;
#ifdef SERIAL_DEBUG_PCI
printk
(
"Setup PCI port: port %x, irq %d, type %d
\n
"
,
serial_req
.
port
,
serial_req
.
irq
,
serial_req
.
io_type
);
#endif
serial_req
.
flags
=
ASYNC_SKIP_TEST
|
ASYNC_AUTOPROBE
;
serial_req
.
baud_base
=
base_baud
;
priv
->
line
[
i
]
=
register_serial
(
&
serial_req
);
if
(
priv
->
line
[
i
]
<
0
)
break
;
}
priv
->
board
=
board
;
priv
->
nr
=
i
;
pci_set_drvdata
(
dev
,
priv
);
return
0
;
deinit:
if
(
board
->
init_fn
)
board
->
init_fn
(
dev
,
0
);
if
(
quirk
->
exit
)
quirk
->
exit
(
dev
);
disable:
pci_disable_device
(
dev
);
return
rc
;
}
static
void
__devexit
pci_remove_one
(
struct
pci_dev
*
dev
)
static
void
__devexit
pci
serial
_remove_one
(
struct
pci_dev
*
dev
)
{
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
int
i
;
pci_set_drvdata
(
dev
,
NULL
);
if
(
priv
)
{
struct
pci_serial_quirk
*
quirk
;
int
i
;
for
(
i
=
0
;
i
<
priv
->
nr
;
i
++
)
unregister_serial
(
priv
->
line
[
i
]);
if
(
priv
->
board
->
init_fn
)
priv
->
board
->
init_fn
(
dev
,
0
);
for
(
i
=
0
;
i
<
PCI_NUM_BAR_RESOURCES
;
i
++
)
{
if
(
priv
->
remapped_bar
[
i
])
iounmap
(
priv
->
remapped_bar
[
i
]);
priv
->
remapped_bar
[
i
]
=
NULL
;
}
/*
* Find the exit quirks.
*/
quirk
=
find_quirk
(
dev
);
if
(
quirk
->
exit
)
quirk
->
exit
(
dev
);
pci_disable_device
(
dev
);
...
...
@@ -825,6 +1592,53 @@ static void __devexit pci_remove_one(struct pci_dev *dev)
}
}
static
int
pciserial_save_state_one
(
struct
pci_dev
*
dev
,
u32
state
)
{
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
if
(
priv
)
{
int
i
;
for
(
i
=
0
;
i
<
priv
->
nr
;
i
++
)
serial8250_suspend_port
(
priv
->
line
[
i
],
SUSPEND_SAVE_STATE
);
}
return
0
;
}
static
int
pciserial_suspend_one
(
struct
pci_dev
*
dev
,
u32
state
)
{
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
if
(
priv
)
{
int
i
;
for
(
i
=
0
;
i
<
priv
->
nr
;
i
++
)
serial8250_suspend_port
(
priv
->
line
[
i
],
SUSPEND_POWER_DOWN
);
}
return
0
;
}
static
int
pciserial_resume_one
(
struct
pci_dev
*
dev
)
{
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
if
(
priv
)
{
int
i
;
/*
* Ensure that the board is correctly configured.
*/
if
(
priv
->
quirk
->
init
)
priv
->
quirk
->
init
(
dev
);
for
(
i
=
0
;
i
<
priv
->
nr
;
i
++
)
{
serial8250_resume_port
(
priv
->
line
[
i
],
RESUME_POWER_ON
);
serial8250_resume_port
(
priv
->
line
[
i
],
RESUME_RESTORE_STATE
);
}
}
return
0
;
}
static
struct
pci_device_id
serial_pci_tbl
[]
__devinitdata
=
{
{
PCI_VENDOR_ID_V3
,
PCI_DEVICE_ID_V3_V960
,
PCI_SUBVENDOR_ID_CONNECT_TECH
,
...
...
@@ -908,7 +1722,9 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
{
PCI_VENDOR_ID_PLX
,
PCI_DEVICE_ID_PLX_SPCOM200
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b2_bt_2_921600
},
/* VScom SPCOM800, from sl@s.pl */
/*
* VScom SPCOM800, from sl@s.pl
*/
{
PCI_VENDOR_ID_PLX
,
PCI_DEVICE_ID_PLX_SPCOM800
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b2_8_921600
},
...
...
@@ -949,8 +1765,10 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
PCI_SUBVENDOR_ID_CHASE_PCIRAS
,
PCI_SUBDEVICE_ID_CHASE_PCIRAS8
,
0
,
0
,
pbn_b2_8_460800
},
/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
/* (Exoray@isys.ca) */
/*
* Megawolf Romulus PCI Serial Card, from Mike Hudson
* (Exoray@isys.ca)
*/
{
PCI_VENDOR_ID_PLX
,
PCI_DEVICE_ID_PLX_ROMULUS
,
0x10b5
,
0x106a
,
0
,
0
,
pbn_plx_romulus
},
...
...
@@ -976,16 +1794,24 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_2_115200
},
/* Digitan DS560-558, from jimd@esoft.com */
/*
* Digitan DS560-558, from jimd@esoft.com
*/
{
PCI_VENDOR_ID_ATT
,
PCI_DEVICE_ID_ATT_VENUS_MODEM
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b1_1_115200
},
/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
/*
* 3Com US Robotics 56k Voice Internal PCI model 5610
*/
{
PCI_VENDOR_ID_USR
,
0x1008
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_1_115200
},
/* Titan Electronic cards */
/*
* Titan Electronic cards
* The 400L and 800L have a custom setup quirk.
*/
{
PCI_VENDOR_ID_TITAN
,
PCI_DEVICE_ID_TITAN_100
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_1_921600
},
...
...
@@ -999,120 +1825,76 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_4_921600
},
{
PCI_VENDOR_ID_TITAN
,
PCI_DEVICE_ID_TITAN_100L
,
PCI_ANY_ID
,
PCI_ANY_ID
,
SPCI_FL_BASE1
,
1
,
921600
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b1_1_
921600
},
{
PCI_VENDOR_ID_TITAN
,
PCI_DEVICE_ID_TITAN_200L
,
PCI_ANY_ID
,
PCI_ANY_ID
,
SPCI_FL_BASE1
|
SPCI_FL_BASE_TABLE
,
2
,
921600
},
/* The 400L and 800L have a custom hack in get_pci_port */
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b1_bt_2_921600
},
{
PCI_VENDOR_ID_TITAN
,
PCI_DEVICE_ID_TITAN_400L
,
PCI_ANY_ID
,
PCI_ANY_ID
,
SPCI_FL_BASE_TABLE
,
4
,
921600
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_4_
921600
},
{
PCI_VENDOR_ID_TITAN
,
PCI_DEVICE_ID_TITAN_800L
,
PCI_ANY_ID
,
PCI_ANY_ID
,
SPCI_FL_BASE_TABLE
,
8
,
921600
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_8_
921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_10x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_
0
},
pbn_
b2_1_46080
0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_10x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_
0
},
pbn_
b2_1_46080
0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_10x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_10x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_1
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_10x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_1
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_10x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_1
},
pbn_b2_1_460800
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_10x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_2
},
pbn_
b2_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_10x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_2
},
pbn_
b2_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_10x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_10x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_10x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_10x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig10x_2
},
pbn_b2_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_10x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_4
},
pbn_
b2_bt_4_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_10x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_4
},
pbn_
b2_bt_4_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_10x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig10x_4
},
pbn_
b2_bt_4_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_
0
},
pbn_
b0_1_92160
0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_
0
},
pbn_
b0_1_92160
0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_1S1P_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2P1S_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2P1S_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2P1S_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_0
},
pbn_b0_1_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_2
},
pbn_
b0_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_2
},
pbn_
b0_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_2
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_2S1P_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_siig20x_2
},
pbn_b0_bt_2_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_20x_550
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_4
},
pbn_
b0_bt_4_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_20x_650
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_4
},
pbn_
b0_bt_4_921600
},
{
PCI_VENDOR_ID_SIIG
,
PCI_DEVICE_ID_SIIG_4S_20x_850
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
siig20x_4
},
pbn_
b0_bt_4_921600
},
/* Computone devices submitted by Doug McNash dmcnash@computone.com */
/*
* Computone devices submitted by Doug McNash dmcnash@computone.com
*/
{
PCI_VENDOR_ID_COMPUTONE
,
PCI_DEVICE_ID_COMPUTONE_PG
,
PCI_SUBVENDOR_ID_COMPUTONE
,
PCI_SUBDEVICE_ID_COMPUTONE_PG4
,
0
,
0
,
pbn_computone_4
},
...
...
@@ -1124,18 +1906,22 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
0
,
0
,
pbn_computone_6
},
{
PCI_VENDOR_ID_OXSEMI
,
PCI_DEVICE_ID_OXSEMI_16PCI95N
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_oxsemi
},
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_oxsemi
},
{
PCI_VENDOR_ID_TIMEDIA
,
PCI_DEVICE_ID_TIMEDIA_1889
,
PCI_VENDOR_ID_TIMEDIA
,
PCI_ANY_ID
,
0
,
0
,
pbn_timedia
},
PCI_VENDOR_ID_TIMEDIA
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_1_921600
},
{
PCI_VENDOR_ID_LAVA
,
PCI_DEVICE_ID_LAVA_DSERIAL
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_2_115200
},
/* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */
/*
* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
*/
{
PCI_VENDOR_ID_AFAVLAB
,
PCI_DEVICE_ID_AFAVLAB_P028
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_8_115200
},
{
PCI_VENDOR_ID_LAVA
,
PCI_DEVICE_ID_LAVA_DSERIAL
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_2_115200
},
{
PCI_VENDOR_ID_LAVA
,
PCI_DEVICE_ID_LAVA_QUATRO_A
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_2_115200
},
...
...
@@ -1158,26 +1944,40 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_bt_1_460800
},
/* RAStel 2 port modem, gerg@moreton.com.au */
/*
* RAStel 2 port modem, gerg@moreton.com.au
*/
{
PCI_VENDOR_ID_MORETON
,
PCI_DEVICE_ID_RASTEL_2PORT
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b2_bt_2_115200
},
/* EKF addition for i960 Boards form EKF with serial port */
{
PCI_VENDOR_ID_INTEL
,
0x1960
,
/*
* EKF addition for i960 Boards form EKF with serial port
*/
{
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_80960_RP
,
0xE4BF
,
PCI_ANY_ID
,
0
,
0
,
pbn_intel_i960
},
/* Xircom Cardbus/Ethernet combos */
/*
* Xircom Cardbus/Ethernet combos
*/
{
PCI_VENDOR_ID_XIRCOM
,
PCI_DEVICE_ID_XIRCOM_X3201_MDM
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_xircom_combo
},
pbn_b0_1_115200
},
/*
* Xircom RBM56G cardbus modem - Dirk Arnold (temp entry)
*/
{
PCI_VENDOR_ID_XIRCOM
,
PCI_DEVICE_ID_XIRCOM_RBM56G
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b0_1_115200
},
/*
* Untested PCI modems, sent in from various folks...
*/
/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
/*
* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de>
*/
{
PCI_VENDOR_ID_ROCKWELL
,
0x1004
,
0x1048
,
0x1500
,
0
,
0
,
pbn_b1_1_115200
},
...
...
@@ -1186,10 +1986,12 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
0xFF00
,
0
,
0
,
0
,
pbn_sgi_ioc3
},
/* HP Diva card */
/*
* HP Diva card
*/
{
PCI_VENDOR_ID_HP
,
PCI_DEVICE_ID_HP_DIVA
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
hp_diva
},
pbn_
b0_5_115200
},
{
PCI_VENDOR_ID_HP
,
PCI_DEVICE_ID_HP_DIVA_AUX
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_b2_1_115200
},
...
...
@@ -1203,15 +2005,14 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
{
PCI_VENDOR_ID_DCI
,
PCI_DEVICE_ID_DCI_PCCOM4
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
dci_pccom4
},
pbn_
b3_4_115200
},
{
PCI_VENDOR_ID_DCI
,
PCI_DEVICE_ID_DCI_PCCOM8
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
pbn_
dci_pccom8
},
pbn_
b3_8_115200
},
/*
* These entries match devices with class
* COMMUNICATION_SERIAL, COMMUNICATION_MODEM
* or COMMUNICATION_MULTISERIAL
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
{
PCI_ANY_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,
PCI_ANY_ID
,
...
...
@@ -1230,9 +2031,15 @@ static struct pci_device_id serial_pci_tbl[] __devinitdata = {
static
struct
pci_driver
serial_pci_driver
=
{
.
name
=
"serial"
,
.
probe
=
pci_init_one
,
.
remove
=
__devexit_p
(
pci_remove_one
),
.
probe
=
pciserial_init_one
,
.
remove
=
__devexit_p
(
pciserial_remove_one
),
.
save_state
=
pciserial_save_state_one
,
.
suspend
=
pciserial_suspend_one
,
.
resume
=
pciserial_resume_one
,
.
id_table
=
serial_pci_tbl
,
.
driver
=
{
.
devclass
=
&
tty_devclass
,
},
};
static
int
__init
serial8250_pci_init
(
void
)
...
...
drivers/serial/core.c
View file @
0deb87aa
...
...
@@ -21,9 +21,6 @@
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: core.c,v 1.100 2002/07/28 10:03:28 rmk Exp $
*
*/
#include <linux/config.h>
#include <linux/module.h>
...
...
@@ -31,9 +28,9 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/pm.h>
#include <linux/serial_core.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/serial.h>
/* for serial_state and serial_icounter_struct */
#include <asm/irq.h>
...
...
@@ -46,11 +43,6 @@
#define DPRINTK(x...) do { } while (0)
#endif
#ifndef CONFIG_PM
#define pm_access(pm) do { } while (0)
#define pm_unregister(pm) do { } while (0)
#endif
/*
* This is used to lock changes in serial line configuration.
*/
...
...
@@ -58,8 +50,17 @@ static DECLARE_MUTEX(port_sem);
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
static
void
uart_change_speed
(
struct
uart_info
*
info
,
struct
termios
*
old_termios
);
#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
#else
#define uart_console(port) (0)
#endif
static
void
uart_change_speed
(
struct
uart_state
*
state
,
struct
termios
*
old_termios
);
static
void
uart_wait_until_sent
(
struct
tty_struct
*
tty
,
int
timeout
);
static
void
uart_change_pm
(
struct
uart_state
*
state
,
int
pm_state
);
/*
* This routine is used by the interrupt handler to schedule processing in
...
...
@@ -73,8 +74,8 @@ void uart_write_wakeup(struct uart_port *port)
static
void
uart_stop
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
...
...
@@ -84,32 +85,31 @@ static void uart_stop(struct tty_struct *tty)
static
void
__uart_start
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
if
(
!
uart_circ_empty
(
&
info
->
xmit
)
&&
info
->
xmit
.
buf
&&
if
(
!
uart_circ_empty
(
&
state
->
info
->
xmit
)
&&
state
->
info
->
xmit
.
buf
&&
!
tty
->
stopped
&&
!
tty
->
hw_stopped
)
port
->
ops
->
start_tx
(
port
,
1
);
}
static
void
uart_start
(
struct
tty_struct
*
tty
)
{
struct
uart_info
*
info
=
tty
->
driver_data
;
struct
uart_state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
flags
;
pm_access
(
info
->
state
->
pm
);
spin_lock_irqsave
(
&
info
->
port
->
lock
,
flags
);
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
__uart_start
(
tty
);
spin_unlock_irqrestore
(
&
info
->
port
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
}
static
void
uart_tasklet_action
(
unsigned
long
data
)
{
struct
uart_
info
*
info
=
(
struct
uart_info
*
)
data
;
struct
uart_
state
*
state
=
(
struct
uart_state
*
)
data
;
struct
tty_struct
*
tty
;
tty
=
info
->
tty
;
tty
=
state
->
info
->
tty
;
if
(
tty
)
{
if
((
tty
->
flags
&
(
1
<<
TTY_DO_WRITE_WAKEUP
))
&&
tty
->
ldisc
.
write_wakeup
)
...
...
@@ -137,11 +137,12 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
/*
* Startup the port. This will be called once per open. All calls
* will be serialised by the
global
port semaphore.
* will be serialised by the
per-
port semaphore.
*/
static
int
uart_startup
(
struct
uart_
info
*
info
,
int
init_hw
)
static
int
uart_startup
(
struct
uart_
state
*
state
,
int
init_hw
)
{
struct
uart_port
*
port
=
info
->
port
;
struct
uart_info
*
info
=
state
->
info
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
page
;
int
retval
=
0
;
...
...
@@ -182,7 +183,7 @@ static int uart_startup(struct uart_info *info, int init_hw)
/*
* Initialise the hardware port settings.
*/
uart_change_speed
(
info
,
NULL
);
uart_change_speed
(
state
,
NULL
);
/*
* Setup the RTS and DTR signals once the
...
...
@@ -194,8 +195,7 @@ static int uart_startup(struct uart_info *info, int init_hw)
info
->
flags
|=
UIF_INITIALIZED
;
if
(
info
->
tty
)
clear_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
clear_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
}
if
(
retval
&&
capable
(
CAP_SYS_ADMIN
))
...
...
@@ -207,11 +207,12 @@ static int uart_startup(struct uart_info *info, int init_hw)
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on. Calls to
* uart_shutdown are serialised by
port_sem
.
* uart_shutdown are serialised by
the per-port semaphore
.
*/
static
void
uart_shutdown
(
struct
uart_
info
*
info
)
static
void
uart_shutdown
(
struct
uart_
state
*
state
)
{
struct
uart_port
*
port
=
info
->
port
;
struct
uart_info
*
info
=
state
->
info
;
struct
uart_port
*
port
=
state
->
port
;
if
(
!
(
info
->
flags
&
UIF_INITIALIZED
))
return
;
...
...
@@ -220,7 +221,7 @@ static void uart_shutdown(struct uart_info *info)
* Turn off DTR and RTS early.
*/
if
(
!
info
->
tty
||
(
info
->
tty
->
termios
->
c_cflag
&
HUPCL
))
uart_clear_mctrl
(
info
->
port
,
TIOCM_DTR
|
TIOCM_RTS
);
uart_clear_mctrl
(
port
,
TIOCM_DTR
|
TIOCM_RTS
);
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free
...
...
@@ -412,10 +413,10 @@ uart_get_divisor(struct uart_port *port, unsigned int baud)
EXPORT_SYMBOL
(
uart_get_divisor
);
static
void
uart_change_speed
(
struct
uart_
info
*
info
,
struct
termios
*
old_termios
)
uart_change_speed
(
struct
uart_
state
*
state
,
struct
termios
*
old_termios
)
{
struct
tty_struct
*
tty
=
info
->
tty
;
struct
uart_port
*
port
=
info
->
port
;
struct
tty_struct
*
tty
=
state
->
info
->
tty
;
struct
uart_port
*
port
=
state
->
port
;
struct
termios
*
termios
;
/*
...
...
@@ -431,14 +432,14 @@ uart_change_speed(struct uart_info *info, struct termios *old_termios)
* Set flags based on termios cflag
*/
if
(
termios
->
c_cflag
&
CRTSCTS
)
info
->
flags
|=
UIF_CTS_FLOW
;
state
->
info
->
flags
|=
UIF_CTS_FLOW
;
else
info
->
flags
&=
~
UIF_CTS_FLOW
;
state
->
info
->
flags
&=
~
UIF_CTS_FLOW
;
if
(
termios
->
c_cflag
&
CLOCAL
)
info
->
flags
&=
~
UIF_CHECK_CD
;
state
->
info
->
flags
&=
~
UIF_CHECK_CD
;
else
info
->
flags
|=
UIF_CHECK_CD
;
state
->
info
->
flags
|=
UIF_CHECK_CD
;
port
->
ops
->
set_termios
(
port
,
termios
,
old_termios
);
}
...
...
@@ -526,10 +527,10 @@ __uart_kern_write(struct uart_port *port, struct circ_buf *circ,
static
void
uart_put_char
(
struct
tty_struct
*
tty
,
unsigned
char
ch
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
if
(
tty
)
__uart_put_char
(
info
->
port
,
&
info
->
xmit
,
ch
);
__uart_put_char
(
state
->
port
,
&
state
->
info
->
xmit
,
ch
);
}
static
void
uart_flush_chars
(
struct
tty_struct
*
tty
)
...
...
@@ -541,16 +542,16 @@ static int
uart_write
(
struct
tty_struct
*
tty
,
int
from_user
,
const
unsigned
char
*
buf
,
int
count
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
int
ret
;
if
(
!
tty
||
!
info
->
xmit
.
buf
)
if
(
!
tty
||
!
state
->
info
->
xmit
.
buf
)
return
0
;
if
(
from_user
)
ret
=
__uart_user_write
(
info
->
port
,
&
info
->
xmit
,
buf
,
count
);
ret
=
__uart_user_write
(
state
->
port
,
&
state
->
info
->
xmit
,
buf
,
count
);
else
ret
=
__uart_kern_write
(
info
->
port
,
&
info
->
xmit
,
buf
,
count
);
ret
=
__uart_kern_write
(
state
->
port
,
&
state
->
info
->
xmit
,
buf
,
count
);
uart_start
(
tty
);
return
ret
;
...
...
@@ -558,29 +559,30 @@ uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf,
static
int
uart_write_room
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
return
uart_circ_chars_free
(
&
info
->
xmit
);
return
uart_circ_chars_free
(
&
state
->
info
->
xmit
);
}
static
int
uart_chars_in_buffer
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
return
uart_circ_chars_pending
(
&
info
->
xmit
);
return
uart_circ_chars_pending
(
&
state
->
info
->
xmit
);
}
static
void
uart_flush_buffer
(
struct
tty_struct
*
tty
)
{
struct
uart_info
*
info
=
tty
->
driver_data
;
struct
uart_state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
flags
;
DPRINTK
(
"uart_flush_buffer(%d) called
\n
"
,
minor
(
tty
->
device
)
-
tty
->
driver
.
minor_start
);
spin_lock_irqsave
(
&
info
->
port
->
lock
,
flags
);
uart_circ_clear
(
&
info
->
xmit
);
spin_unlock_irqrestore
(
&
info
->
port
->
lock
,
flags
);
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
uart_circ_clear
(
&
state
->
info
->
xmit
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
wake_up_interruptible
(
&
tty
->
write_wait
);
if
((
tty
->
flags
&
(
1
<<
TTY_DO_WRITE_WAKEUP
))
&&
tty
->
ldisc
.
write_wakeup
)
...
...
@@ -593,8 +595,8 @@ static void uart_flush_buffer(struct tty_struct *tty)
*/
static
void
uart_send_xchar
(
struct
tty_struct
*
tty
,
char
ch
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
flags
;
if
(
port
->
ops
->
send_xchar
)
...
...
@@ -611,19 +613,19 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static
void
uart_throttle
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
if
(
I_IXOFF
(
tty
))
uart_send_xchar
(
tty
,
STOP_CHAR
(
tty
));
if
(
tty
->
termios
->
c_cflag
&
CRTSCTS
)
uart_clear_mctrl
(
info
->
port
,
TIOCM_RTS
);
uart_clear_mctrl
(
state
->
port
,
TIOCM_RTS
);
}
static
void
uart_unthrottle
(
struct
tty_struct
*
tty
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
if
(
I_IXOFF
(
tty
))
{
if
(
port
->
x_char
)
...
...
@@ -636,10 +638,9 @@ static void uart_unthrottle(struct tty_struct *tty)
uart_set_mctrl
(
port
,
TIOCM_RTS
);
}
static
int
uart_get_info
(
struct
uart_
info
*
info
,
struct
serial_struct
*
retinfo
)
static
int
uart_get_info
(
struct
uart_
state
*
state
,
struct
serial_struct
*
retinfo
)
{
struct
uart_state
*
state
=
info
->
state
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_port
*
port
=
state
->
port
;
struct
serial_struct
tmp
;
memset
(
&
tmp
,
0
,
sizeof
(
tmp
));
...
...
@@ -649,7 +650,7 @@ static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo)
if
(
HIGH_BITS_OFFSET
)
tmp
.
port_high
=
(
long
)
port
->
iobase
>>
HIGH_BITS_OFFSET
;
tmp
.
irq
=
port
->
irq
;
tmp
.
flags
=
port
->
flags
|
info
->
flags
;
tmp
.
flags
=
port
->
flags
;
tmp
.
xmit_fifo_size
=
port
->
fifosize
;
tmp
.
baud_base
=
port
->
uartclk
/
16
;
tmp
.
close_delay
=
state
->
close_delay
;
...
...
@@ -666,11 +667,10 @@ static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo)
}
static
int
uart_set_info
(
struct
uart_
info
*
info
,
struct
serial_struct
*
newinfo
)
uart_set_info
(
struct
uart_
state
*
state
,
struct
serial_struct
*
newinfo
)
{
struct
serial_struct
new_serial
;
struct
uart_state
*
state
=
info
->
state
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
new_port
;
unsigned
int
change_irq
,
change_port
,
old_flags
;
unsigned
int
old_custom_divisor
;
...
...
@@ -692,7 +692,7 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
* module insertion/removal doesn't change anything
* under us.
*/
down
(
&
port_
sem
);
down
(
&
state
->
sem
);
change_irq
=
new_serial
.
irq
!=
port
->
irq
;
...
...
@@ -745,14 +745,14 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
/*
* Make sure that we are the sole user of this port.
*/
if
(
state
->
count
>
1
||
info
->
blocked_open
!=
0
)
if
(
uart_users
(
state
)
>
1
)
goto
exit
;
/*
* We need to shutdown the serial port at the old
* port/type/irq combination.
*/
uart_shutdown
(
info
);
uart_shutdown
(
state
);
}
if
(
change_port
)
{
...
...
@@ -813,18 +813,21 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
port
->
irq
=
new_serial
.
irq
;
port
->
uartclk
=
new_serial
.
baud_base
*
16
;
port
->
flags
=
new_serial
.
flags
&
UPF_CHANGE_MASK
;
port
->
flags
=
(
port
->
flags
&
~
UPF_CHANGE_MASK
)
|
(
new_serial
.
flags
&
UPF_CHANGE_MASK
);
port
->
custom_divisor
=
new_serial
.
custom_divisor
;
state
->
close_delay
=
new_serial
.
close_delay
*
HZ
/
100
;
state
->
closing_wait
=
new_serial
.
closing_wait
*
HZ
/
100
;
port
->
fifosize
=
new_serial
.
xmit_fifo_size
;
info
->
tty
->
low_latency
=
(
port
->
flags
&
UPF_LOW_LATENCY
)
?
1
:
0
;
if
(
state
->
info
->
tty
)
state
->
info
->
tty
->
low_latency
=
(
port
->
flags
&
UPF_LOW_LATENCY
)
?
1
:
0
;
check_and_exit:
retval
=
0
;
if
(
port
->
type
==
PORT_UNKNOWN
)
goto
exit
;
if
(
info
->
flags
&
UIF_INITIALIZED
)
{
if
(
state
->
info
->
flags
&
UIF_INITIALIZED
)
{
if
(((
old_flags
^
port
->
flags
)
&
UPF_SPD_MASK
)
||
old_custom_divisor
!=
port
->
custom_divisor
)
{
/* If they're setting up a custom divisor or speed,
...
...
@@ -832,25 +835,26 @@ uart_set_info(struct uart_info *info, struct serial_struct *newinfo)
* need to rate-limit; it's CAP_SYS_ADMIN only. */
if
(
port
->
flags
&
UPF_SPD_MASK
)
{
printk
(
KERN_NOTICE
"%s sets custom speed on %s%d. This is deprecated.
\n
"
,
current
->
comm
,
info
->
tty
->
driver
.
name
,
info
->
port
->
line
);
current
->
comm
,
state
->
info
->
tty
->
driver
.
name
,
state
->
port
->
line
);
}
uart_change_speed
(
info
,
NULL
);
uart_change_speed
(
state
,
NULL
);
}
}
else
retval
=
uart_startup
(
info
,
1
);
retval
=
uart_startup
(
state
,
1
);
exit:
up
(
&
port_
sem
);
up
(
&
state
->
sem
);
return
retval
;
}
/*
* uart_get_lsr_info - get line status register info
* uart_get_lsr_info - get line status register info.
* Note: uart_ioctl protects us against hangups.
*/
static
int
uart_get_lsr_info
(
struct
uart_
info
*
info
,
unsigned
int
*
value
)
static
int
uart_get_lsr_info
(
struct
uart_
state
*
state
,
unsigned
int
*
value
)
{
struct
uart_port
*
port
=
info
->
port
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
int
result
;
result
=
port
->
ops
->
tx_empty
(
port
);
...
...
@@ -861,9 +865,9 @@ static int uart_get_lsr_info(struct uart_info *info, unsigned int *value)
* avoid a race condition (depending on when the transmit
* interrupt happens).
*/
if
(
info
->
port
->
x_char
||
((
uart_circ_chars_pending
(
&
info
->
xmit
)
>
0
)
&&
!
info
->
tty
->
stopped
&&
!
info
->
tty
->
hw_stopped
))
if
(
port
->
x_char
||
((
uart_circ_chars_pending
(
&
state
->
info
->
xmit
)
>
0
)
&&
!
state
->
info
->
tty
->
stopped
&&
!
state
->
info
->
tty
->
hw_stopped
))
result
&=
~
TIOCSER_TEMT
;
return
put_user
(
result
,
value
);
...
...
@@ -888,6 +892,8 @@ uart_set_modem_info(struct uart_port *port, unsigned int cmd,
if
(
get_user
(
arg
,
value
))
return
-
EFAULT
;
arg
&=
TIOCM_DTR
|
TIOCM_RTS
|
TIOCM_OUT1
|
TIOCM_OUT2
;
set
=
clear
=
0
;
switch
(
cmd
)
{
case
TIOCMBIS
:
...
...
@@ -911,8 +917,8 @@ uart_set_modem_info(struct uart_port *port, unsigned int cmd,
static
void
uart_break_ctl
(
struct
tty_struct
*
tty
,
int
break_state
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
BUG_ON
(
!
kernel_locked
());
...
...
@@ -920,25 +926,25 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state)
port
->
ops
->
break_ctl
(
port
,
break_state
);
}
static
int
uart_do_autoconfig
(
struct
uart_
info
*
info
)
static
int
uart_do_autoconfig
(
struct
uart_
state
*
state
)
{
struct
uart_port
*
port
=
info
->
port
;
struct
uart_port
*
port
=
state
->
port
;
int
flags
,
ret
;
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
/*
* Take the
'count' lock. This prevents count
*
from incrementing, and hence any extra opens
*
of the port while we're auto-configg
ing.
* Take the
per-port semaphore. This prevents count from
*
changing, and hence any extra opens of the port while
*
we're auto-configur
ing.
*/
if
(
down_interruptible
(
&
port_
sem
))
if
(
down_interruptible
(
&
state
->
sem
))
return
-
ERESTARTSYS
;
ret
=
-
EBUSY
;
if
(
info
->
state
->
count
==
1
&&
info
->
blocked_open
==
0
)
{
uart_shutdown
(
info
);
if
(
uart_users
(
state
)
==
1
)
{
uart_shutdown
(
state
);
/*
* If we already have a port type configured,
...
...
@@ -957,16 +963,22 @@ static int uart_do_autoconfig(struct uart_info *info)
*/
port
->
ops
->
config_port
(
port
,
flags
);
ret
=
uart_startup
(
info
,
1
);
ret
=
uart_startup
(
state
,
1
);
}
up
(
&
port_
sem
);
up
(
&
state
->
sem
);
return
ret
;
}
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
static
int
uart_wait_modem_status
(
struct
uart_
info
*
info
,
unsigned
long
arg
)
uart_wait_modem_status
(
struct
uart_
state
*
state
,
unsigned
long
arg
)
{
struct
uart_port
*
port
=
info
->
port
;
struct
uart_port
*
port
=
state
->
port
;
DECLARE_WAITQUEUE
(
wait
,
current
);
struct
uart_icount
cprev
,
cnow
;
int
ret
;
...
...
@@ -983,7 +995,7 @@ uart_wait_modem_status(struct uart_info *info, unsigned long arg)
port
->
ops
->
enable_ms
(
port
);
spin_unlock_irq
(
&
port
->
lock
);
add_wait_queue
(
&
info
->
delta_msr_wait
,
&
wait
);
add_wait_queue
(
&
state
->
info
->
delta_msr_wait
,
&
wait
);
for
(;;)
{
spin_lock_irq
(
&
port
->
lock
);
memcpy
(
&
cnow
,
&
port
->
icount
,
sizeof
(
struct
uart_icount
));
...
...
@@ -1011,117 +1023,144 @@ uart_wait_modem_status(struct uart_info *info, unsigned long arg)
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
&
info
->
delta_msr_wait
,
&
wait
);
remove_wait_queue
(
&
state
->
info
->
delta_msr_wait
,
&
wait
);
return
ret
;
}
/*
* Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
* Return: write counters to the user passed counter struct
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
static
int
uart_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
uart_get_count
(
struct
uart_state
*
state
,
struct
serial_icounter_struct
*
icnt
)
{
struct
uart_info
*
info
=
tty
->
driver_data
;
struct
serial_icounter_struct
icount
;
struct
uart_icount
cnow
;
struct
uart_port
*
port
=
state
->
port
;
spin_lock_irq
(
&
port
->
lock
);
memcpy
(
&
cnow
,
&
port
->
icount
,
sizeof
(
struct
uart_icount
));
spin_unlock_irq
(
&
port
->
lock
);
icount
.
cts
=
cnow
.
cts
;
icount
.
dsr
=
cnow
.
dsr
;
icount
.
rng
=
cnow
.
rng
;
icount
.
dcd
=
cnow
.
dcd
;
icount
.
rx
=
cnow
.
rx
;
icount
.
tx
=
cnow
.
tx
;
icount
.
frame
=
cnow
.
frame
;
icount
.
overrun
=
cnow
.
overrun
;
icount
.
parity
=
cnow
.
parity
;
icount
.
brk
=
cnow
.
brk
;
icount
.
buf_overrun
=
cnow
.
buf_overrun
;
return
copy_to_user
(
icnt
,
&
icount
,
sizeof
(
icount
))
?
-
EFAULT
:
0
;
}
/*
* Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
*/
static
int
uart_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
uart_state
*
state
=
tty
->
driver_data
;
int
ret
=
-
ENOIOCTLCMD
;
BUG_ON
(
!
kernel_locked
());
if
((
cmd
!=
TIOCGSERIAL
)
&&
(
cmd
!=
TIOCSSERIAL
)
&&
(
cmd
!=
TIOCSERCONFIG
)
&&
(
cmd
!=
TIOCSERGSTRUCT
)
&&
(
cmd
!=
TIOCMIWAIT
)
&&
(
cmd
!=
TIOCGICOUNT
))
{
if
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
))
return
-
EIO
;
/*
* These ioctls don't rely on the hardware to be present.
*/
switch
(
cmd
)
{
case
TIOCGSERIAL
:
ret
=
uart_get_info
(
state
,
(
struct
serial_struct
*
)
arg
);
break
;
case
TIOCSSERIAL
:
ret
=
uart_set_info
(
state
,
(
struct
serial_struct
*
)
arg
);
break
;
case
TIOCSERCONFIG
:
ret
=
uart_do_autoconfig
(
state
);
break
;
case
TIOCSERGWILD
:
/* obsolete */
case
TIOCSERSWILD
:
/* obsolete */
ret
=
0
;
break
;
}
switch
(
cmd
)
{
case
TIOCMGET
:
ret
=
uart_get_modem_info
(
info
->
port
,
(
unsigned
int
*
)
arg
);
break
;
if
(
ret
!=
-
ENOIOCTLCMD
)
goto
out
;
case
TIOCMBIS
:
case
TIOCMBIC
:
case
TIOCMSET
:
ret
=
uart_set_modem_info
(
info
->
port
,
cmd
,
(
unsigned
int
*
)
arg
);
break
;
if
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
))
{
ret
=
-
EIO
;
goto
out
;
}
case
TIOCGSERIAL
:
ret
=
uart_get_info
(
info
,
(
struct
serial_struct
*
)
arg
);
break
;
/*
* The following should only be used when hardware is present.
*/
switch
(
cmd
)
{
case
TIOCMIWAIT
:
ret
=
uart_wait_modem_status
(
state
,
arg
);
break
;
case
TIOCSSERIAL
:
ret
=
uart_set_info
(
info
,
(
struct
serial_struct
*
)
arg
);
break
;
case
TIOCGICOUNT
:
ret
=
uart_get_count
(
state
,
(
struct
serial_icounter_struct
*
)
arg
);
break
;
}
case
TIOCSERCONFIG
:
ret
=
uart_do_autoconfig
(
info
);
break
;
if
(
ret
!=
-
ENOIOCTLCMD
)
goto
out
;
case
TIOCSERGETLSR
:
/* Get line status register */
ret
=
uart_get_lsr_info
(
info
,
(
unsigned
int
*
)
arg
);
break
;
down
(
&
state
->
sem
);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
case
TIOCMIWAIT
:
ret
=
uart_wait_modem_status
(
info
,
arg
);
break
;
if
(
tty_hung_up_p
(
filp
))
{
ret
=
-
EIO
;
goto
out_up
;
}
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
* Return: write counters to the user passed counter struct
* NB: both 1->0 and 0->1 transitions are counted except for
* RI where only 0->1 is counted.
*/
case
TIOCGICOUNT
:
spin_lock_irq
(
&
info
->
port
->
lock
);
memcpy
(
&
cnow
,
&
info
->
port
->
icount
,
sizeof
(
struct
uart_icount
));
spin_unlock_irq
(
&
info
->
port
->
lock
);
icount
.
cts
=
cnow
.
cts
;
icount
.
dsr
=
cnow
.
dsr
;
icount
.
rng
=
cnow
.
rng
;
icount
.
dcd
=
cnow
.
dcd
;
icount
.
rx
=
cnow
.
rx
;
icount
.
tx
=
cnow
.
tx
;
icount
.
frame
=
cnow
.
frame
;
icount
.
overrun
=
cnow
.
overrun
;
icount
.
parity
=
cnow
.
parity
;
icount
.
brk
=
cnow
.
brk
;
icount
.
buf_overrun
=
cnow
.
buf_overrun
;
ret
=
copy_to_user
((
void
*
)
arg
,
&
icount
,
sizeof
(
icount
))
?
-
EFAULT
:
0
;
break
;
/*
* All these rely on hardware being present and need to be
* protected against the tty being hung up.
*/
switch
(
cmd
)
{
case
TIOCMGET
:
ret
=
uart_get_modem_info
(
state
->
port
,
(
unsigned
int
*
)
arg
);
break
;
case
TIOCSERGWILD
:
/* obsolete */
case
TIOCSERSWILD
:
/* obsolete */
ret
=
0
;
break
;
case
TIOCMBIS
:
case
TIOCMBIC
:
case
TIOCMSET
:
ret
=
uart_set_modem_info
(
state
->
port
,
cmd
,
(
unsigned
int
*
)
arg
);
break
;
default:
{
struct
uart_port
*
port
=
info
->
port
;
if
(
port
->
ops
->
ioctl
)
ret
=
port
->
ops
->
ioctl
(
port
,
cmd
,
arg
);
break
;
}
case
TIOCSERGETLSR
:
/* Get line status register */
ret
=
uart_get_lsr_info
(
state
,
(
unsigned
int
*
)
arg
);
break
;
default:
{
struct
uart_port
*
port
=
state
->
port
;
if
(
port
->
ops
->
ioctl
)
ret
=
port
->
ops
->
ioctl
(
port
,
cmd
,
arg
);
break
;
}
}
out_up:
up
(
&
state
->
sem
);
out:
return
ret
;
}
static
void
uart_set_termios
(
struct
tty_struct
*
tty
,
struct
termios
*
old_termios
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
unsigned
long
flags
;
unsigned
int
cflag
=
tty
->
termios
->
c_cflag
;
...
...
@@ -1137,11 +1176,11 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
RELEVANT_IFLAG
(
tty
->
termios
->
c_iflag
^
old_termios
->
c_iflag
)
==
0
)
return
;
uart_change_speed
(
info
,
old_termios
);
uart_change_speed
(
state
,
old_termios
);
/* Handle transition to B0 status */
if
((
old_termios
->
c_cflag
&
CBAUD
)
&&
!
(
cflag
&
CBAUD
))
uart_clear_mctrl
(
info
->
port
,
TIOCM_RTS
|
TIOCM_DTR
);
uart_clear_mctrl
(
state
->
port
,
TIOCM_RTS
|
TIOCM_DTR
);
/* Handle transition away from B0 status */
if
(
!
(
old_termios
->
c_cflag
&
CBAUD
)
&&
(
cflag
&
CBAUD
))
{
...
...
@@ -1149,15 +1188,15 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
if
(
!
(
cflag
&
CRTSCTS
)
||
!
test_bit
(
TTY_THROTTLED
,
&
tty
->
flags
))
mask
|=
TIOCM_RTS
;
uart_set_mctrl
(
info
->
port
,
mask
);
uart_set_mctrl
(
state
->
port
,
mask
);
}
/* Handle turning off CRTSCTS */
if
((
old_termios
->
c_cflag
&
CRTSCTS
)
&&
!
(
cflag
&
CRTSCTS
))
{
spin_lock_irqsave
(
&
info
->
port
->
lock
,
flags
);
spin_lock_irqsave
(
&
state
->
port
->
lock
,
flags
);
tty
->
hw_stopped
=
0
;
__uart_start
(
tty
);
spin_unlock_irqrestore
(
&
info
->
port
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
state
->
port
->
lock
,
flags
);
}
#if 0
...
...
@@ -1169,7 +1208,7 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
wake_up_interruptible(&info->open_wait);
wake_up_interruptible(&
state->
info->open_wait);
#endif
}
...
...
@@ -1180,29 +1219,17 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
*/
static
void
uart_close
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
struct
uart_driver
*
drv
=
(
struct
uart_driver
*
)
tty
->
driver
.
driver_state
;
struct
uart_info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_state
*
state
;
unsigned
long
flags
;
struct
uart_state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
BUG_ON
(
!
kernel_locked
());
DPRINTK
(
"uart_close(%d) called
\n
"
,
port
->
line
);
if
(
!
info
)
return
;
state
=
info
->
state
;
down
(
&
state
->
sem
);
DPRINTK
(
"uart_close() called
\n
"
);
/*
* This is safe, as long as the BKL exists in
* do_tty_hangup(), and we're protected by the BKL.
*/
if
(
tty_hung_up_p
(
filp
))
goto
done
;
spin_lock_irqsave
(
&
info
->
port
->
lock
,
flags
);
if
((
tty
->
count
==
1
)
&&
(
state
->
count
!=
1
))
{
/*
* Uh, oh. tty->count is 1, which means that the tty
...
...
@@ -1217,34 +1244,28 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
}
if
(
--
state
->
count
<
0
)
{
printk
(
"rs_close: bad serial port count for %s%d: %d
\n
"
,
tty
->
driver
.
name
,
info
->
port
->
line
,
state
->
count
);
tty
->
driver
.
name
,
port
->
line
,
state
->
count
);
state
->
count
=
0
;
}
if
(
state
->
count
)
{
spin_unlock_irqrestore
(
&
info
->
port
->
lock
,
flags
);
if
(
state
->
count
)
goto
done
;
}
/*
* The UIF_CLOSING flag protects us against further opens
* of this port.
*/
info
->
flags
|=
UIF_CLOSING
;
spin_unlock_irqrestore
(
&
info
->
port
->
lock
,
flags
);
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
* the line discipline to only process XON/XOFF characters by
* setting tty->closing.
*/
tty
->
closing
=
1
;
if
(
info
->
state
->
closing_wait
!=
USF_CLOSING_WAIT_NONE
)
tty_wait_until_sent
(
tty
,
info
->
state
->
closing_wait
);
if
(
state
->
closing_wait
!=
USF_CLOSING_WAIT_NONE
)
tty_wait_until_sent
(
tty
,
state
->
closing_wait
);
/*
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
if
(
info
->
flags
&
UIF_INITIALIZED
)
{
if
(
state
->
info
->
flags
&
UIF_INITIALIZED
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
port
->
lock
,
flags
);
port
->
ops
->
stop_rx
(
port
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
...
...
@@ -1255,46 +1276,38 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
*/
uart_wait_until_sent
(
tty
,
port
->
timeout
);
}
down
(
&
port_sem
);
uart_shutdown
(
info
);
up
(
&
port_sem
);
uart_shutdown
(
state
);
uart_flush_buffer
(
tty
);
if
(
tty
->
ldisc
.
flush_buffer
)
tty
->
ldisc
.
flush_buffer
(
tty
);
tty
->
closing
=
0
;
info
->
tty
=
NULL
;
if
(
info
->
blocked_open
)
{
if
(
info
->
state
->
close_delay
)
{
state
->
info
->
tty
=
NULL
;
if
(
state
->
info
->
blocked_open
)
{
if
(
state
->
close_delay
)
{
set_current_state
(
TASK_INTERRUPTIBLE
);
schedule_timeout
(
info
->
state
->
close_delay
);
schedule_timeout
(
state
->
close_delay
);
set_current_state
(
TASK_RUNNING
);
}
}
else
{
#ifdef CONFIG_PM
/*
* Put device into D3 state.
*/
pm_send
(
info
->
state
->
pm
,
PM_SUSPEND
,
(
void
*
)
3
);
#else
if
(
port
->
ops
->
pm
)
port
->
ops
->
pm
(
port
,
3
,
0
);
#endif
}
else
if
(
!
uart_console
(
port
))
{
uart_change_pm
(
state
,
3
);
}
/*
* Wake up anyone trying to open this port.
*/
info
->
flags
&=
~
(
UIF_NORMAL_ACTIVE
|
UIF_CLOSING
)
;
wake_up_interruptible
(
&
info
->
open_wait
);
state
->
info
->
flags
&=
~
UIF_NORMAL_ACTIVE
;
wake_up_interruptible
(
&
state
->
info
->
open_wait
);
done:
module_put
(
drv
->
owner
);
up
(
&
state
->
sem
);
}
static
void
uart_wait_until_sent
(
struct
tty_struct
*
tty
,
int
timeout
)
{
struct
uart_
info
*
info
=
tty
->
driver_data
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
state
*
state
=
tty
->
driver_data
;
struct
uart_port
*
port
=
state
->
port
;
unsigned
long
char_time
,
expire
;
BUG_ON
(
!
kernel_locked
());
...
...
@@ -1358,23 +1371,22 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static
void
uart_hangup
(
struct
tty_struct
*
tty
)
{
struct
uart_info
*
info
=
tty
->
driver_data
;
struct
uart_state
*
state
=
info
->
state
;
struct
uart_state
*
state
=
tty
->
driver_data
;
BUG_ON
(
!
kernel_locked
());
DPRINTK
(
"uart_hangup(%d)
\n
"
,
state
->
port
->
line
);
uart_flush_buffer
(
tty
);
down
(
&
port_sem
);
if
(
info
->
flags
&
UIF_CLOSING
)
{
up
(
&
port_sem
);
return
;
down
(
&
state
->
sem
);
if
(
state
->
info
&&
state
->
info
->
flags
&
UIF_NORMAL_ACTIVE
)
{
uart_flush_buffer
(
tty
);
uart_shutdown
(
state
);
state
->
count
=
0
;
state
->
info
->
flags
&=
~
UIF_NORMAL_ACTIVE
;
state
->
info
->
tty
=
NULL
;
wake_up_interruptible
(
&
state
->
info
->
open_wait
);
wake_up_interruptible
(
&
state
->
info
->
delta_msr_wait
);
}
uart_shutdown
(
info
);
state
->
count
=
0
;
info
->
flags
&=
~
UIF_NORMAL_ACTIVE
;
info
->
tty
=
NULL
;
up
(
&
port_sem
);
wake_up_interruptible
(
&
info
->
open_wait
);
up
(
&
state
->
sem
);
}
/*
...
...
@@ -1383,18 +1395,15 @@ static void uart_hangup(struct tty_struct *tty)
* kernel settings, and the settings init adopts when it opens the port
* for the first time.
*/
static
void
uart_update_termios
(
struct
uart_
info
*
info
)
static
void
uart_update_termios
(
struct
uart_
state
*
state
)
{
struct
tty_struct
*
tty
=
info
->
tty
;
#ifdef CONFIG_SERIAL_CORE_CONSOLE
struct
console
*
c
=
info
->
port
->
cons
;
struct
tty_struct
*
tty
=
state
->
info
->
tty
;
struct
uart_port
*
port
=
state
->
port
;
if
(
c
&&
c
->
cflag
&&
c
->
index
==
info
->
port
->
line
)
{
tty
->
termios
->
c_cflag
=
c
->
cflag
;
c
->
cflag
=
0
;
if
(
uart_console
(
port
)
&&
port
->
cons
->
cflag
)
{
tty
->
termios
->
c_cflag
=
port
->
cons
->
cflag
;
port
->
cons
->
cflag
=
0
;
}
#endif
/*
* If the device failed to grab its irq resources,
...
...
@@ -1405,22 +1414,26 @@ static void uart_update_termios(struct uart_info *info)
/*
* Make termios settings take effect.
*/
uart_change_speed
(
info
,
NULL
);
uart_change_speed
(
state
,
NULL
);
/*
* And finally enable the RTS and DTR signals.
*/
if
(
tty
->
termios
->
c_cflag
&
CBAUD
)
uart_set_mctrl
(
info
->
port
,
TIOCM_DTR
|
TIOCM_RTS
);
uart_set_mctrl
(
port
,
TIOCM_DTR
|
TIOCM_RTS
);
}
}
/*
* Block the open until the port is ready. We must be called with
* the per-port semaphore held.
*/
static
int
uart_block_til_ready
(
struct
file
*
filp
,
struct
uart_
info
*
info
)
uart_block_til_ready
(
struct
file
*
filp
,
struct
uart_
state
*
state
)
{
DECLARE_WAITQUEUE
(
wait
,
current
);
struct
uart_
state
*
state
=
info
->
state
;
struct
uart_port
*
port
=
info
->
port
;
struct
uart_
info
*
info
=
state
->
info
;
struct
uart_port
*
port
=
state
->
port
;
info
->
blocked_open
++
;
state
->
count
--
;
...
...
@@ -1432,17 +1445,9 @@ uart_block_til_ready(struct file *filp, struct uart_info *info)
/*
* If we have been hung up, tell userspace/restart open.
*/
if
(
tty_hung_up_p
(
filp
))
if
(
tty_hung_up_p
(
filp
)
||
info
->
tty
==
NULL
)
break
;
/*
* If the device is in the middle of being closed, block
* until it's done. We will need to re-initialise the
* port. Hmm, is it legal to block a non-blocking open?
*/
if
(
info
->
flags
&
UIF_CLOSING
)
goto
wait
;
/*
* If the port has been closed, tell userspace/restart open.
*/
...
...
@@ -1470,7 +1475,7 @@ uart_block_til_ready(struct file *filp, struct uart_info *info)
* the data from the modem.
*/
if
(
info
->
tty
->
termios
->
c_cflag
&
CBAUD
)
uart_set_mctrl
(
info
->
port
,
TIOCM_DTR
);
uart_set_mctrl
(
port
,
TIOCM_DTR
);
/*
* and wait for the carrier to indicate that the
...
...
@@ -1479,8 +1484,9 @@ uart_block_til_ready(struct file *filp, struct uart_info *info)
if
(
port
->
ops
->
get_mctrl
(
port
)
&
TIOCM_CAR
)
break
;
wait:
up
(
&
state
->
sem
);
schedule
();
down
(
&
state
->
sem
);
if
(
signal_pending
(
current
))
break
;
...
...
@@ -1494,52 +1500,56 @@ uart_block_til_ready(struct file *filp, struct uart_info *info)
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
if
(
info
->
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
))
return
0
;
if
(
tty_hung_up_p
(
filp
)
||
!
(
info
->
flags
&
UIF_INITIALIZED
))
if
(
!
info
->
tty
||
tty_hung_up_p
(
filp
))
return
(
port
->
flags
&
UPF_HUP_NOTIFY
)
?
-
EAGAIN
:
-
ERESTARTSYS
;
return
0
;
}
static
struct
uart_
info
*
uart_get
(
struct
uart_driver
*
drv
,
int
line
)
static
struct
uart_
state
*
uart_get
(
struct
uart_driver
*
drv
,
int
line
)
{
struct
uart_state
*
state
=
drv
->
state
+
line
;
struct
uart_info
*
info
=
NULL
;
struct
uart_state
*
state
;
down
(
&
port_sem
);
if
(
!
state
->
port
)
state
=
drv
->
state
+
line
;
if
(
down_interruptible
(
&
state
->
sem
))
{
state
=
ERR_PTR
(
-
ERESTARTSYS
);
goto
out
;
}
state
->
count
++
;
info
=
state
->
info
;
if
(
!
state
->
port
)
{
state
->
count
--
;
up
(
&
state
->
sem
);
state
=
ERR_PTR
(
-
ENXIO
);
goto
out
;
}
if
(
!
info
)
{
info
=
kmalloc
(
sizeof
(
struct
uart_info
),
GFP_KERNEL
);
if
(
info
)
{
memset
(
info
,
0
,
sizeof
(
struct
uart_info
));
init_waitqueue_head
(
&
info
->
open_wait
);
init_waitqueue_head
(
&
info
->
delta_msr_wait
);
if
(
!
state
->
info
)
{
state
->
info
=
kmalloc
(
sizeof
(
struct
uart_info
),
GFP_KERNEL
);
if
(
state
->
info
)
{
memset
(
state
->
info
,
0
,
sizeof
(
struct
uart_info
));
init_waitqueue_head
(
&
state
->
info
->
open_wait
);
init_waitqueue_head
(
&
state
->
info
->
delta_msr_wait
);
/*
* Link the info into the other structures.
*/
info
->
port
=
state
->
port
;
info
->
state
=
state
;
state
->
port
->
info
=
info
;
tasklet_init
(
&
info
->
tlet
,
uart_tasklet_action
,
(
unsigned
long
)
info
);
state
->
info
=
info
;
}
else
state
->
port
->
info
=
state
->
info
;
tasklet_init
(
&
state
->
info
->
tlet
,
uart_tasklet_action
,
(
unsigned
long
)
state
);
}
else
{
state
->
count
--
;
up
(
&
state
->
sem
);
state
=
ERR_PTR
(
-
ENOMEM
);
}
}
out:
up
(
&
port_sem
);
return
info
;
return
state
;
}
/*
...
...
@@ -1555,11 +1565,10 @@ static struct uart_info *uart_get(struct uart_driver *drv, int line)
static
int
uart_open
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
struct
uart_driver
*
drv
=
(
struct
uart_driver
*
)
tty
->
driver
.
driver_state
;
struct
uart_
info
*
info
;
struct
uart_
state
*
state
;
int
retval
,
line
=
minor
(
tty
->
device
)
-
tty
->
driver
.
minor_start
;
BUG_ON
(
!
kernel_locked
());
DPRINTK
(
"uart_open(%d) called
\n
"
,
line
);
/*
...
...
@@ -1572,92 +1581,66 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
goto
fail
;
/*
* If we fail to increment the module use count, we can't have
* any other users of this tty (since this implies that the module
* is about to be unloaded). Therefore, it is safe to set
* tty->driver_data to be NULL, so uart_close() doesn't bite us.
* We take the semaphore inside uart_get to guarantee that we won't
* be re-entered while allocating the info structure, or while we
* request any IRQs that the driver may need. This also has the nice
* side-effect that it delays the action of uart_hangup, so we can
* guarantee that info->tty will always contain something reasonable.
*/
if
(
!
try_module_get
(
drv
->
owner
))
{
tty
->
driver_data
=
NULL
;
state
=
uart_get
(
drv
,
line
);
if
(
IS_ERR
(
state
))
{
retval
=
PTR_ERR
(
state
);
goto
fail
;
}
/*
* FIXME: This one isn't fun. We can't guarantee that the tty isn't
* already in open, nor can we guarantee the state of tty->driver_data
*/
info
=
uart_get
(
drv
,
line
);
retval
=
-
ENOMEM
;
if
(
!
info
)
{
if
(
tty
->
driver_data
)
goto
fail
;
else
goto
out
;
}
/*
* Once we set tty->driver_data here, we are guaranteed that
* uart_close() will decrement the driver module use count.
* Any failures from here onwards should not touch the count.
*/
tty
->
driver_data
=
info
;
tty
->
low_latency
=
(
info
->
port
->
flags
&
UPF_LOW_LATENCY
)
?
1
:
0
;
tty
->
driver_data
=
state
;
tty
->
low_latency
=
(
state
->
port
->
flags
&
UPF_LOW_LATENCY
)
?
1
:
0
;
tty
->
alt_speed
=
0
;
info
->
tty
=
tty
;
state
->
info
->
tty
=
tty
;
/*
* If the port is in the middle of closing, bail out now.
*/
if
(
tty_hung_up_p
(
filp
)
||
(
info
->
flags
&
UIF_CLOSING
))
{
wait_event_interruptible
(
info
->
open_wait
,
!
(
info
->
flags
&
UIF_CLOSING
));
retval
=
(
info
->
port
->
flags
&
UPF_HUP_NOTIFY
)
?
if
(
tty_hung_up_p
(
filp
))
{
retval
=
(
state
->
port
->
flags
&
UPF_HUP_NOTIFY
)
?
-
EAGAIN
:
-
ERESTARTSYS
;
state
->
count
--
;
up
(
&
state
->
sem
);
goto
fail
;
}
/*
* Make sure the device is in D0 state.
*/
if
(
info
->
state
->
count
==
1
)
{
#ifdef CONFIG_PM
pm_send
(
info
->
state
->
pm
,
PM_RESUME
,
(
void
*
)
0
);
#else
struct
uart_port
*
port
=
info
->
port
;
if
(
port
->
ops
->
pm
)
port
->
ops
->
pm
(
port
,
0
,
3
);
#endif
}
if
(
state
->
count
==
1
)
uart_change_pm
(
state
,
0
);
/*
* Start up the serial port. We have this semaphore here to
* prevent uart_startup or uart_shutdown being re-entered if
* we sleep while requesting an IRQ.
* Start up the serial port.
*/
down
(
&
port_sem
);
retval
=
uart_startup
(
info
,
0
);
up
(
&
port_sem
);
if
(
retval
)
goto
fail
;
retval
=
uart_startup
(
state
,
0
);
/*
*
W
ait until the port is ready.
*
If we succeeded, w
ait until the port is ready.
*/
retval
=
uart_block_til_ready
(
filp
,
info
);
if
(
retval
==
0
)
retval
=
uart_block_til_ready
(
filp
,
state
);
up
(
&
state
->
sem
);
/*
* If this is the first open to succeed, adjust things to suit.
*/
if
(
retval
==
0
&&
!
(
info
->
flags
&
UIF_NORMAL_ACTIVE
))
{
info
->
flags
|=
UIF_NORMAL_ACTIVE
;
if
(
retval
==
0
&&
!
(
state
->
info
->
flags
&
UIF_NORMAL_ACTIVE
))
{
state
->
info
->
flags
|=
UIF_NORMAL_ACTIVE
;
uart_update_termios
(
info
);
uart_update_termios
(
state
);
}
return
retval
;
out:
module_put
(
drv
->
owner
);
fail:
return
retval
;
}
...
...
@@ -1892,115 +1875,98 @@ uart_set_options(struct uart_port *port, struct console *co,
}
#endif
/* CONFIG_SERIAL_CORE_CONSOLE */
#ifdef CONFIG_PM
/*
* Serial port power management.
*
* This is pretty coarse at the moment - either all on or all off. We
* should probably some day do finer power management here some day.
*
* We don't actually save any state; the serial driver already has the
* state held internally to re-setup the port when we come out of D3.
*/
static
int
uart_pm_set_state
(
struct
uart_state
*
state
,
int
pm_state
,
int
oldstate
)
static
void
uart_change_pm
(
struct
uart_state
*
state
,
int
pm_state
)
{
struct
uart_port
*
port
;
struct
uart_ops
*
ops
;
int
running
=
state
->
info
&&
state
->
info
->
flags
&
UIF_INITIALIZED
;
struct
uart_port
*
port
=
state
->
port
;
if
(
port
->
ops
->
pm
)
port
->
ops
->
pm
(
port
,
pm_state
,
state
->
pm_state
);
state
->
pm_state
=
pm_state
;
}
down
(
&
port_sem
);
int
uart_suspend_port
(
struct
uart_driver
*
drv
,
struct
uart_port
*
port
,
u32
level
)
{
struct
uart_state
*
state
=
drv
->
state
+
port
->
line
;
if
(
!
state
->
port
||
state
->
port
->
type
==
PORT_UNKNOWN
)
{
up
(
&
port_sem
);
return
0
;
}
down
(
&
state
->
sem
);
port
=
state
->
port
;
ops
=
port
->
ops
;
switch
(
level
)
{
case
SUSPEND_SAVE_STATE
:
if
(
state
->
info
&&
state
->
info
->
flags
&
UIF_INITIALIZED
)
{
struct
uart_ops
*
ops
=
port
->
ops
;
DPRINTK
(
"pm: %08x: %d -> %d, %srunning
\n
"
,
port
->
iobase
,
dev
->
state
,
pm_state
,
running
?
""
:
"not "
);
spin_lock_irq
(
&
port
->
lock
);
ops
->
stop_tx
(
port
,
0
);
ops
->
set_mctrl
(
port
,
0
);
ops
->
stop_rx
(
port
);
spin_unlock_irq
(
&
port
->
lock
);
if
(
pm_state
==
0
)
{
if
(
ops
->
pm
)
ops
->
pm
(
port
,
pm_state
,
oldstate
);
if
(
running
)
{
/*
* The port lock isn't taken here -
* the port isn't initialised.
* Wait for the transmitter to empty.
*/
ops
->
set_mctrl
(
port
,
0
);
ops
->
startup
(
port
);
uart_change_speed
(
state
->
info
,
NULL
);
spin_lock_irq
(
&
port
->
lock
);
ops
->
set_mctrl
(
port
,
port
->
mctrl
);
ops
->
start_tx
(
port
,
0
);
spin_unlock_irq
(
&
port
->
lock
);
while
(
!
ops
->
tx_empty
(
port
))
{
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
10
*
HZ
/
1000
);
}
set_current_state
(
TASK_RUNNING
);
ops
->
shutdown
(
port
);
}
break
;
/*
* Re-enable the console device after suspending.
*/
if
(
port
->
cons
&&
port
->
cons
->
index
==
port
->
line
)
port
->
cons
->
flags
|=
CON_ENABLED
;
}
else
if
(
pm_state
==
1
)
{
if
(
ops
->
pm
)
ops
->
pm
(
port
,
pm_state
,
oldstate
);
}
else
{
case
SUSPEND_POWER_DOWN
:
/*
* Disable the console device before suspending.
*/
if
(
port
->
cons
&&
port
->
cons
->
index
==
port
->
line
)
if
(
uart_console
(
port
)
)
port
->
cons
->
flags
&=
~
CON_ENABLED
;
if
(
running
)
{
spin_lock_irq
(
&
port
->
lock
);
ops
->
stop_tx
(
port
,
0
);
ops
->
set_mctrl
(
port
,
0
);
ops
->
stop_rx
(
port
);
spin_unlock_irq
(
&
port
->
lock
);
ops
->
shutdown
(
port
);
}
if
(
ops
->
pm
)
ops
->
pm
(
port
,
pm_state
,
oldstate
);
uart_change_pm
(
state
,
3
);
break
;
}
up
(
&
port_sem
);
up
(
&
state
->
sem
);
return
0
;
}
/*
* Wakeup support.
*/
static
int
uart_pm_set_wakeup
(
struct
uart_state
*
state
,
int
data
)
int
uart_resume_port
(
struct
uart_driver
*
drv
,
struct
uart_port
*
port
,
u32
level
)
{
int
err
=
0
;
if
(
state
->
port
->
ops
->
set_wake
)
err
=
state
->
port
->
ops
->
set_wake
(
state
->
port
,
data
);
struct
uart_state
*
state
=
drv
->
state
+
port
->
line
;
return
err
;
}
down
(
&
state
->
sem
);
static
int
uart_pm
(
struct
pm_dev
*
dev
,
pm_request_t
rqst
,
void
*
data
)
{
struct
uart_state
*
state
=
dev
->
data
;
int
err
=
0
;
switch
(
level
)
{
case
RESUME_POWER_ON
:
uart_change_pm
(
state
,
0
);
switch
(
rqst
)
{
case
PM_SUSPEND
:
case
PM_RESUME
:
err
=
uart_pm_set_state
(
state
,
(
int
)(
long
)
data
,
dev
->
state
);
/*
* Re-enable the console device after suspending.
*/
if
(
uart_console
(
port
))
{
uart_change_speed
(
state
,
NULL
);
port
->
cons
->
flags
|=
CON_ENABLED
;
}
break
;
case
PM_SET_WAKEUP
:
err
=
uart_pm_set_wakeup
(
state
,
(
int
)(
long
)
data
);
case
RESUME_RESTORE_STATE
:
if
(
state
->
info
&&
state
->
info
->
flags
&
UIF_INITIALIZED
)
{
struct
uart_ops
*
ops
=
port
->
ops
;
ops
->
set_mctrl
(
port
,
0
);
ops
->
startup
(
port
);
uart_change_speed
(
state
,
NULL
);
spin_lock_irq
(
&
port
->
lock
);
ops
->
set_mctrl
(
port
,
port
->
mctrl
);
ops
->
start_tx
(
port
,
0
);
spin_unlock_irq
(
&
port
->
lock
);
}
break
;
}
return
err
;
up
(
&
state
->
sem
);
return
0
;
}
#endif
static
inline
void
uart_report_port
(
struct
uart_driver
*
drv
,
struct
uart_port
*
port
)
...
...
@@ -2022,17 +1988,11 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
}
static
void
__uart_register
_port
(
struct
uart_driver
*
drv
,
struct
uart_state
*
state
,
struct
uart_port
*
port
)
uart_configure
_port
(
struct
uart_driver
*
drv
,
struct
uart_state
*
state
,
struct
uart_port
*
port
)
{
unsigned
int
flags
;
state
->
port
=
port
;
spin_lock_init
(
&
port
->
lock
);
port
->
cons
=
drv
->
cons
;
port
->
info
=
state
->
info
;
/*
* If there isn't a port here, don't do anything further.
*/
...
...
@@ -2051,12 +2011,6 @@ __uart_register_port(struct uart_driver *drv, struct uart_state *state,
port
->
ops
->
config_port
(
port
,
flags
);
}
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_register_device
(
drv
->
tty_driver
,
drv
->
minor
+
port
->
line
);
if
(
port
->
type
!=
PORT_UNKNOWN
)
{
unsigned
long
flags
;
...
...
@@ -2070,50 +2024,32 @@ __uart_register_port(struct uart_driver *drv, struct uart_state *state,
port
->
ops
->
set_mctrl
(
port
,
0
);
spin_unlock_irqrestore
(
&
port
->
lock
,
flags
);
#ifdef CONFIG_PM
/*
* Power down all ports by default, except the
* console if we have one. We need to drop the
* port semaphore here.
* console if we have one.
*/
if
(
state
->
pm
&&
(
!
drv
->
cons
||
port
->
line
!=
drv
->
cons
->
index
))
{
up
(
&
port_sem
);
pm_send
(
state
->
pm
,
PM_SUSPEND
,
(
void
*
)
3
);
down
(
&
port_sem
);
}
#endif
if
(
!
uart_console
(
port
))
uart_change_pm
(
state
,
3
);
}
}
/*
*
Hangup the port. This must be done outside the port_sem
*
since uart_hangup() grabs this same semaphore. Grr
.
*
This reverses the affects of uart_configure_port, hanging up the
*
port before removal
.
*/
static
void
__uart_hangup
_port
(
struct
uart_driver
*
drv
,
struct
uart_state
*
state
)
uart_unconfigure
_port
(
struct
uart_driver
*
drv
,
struct
uart_state
*
state
)
{
struct
uart_port
*
port
=
state
->
port
;
struct
uart_info
*
info
=
state
->
info
;
if
(
info
&&
info
->
tty
)
tty_vhangup
(
info
->
tty
);
}
/*
* This reverses the affects of __uart_register_port.
*/
static
void
__uart_unregister_port
(
struct
uart_driver
*
drv
,
struct
uart_state
*
state
)
{
struct
uart_port
*
port
=
state
->
port
;
struct
uart_info
*
info
=
state
->
info
;
down
(
&
state
->
sem
);
state
->
info
=
NULL
;
/*
* Remove the devices from devfs
*/
tty_unregister_device
(
drv
->
tty_driver
,
drv
->
minor
+
port
->
line
);
/*
* Free the port IO and memory resources, if any.
*/
...
...
@@ -2132,6 +2068,8 @@ __uart_unregister_port(struct uart_driver *drv, struct uart_state *state)
tasklet_kill
(
&
info
->
tlet
);
kfree
(
info
);
}
up
(
&
state
->
sem
);
}
/**
...
...
@@ -2186,6 +2124,7 @@ int uart_register_driver(struct uart_driver *drv)
drv
->
tty_driver
=
normal
;
normal
->
magic
=
TTY_DRIVER_MAGIC
;
normal
->
owner
=
drv
->
owner
;
normal
->
driver_name
=
drv
->
driver_name
;
normal
->
name
=
drv
->
dev_name
;
normal
->
major
=
drv
->
major
;
...
...
@@ -2232,20 +2171,13 @@ int uart_register_driver(struct uart_driver *drv)
state
->
close_delay
=
5
*
HZ
/
10
;
state
->
closing_wait
=
30
*
HZ
;
#ifdef CONFIG_PM
state
->
pm
=
pm_register
(
PM_SYS_DEV
,
PM_SYS_COM
,
uart_pm
);
if
(
state
->
pm
)
state
->
pm
->
data
=
state
;
#endif
init_MUTEX
(
&
state
->
sem
);
}
retval
=
tty_register_driver
(
normal
);
out:
if
(
retval
<
0
)
{
#ifdef CONFIG_PM
for
(
i
=
0
;
i
<
drv
->
nr
;
i
++
)
pm_unregister
(
drv
->
state
[
i
].
pm
);
#endif
kfree
(
normal
);
kfree
(
drv
->
state
);
kfree
(
termios
);
...
...
@@ -2264,11 +2196,6 @@ int uart_register_driver(struct uart_driver *drv)
*/
void
uart_unregister_driver
(
struct
uart_driver
*
drv
)
{
int
i
;
for
(
i
=
0
;
i
<
drv
->
nr
;
i
++
)
pm_unregister
(
drv
->
state
[
i
].
pm
);
tty_unregister_driver
(
drv
->
tty_driver
);
kfree
(
drv
->
state
);
...
...
@@ -2289,6 +2216,7 @@ void uart_unregister_driver(struct uart_driver *drv)
int
uart_add_one_port
(
struct
uart_driver
*
drv
,
struct
uart_port
*
port
)
{
struct
uart_state
*
state
;
int
ret
=
0
;
BUG_ON
(
in_interrupt
());
...
...
@@ -2298,10 +2226,29 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state
=
drv
->
state
+
port
->
line
;
down
(
&
port_sem
);
__uart_register_port
(
drv
,
state
,
port
);
if
(
state
->
port
)
{
ret
=
-
EINVAL
;
goto
out
;
}
state
->
port
=
port
;
spin_lock_init
(
&
port
->
lock
);
port
->
cons
=
drv
->
cons
;
port
->
info
=
state
->
info
;
uart_configure_port
(
drv
,
state
,
port
);
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this ports parameters.
*/
tty_register_device
(
drv
->
tty_driver
,
drv
->
minor
+
port
->
line
);
out:
up
(
&
port_sem
);
return
0
;
return
ret
;
}
/**
...
...
@@ -2323,10 +2270,14 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
printk
(
KERN_ALERT
"Removing wrong port: %p != %p
\n
"
,
state
->
port
,
port
);
__uart_hangup_port
(
drv
,
state
);
down
(
&
port_sem
);
__uart_unregister_port
(
drv
,
state
);
/*
* Remove the devices from devfs
*/
tty_unregister_device
(
drv
->
tty_driver
,
drv
->
minor
+
port
->
line
);
uart_unconfigure_port
(
drv
,
state
);
state
->
port
=
NULL
;
up
(
&
port_sem
);
...
...
@@ -2426,8 +2377,7 @@ int uart_register_port(struct uart_driver *drv, struct uart_port *port)
* alter it underneath itself - the port may be open and
* trying to do useful work.
*/
if
(
state
->
count
!=
0
||
(
state
->
info
&&
state
->
info
->
blocked_open
!=
0
))
{
if
(
uart_users
(
state
)
!=
0
)
{
ret
=
-
EBUSY
;
goto
out
;
}
...
...
@@ -2447,7 +2397,7 @@ int uart_register_port(struct uart_driver *drv, struct uart_port *port)
state
->
port
->
line
=
state
-
drv
->
state
;
state
->
port
->
mapbase
=
port
->
mapbase
;
__uart_register
_port
(
drv
,
state
,
state
->
port
);
uart_configure
_port
(
drv
,
state
,
state
->
port
);
}
ret
=
state
->
port
->
line
;
...
...
@@ -2479,16 +2429,16 @@ void uart_unregister_port(struct uart_driver *drv, int line)
state
=
drv
->
state
+
line
;
__uart_hangup_port
(
drv
,
state
);
down
(
&
port_sem
);
__uart_unregister
_port
(
drv
,
state
);
uart_unconfigure
_port
(
drv
,
state
);
up
(
&
port_sem
);
}
EXPORT_SYMBOL
(
uart_write_wakeup
);
EXPORT_SYMBOL
(
uart_register_driver
);
EXPORT_SYMBOL
(
uart_unregister_driver
);
EXPORT_SYMBOL
(
uart_suspend_port
);
EXPORT_SYMBOL
(
uart_resume_port
);
EXPORT_SYMBOL
(
uart_register_port
);
EXPORT_SYMBOL
(
uart_unregister_port
);
EXPORT_SYMBOL
(
uart_add_one_port
);
...
...
drivers/serial/sa1100.c
View file @
0deb87aa
...
...
@@ -32,6 +32,7 @@
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/irq.h>
...
...
@@ -857,12 +858,54 @@ static struct uart_driver sa1100_reg = {
.
cons
=
SA1100_CONSOLE
,
};
static
int
sa1100_serial_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
{
int
i
;
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
)
uart_suspend_port
(
&
sa1100_reg
,
&
sa1100_ports
[
i
].
port
,
level
);
return
0
;
}
static
int
sa1100_serial_resume
(
struct
device
*
dev
,
u32
level
)
{
int
i
;
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
)
uart_resume_port
(
&
sa1100_reg
,
&
sa1100_ports
[
i
].
port
,
level
);
return
0
;
}
static
struct
device_driver
sa11x0_serial_driver
=
{
.
name
=
"sa11x0_serial"
,
.
bus
=
&
system_bus_type
,
.
devclass
=
&
tty_devclass
,
.
suspend
=
sa1100_serial_suspend
,
.
resume
=
sa1100_serial_resume
,
};
/*
* This "device" covers _all_ ISA 8250-compatible serial devices.
*/
static
struct
sys_device
sa11x0_serial_devs
=
{
.
name
=
"sa11x0_serial"
,
.
id
=
0
,
.
dev
=
{
.
driver
=
&
sa11x0_serial_driver
,
},
};
static
int
__init
sa1100_serial_init
(
void
)
{
int
ret
;
printk
(
KERN_INFO
"Serial: SA11x0 driver $Revision: 1.50 $
\n
"
);
driver_register
(
&
sa11x0_serial_driver
);
sys_device_register
(
&
sa11x0_serial_devs
);
sa1100_init_ports
();
ret
=
uart_register_driver
(
&
sa1100_reg
);
if
(
ret
==
0
)
{
...
...
include/linux/pci_ids.h
View file @
0deb87aa
...
...
@@ -1235,6 +1235,7 @@
#define PCI_VENDOR_ID_XIRCOM 0x115d
#define PCI_DEVICE_ID_XIRCOM_X3201_ETH 0x0003
#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103
#define PCI_VENDOR_ID_RENDITION 0x1163
...
...
include/linux/serial_core.h
View file @
0deb87aa
...
...
@@ -208,12 +208,11 @@ struct uart_state {
#define USF_CLOSING_WAIT_NONE (65535)
int
count
;
int
pm_state
;
struct
uart_info
*
info
;
struct
uart_port
*
port
;
#ifdef CONFIG_PM
struct
pm_dev
*
pm
;
#endif
struct
semaphore
sem
;
};
#define UART_XMIT_SIZE 1024
...
...
@@ -224,8 +223,6 @@ struct uart_state {
* stuff here.
*/
struct
uart_info
{
struct
uart_port
*
port
;
struct
uart_state
*
state
;
struct
tty_struct
*
tty
;
struct
circ_buf
xmit
;
unsigned
int
flags
;
...
...
@@ -237,7 +234,6 @@ struct uart_info {
*/
#define UIF_CHECK_CD (1 << 25)
#define UIF_CTS_FLOW (1 << 26)
#define UIF_CLOSING (1 << 27)
#define UIF_NORMAL_ACTIVE (1 << 29)
#define UIF_INITIALIZED (1 << 31)
...
...
@@ -307,6 +303,12 @@ int uart_register_port(struct uart_driver *reg, struct uart_port *port);
int
uart_add_one_port
(
struct
uart_driver
*
reg
,
struct
uart_port
*
port
);
int
uart_remove_one_port
(
struct
uart_driver
*
reg
,
struct
uart_port
*
port
);
/*
* Power Management
*/
int
uart_suspend_port
(
struct
uart_driver
*
reg
,
struct
uart_port
*
port
,
u32
level
);
int
uart_resume_port
(
struct
uart_driver
*
reg
,
struct
uart_port
*
port
,
u32
level
);
#define uart_circ_empty(circ) ((circ)->head == (circ)->tail)
#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment