Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
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