Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d8b3edf1
Commit
d8b3edf1
authored
Oct 18, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk/linux-2.6-serial
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
340fc58c
0dbd84c6
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
466 additions
and
164 deletions
+466
-164
drivers/serial/8250.c
drivers/serial/8250.c
+415
-125
drivers/serial/8250.h
drivers/serial/8250.h
+6
-2
drivers/serial/8250_pci.c
drivers/serial/8250_pci.c
+36
-37
drivers/serial/serial_core.c
drivers/serial/serial_core.c
+9
-0
No files found.
drivers/serial/8250.c
View file @
d8b3edf1
...
...
@@ -157,23 +157,109 @@ static struct irq_info irq_lists[NR_IRQS];
/*
* Here we define the default xmit fifo size used for each type of UART.
*/
static
const
struct
serial8250_config
uart_config
[
PORT_MAX_8250
+
1
]
=
{
{
"unknown"
,
1
,
1
,
0
},
{
"8250"
,
1
,
1
,
0
},
{
"16450"
,
1
,
1
,
0
},
{
"16550"
,
1
,
1
,
0
},
{
"16550A"
,
16
,
16
,
UART_CAP_FIFO
},
{
"Cirrus"
,
1
,
1
,
0
},
{
"ST16650"
,
1
,
1
,
UART_CAP_FIFO
|
UART_CAP_SLEEP
|
UART_CAP_EFR
},
{
"ST16650V2"
,
32
,
16
,
UART_CAP_FIFO
|
UART_CAP_SLEEP
|
UART_CAP_EFR
},
{
"TI16750"
,
64
,
64
,
UART_CAP_FIFO
|
UART_CAP_SLEEP
},
{
"Startech"
,
1
,
1
,
0
},
{
"16C950/954"
,
128
,
128
,
UART_CAP_FIFO
},
{
"ST16654"
,
64
,
32
,
UART_CAP_FIFO
|
UART_CAP_SLEEP
|
UART_CAP_EFR
},
{
"XR16850"
,
128
,
128
,
UART_CAP_FIFO
|
UART_CAP_SLEEP
|
UART_CAP_EFR
},
{
"RSA"
,
2048
,
2048
,
UART_CAP_FIFO
},
{
"NS16550A"
,
16
,
16
,
UART_CAP_FIFO
|
UART_NATSEMI
},
{
"XScale"
,
32
,
32
,
UART_CAP_FIFO
},
static
const
struct
serial8250_config
uart_config
[]
=
{
[
PORT_UNKNOWN
]
=
{
.
name
=
"unknown"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_8250
]
=
{
.
name
=
"8250"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_16450
]
=
{
.
name
=
"16450"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_16550
]
=
{
.
name
=
"16550"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_16550A
]
=
{
.
name
=
"16550A"
,
.
fifo_size
=
16
,
.
tx_loadsz
=
16
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
,
.
flags
=
UART_CAP_FIFO
,
},
[
PORT_CIRRUS
]
=
{
.
name
=
"Cirrus"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_16650
]
=
{
.
name
=
"ST16650"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
.
flags
=
UART_CAP_FIFO
|
UART_CAP_EFR
|
UART_CAP_SLEEP
,
},
[
PORT_16650V2
]
=
{
.
name
=
"ST16650V2"
,
.
fifo_size
=
32
,
.
tx_loadsz
=
16
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_01
|
UART_FCR_T_TRIG_00
,
.
flags
=
UART_CAP_FIFO
|
UART_CAP_EFR
|
UART_CAP_SLEEP
,
},
[
PORT_16750
]
=
{
.
name
=
"TI16750"
,
.
fifo_size
=
64
,
.
tx_loadsz
=
64
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
|
UART_FCR7_64BYTE
,
.
flags
=
UART_CAP_FIFO
|
UART_CAP_SLEEP
|
UART_CAP_AFE
,
},
[
PORT_STARTECH
]
=
{
.
name
=
"Startech"
,
.
fifo_size
=
1
,
.
tx_loadsz
=
1
,
},
[
PORT_16C950
]
=
{
.
name
=
"16C950/954"
,
.
fifo_size
=
128
,
.
tx_loadsz
=
128
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
,
.
flags
=
UART_CAP_FIFO
,
},
[
PORT_16654
]
=
{
.
name
=
"ST16654"
,
.
fifo_size
=
64
,
.
tx_loadsz
=
32
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_01
|
UART_FCR_T_TRIG_10
,
.
flags
=
UART_CAP_FIFO
|
UART_CAP_EFR
|
UART_CAP_SLEEP
,
},
[
PORT_16850
]
=
{
.
name
=
"XR16850"
,
.
fifo_size
=
128
,
.
tx_loadsz
=
128
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
,
.
flags
=
UART_CAP_FIFO
|
UART_CAP_EFR
|
UART_CAP_SLEEP
,
},
[
PORT_RSA
]
=
{
.
name
=
"RSA"
,
.
fifo_size
=
2048
,
.
tx_loadsz
=
2048
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_11
,
.
flags
=
UART_CAP_FIFO
,
},
[
PORT_NS16550A
]
=
{
.
name
=
"NS16550A"
,
.
fifo_size
=
16
,
.
tx_loadsz
=
16
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
,
.
flags
=
UART_CAP_FIFO
|
UART_NATSEMI
,
},
[
PORT_XSCALE
]
=
{
.
name
=
"XScale"
,
.
fifo_size
=
32
,
.
tx_loadsz
=
32
,
.
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_R_TRIG_10
,
.
flags
=
UART_CAP_FIFO
,
},
};
static
_INLINE_
unsigned
int
serial_in
(
struct
uart_8250_port
*
up
,
int
offset
)
...
...
@@ -404,6 +490,11 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
{
unsigned
char
id1
,
id2
,
id3
,
rev
,
saved_dll
,
saved_dlm
;
/*
* Everything with an EFR has SLEEP
*/
up
->
capabilities
|=
UART_CAP_EFR
|
UART_CAP_SLEEP
;
/*
* First we check to see if it's an Oxford Semiconductor UART.
*
...
...
@@ -514,6 +605,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
unsigned
char
status1
,
status2
;
up
->
port
.
type
=
PORT_16550A
;
up
->
capabilities
|=
UART_CAP_FIFO
;
/*
* Check for presence of the EFR when DLAB is set.
...
...
@@ -525,6 +617,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if
(
serial_in
(
up
,
UART_EFR
)
!=
0
)
{
DEBUG_AUTOCONF
(
"EFRv1 "
);
up
->
port
.
type
=
PORT_16650
;
up
->
capabilities
|=
UART_CAP_EFR
|
UART_CAP_SLEEP
;
}
else
{
DEBUG_AUTOCONF
(
"Motorola 8xxx DUART "
);
}
...
...
@@ -577,6 +670,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
#endif
up
->
port
.
type
=
PORT_NS16550A
;
up
->
capabilities
|=
UART_NATSEMI
;
return
;
}
}
...
...
@@ -600,6 +694,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
if
(
status1
==
6
&&
status2
==
7
)
{
up
->
port
.
type
=
PORT_16750
;
up
->
capabilities
|=
UART_CAP_AFE
|
UART_CAP_SLEEP
;
return
;
}
}
...
...
@@ -630,6 +725,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
// save_flags(flags); cli();
up
->
capabilities
=
0
;
if
(
!
(
up
->
port
.
flags
&
UPF_BUGGY_UART
))
{
/*
* Do a simple existence test first; if we fail this,
...
...
@@ -740,6 +837,13 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
#endif
serial_outp
(
up
,
UART_LCR
,
save_lcr
);
if
(
up
->
capabilities
!=
uart_config
[
up
->
port
.
type
].
flags
)
{
printk
(
KERN_WARNING
"ttyS%d: detected caps %08x should be %08x
\n
"
,
up
->
port
.
line
,
up
->
capabilities
,
uart_config
[
up
->
port
.
type
].
flags
);
}
up
->
port
.
fifosize
=
uart_config
[
up
->
port
.
type
].
fifo_size
;
up
->
capabilities
=
uart_config
[
up
->
port
.
type
].
flags
;
up
->
tx_loadsz
=
uart_config
[
up
->
port
.
type
].
tx_loadsz
;
...
...
@@ -822,6 +926,12 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
up
->
ier
&=
~
UART_IER_THRI
;
serial_out
(
up
,
UART_IER
,
up
->
ier
);
}
/*
* We only do this from uart_stop - if we run out of
* characters to send, we don't want to prevent the
* FIFO from emptying.
*/
if
(
up
->
port
.
type
==
PORT_16C950
&&
tty_stop
)
{
up
->
acr
|=
UART_ACR_TXDIS
;
serial_icr_write
(
up
,
UART_ACR
,
up
->
acr
);
...
...
@@ -866,7 +976,7 @@ static _INLINE_ void
receive_chars
(
struct
uart_8250_port
*
up
,
int
*
status
,
struct
pt_regs
*
regs
)
{
struct
tty_struct
*
tty
=
up
->
port
.
info
->
tty
;
unsigned
char
ch
;
unsigned
char
ch
,
lsr
=
*
status
;
int
max_count
=
256
;
do
{
...
...
@@ -880,13 +990,23 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_NORMAL
;
up
->
port
.
icount
.
rx
++
;
if
(
unlikely
(
*
status
&
(
UART_LSR_BI
|
UART_LSR_PE
|
#ifdef CONFIG_SERIAL_8250_CONSOLE
/*
* Recover the break flag from console xmit
*/
if
(
up
->
port
.
line
==
up
->
port
.
cons
->
index
)
{
lsr
|=
up
->
lsr_break_flag
;
up
->
lsr_break_flag
=
0
;
}
#endif
if
(
unlikely
(
lsr
&
(
UART_LSR_BI
|
UART_LSR_PE
|
UART_LSR_FE
|
UART_LSR_OE
)))
{
/*
* For statistics only
*/
if
(
*
status
&
UART_LSR_BI
)
{
*
status
&=
~
(
UART_LSR_FE
|
UART_LSR_PE
);
if
(
lsr
&
UART_LSR_BI
)
{
lsr
&=
~
(
UART_LSR_FE
|
UART_LSR_PE
);
up
->
port
.
icount
.
brk
++
;
/*
* We do the SysRQ and SAK checking
...
...
@@ -896,41 +1016,34 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
*/
if
(
uart_handle_break
(
&
up
->
port
))
goto
ignore_char
;
}
else
if
(
*
status
&
UART_LSR_PE
)
}
else
if
(
lsr
&
UART_LSR_PE
)
up
->
port
.
icount
.
parity
++
;
else
if
(
*
status
&
UART_LSR_FE
)
else
if
(
lsr
&
UART_LSR_FE
)
up
->
port
.
icount
.
frame
++
;
if
(
*
status
&
UART_LSR_OE
)
if
(
lsr
&
UART_LSR_OE
)
up
->
port
.
icount
.
overrun
++
;
/*
* Mask off conditions which should be ingored.
*/
*
status
&=
up
->
port
.
read_status_mask
;
lsr
&=
up
->
port
.
read_status_mask
;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if
(
up
->
port
.
line
==
up
->
port
.
cons
->
index
)
{
/* Recover the break flag from console xmit */
*
status
|=
up
->
lsr_break_flag
;
up
->
lsr_break_flag
=
0
;
}
#endif
if
(
*
status
&
UART_LSR_BI
)
{
if
(
lsr
&
UART_LSR_BI
)
{
DEBUG_INTR
(
"handling break...."
);
*
tty
->
flip
.
flag_buf_ptr
=
TTY_BREAK
;
}
else
if
(
*
status
&
UART_LSR_PE
)
}
else
if
(
lsr
&
UART_LSR_PE
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_PARITY
;
else
if
(
*
status
&
UART_LSR_FE
)
else
if
(
lsr
&
UART_LSR_FE
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_FRAME
;
}
if
(
uart_handle_sysrq_char
(
&
up
->
port
,
ch
,
regs
))
goto
ignore_char
;
if
((
*
status
&
up
->
port
.
ignore_status_mask
)
==
0
)
{
if
((
lsr
&
up
->
port
.
ignore_status_mask
)
==
0
)
{
tty
->
flip
.
flag_buf_ptr
++
;
tty
->
flip
.
char_buf_ptr
++
;
tty
->
flip
.
count
++
;
}
if
((
*
status
&
UART_LSR_OE
)
&&
if
((
lsr
&
UART_LSR_OE
)
&&
tty
->
flip
.
count
<
TTY_FLIPBUF_SIZE
)
{
/*
* Overrun is special, since it's reported
...
...
@@ -943,9 +1056,10 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
tty
->
flip
.
count
++
;
}
ignore_char:
*
status
=
serial_inp
(
up
,
UART_LSR
);
}
while
((
*
status
&
UART_LSR_DR
)
&&
(
max_count
--
>
0
));
lsr
=
serial_inp
(
up
,
UART_LSR
);
}
while
((
lsr
&
UART_LSR_DR
)
&&
(
max_count
--
>
0
));
tty_flip_buffer_push
(
tty
);
*
status
=
lsr
;
}
static
_INLINE_
void
transmit_chars
(
struct
uart_8250_port
*
up
)
...
...
@@ -1493,25 +1607,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
if
(
up
->
capabilities
&
UART_CAP_FIFO
&&
up
->
port
.
fifosize
>
1
)
{
if
(
baud
<
2400
)
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_TRIGGER_1
;
#ifdef CONFIG_SERIAL_8250_RSA
else
if
(
up
->
port
.
type
==
PORT_RSA
)
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_TRIGGER_14
;
#endif
else
fcr
=
UART_FCR_ENABLE_FIFO
|
UART_FCR_TRIGGER_8
;
fcr
=
uart_config
[
up
->
port
.
type
].
fcr
;
}
/*
* TI16C750: hardware flow control and 64 byte FIFOs. When AFE is
* enabled, RTS will be deasserted when the receive FIFO contains
* more characters than the trigger, or the MCR RTS bit is cleared.
*/
if
(
up
->
port
.
type
==
PORT_16750
)
{
* MCR-based auto flow control. When AFE is enabled, RTS will be
* deasserted when the receive FIFO contains more characters than
* the trigger, or the MCR RTS bit is cleared. In the case where
* the remote UART is not using CTS auto flow control, we must
* have sufficient FIFO entries for the latency of the remote
* UART to respond. IOW, at least 32 bytes of FIFO.
*/
if
(
up
->
capabilities
&
UART_CAP_AFE
&&
up
->
port
.
fifosize
>=
32
)
{
up
->
mcr
&=
~
UART_MCR_AFE
;
if
(
termios
->
c_cflag
&
CRTSCTS
)
up
->
mcr
|=
UART_MCR_AFE
;
fcr
|=
UART_FCR7_64BYTE
;
}
/*
...
...
@@ -1565,9 +1676,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_out
(
up
,
UART_IER
,
up
->
ier
);
if
(
up
->
capabilities
&
UART_CAP_EFR
)
{
unsigned
char
efr
=
0
;
/*
* TI16C752/Startech hardware flow control. FIXME:
* - TI16C752 requires control thresholds to be set.
* - UART_MCR_RTS is ineffective if auto-RTS mode is enabled.
*/
if
(
termios
->
c_cflag
&
CRTSCTS
)
efr
|=
UART_EFR_CTS
;
serial_outp
(
up
,
UART_LCR
,
0xBF
);
serial_outp
(
up
,
UART_EFR
,
termios
->
c_cflag
&
CRTSCTS
?
UART_EFR_CTS
:
0
);
serial_outp
(
up
,
UART_EFR
,
efr
);
}
if
(
up
->
capabilities
&
UART_NATSEMI
)
{
...
...
@@ -1797,7 +1916,7 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if
(
ser
->
irq
>=
NR_IRQS
||
ser
->
irq
<
0
||
ser
->
baud_base
<
9600
||
ser
->
type
<
PORT_UNKNOWN
||
ser
->
type
>
PORT_MAX_8250
||
ser
->
type
==
PORT_CIRRUS
||
ser
->
type
>
=
ARRAY_SIZE
(
uart_config
)
||
ser
->
type
==
PORT_CIRRUS
||
ser
->
type
==
PORT_STARTECH
)
return
-
EINVAL
;
return
0
;
...
...
@@ -1861,7 +1980,8 @@ static void __init serial8250_isa_init_ports(void)
}
}
static
void
__init
serial8250_register_ports
(
struct
uart_driver
*
drv
)
static
void
__init
serial8250_register_ports
(
struct
uart_driver
*
drv
,
struct
device
*
dev
)
{
int
i
;
...
...
@@ -1872,6 +1992,7 @@ static void __init serial8250_register_ports(struct uart_driver *drv)
up
->
port
.
line
=
i
;
up
->
port
.
ops
=
&
serial8250_pops
;
up
->
port
.
dev
=
dev
;
init_timer
(
&
up
->
timer
);
up
->
timer
.
function
=
serial8250_timeout
;
...
...
@@ -2038,60 +2159,6 @@ static struct uart_driver serial8250_reg = {
.
cons
=
SERIAL8250_CONSOLE
,
};
/*
* register_serial and unregister_serial allows for 16x50 serial ports to be
* configured at run-time, to support PCMCIA modems.
*/
static
int
__register_serial
(
struct
serial_struct
*
req
,
int
line
)
{
struct
uart_port
port
;
port
.
iobase
=
req
->
port
;
port
.
membase
=
req
->
iomem_base
;
port
.
irq
=
req
->
irq
;
port
.
uartclk
=
req
->
baud_base
*
16
;
port
.
fifosize
=
req
->
xmit_fifo_size
;
port
.
regshift
=
req
->
iomem_reg_shift
;
port
.
iotype
=
req
->
io_type
;
port
.
flags
=
req
->
flags
|
UPF_BOOT_AUTOCONF
;
port
.
mapbase
=
req
->
iomap_base
;
port
.
line
=
line
;
if
(
share_irqs
)
port
.
flags
|=
UPF_SHARE_IRQ
;
if
(
HIGH_BITS_OFFSET
)
port
.
iobase
|=
(
long
)
req
->
port_high
<<
HIGH_BITS_OFFSET
;
/*
* If a clock rate wasn't specified by the low level
* driver, then default to the standard clock rate.
*/
if
(
port
.
uartclk
==
0
)
port
.
uartclk
=
BASE_BAUD
*
16
;
return
uart_register_port
(
&
serial8250_reg
,
&
port
);
}
/**
* register_serial - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
* port exists and is in use an error is returned. If the port
* is not currently in the table it is added.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int
register_serial
(
struct
serial_struct
*
req
)
{
return
__register_serial
(
req
,
-
1
);
}
int
__init
early_serial_setup
(
struct
uart_port
*
port
)
{
if
(
port
->
line
>=
ARRAY_SIZE
(
serial8250_ports
))
...
...
@@ -2103,18 +2170,6 @@ int __init early_serial_setup(struct uart_port *port)
return
0
;
}
/**
* unregister_serial - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may be called from interrupt
* context.
*/
void
unregister_serial
(
int
line
)
{
uart_unregister_port
(
&
serial8250_reg
,
line
);
}
/*
* This is for ISAPNP only.
*/
...
...
@@ -2153,6 +2208,174 @@ void serial8250_resume_port(int line)
uart_resume_port
(
&
serial8250_reg
,
&
serial8250_ports
[
line
].
port
);
}
static
int
serial8250_suspend
(
struct
device
*
dev
,
u32
state
,
u32
level
)
{
int
i
;
if
(
level
!=
SUSPEND_DISABLE
)
return
0
;
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
{
struct
uart_8250_port
*
up
=
&
serial8250_ports
[
i
];
if
(
up
->
port
.
type
!=
PORT_UNKNOWN
&&
up
->
port
.
dev
==
dev
)
uart_suspend_port
(
&
serial8250_reg
,
&
up
->
port
);
}
return
0
;
}
static
int
serial8250_resume
(
struct
device
*
dev
,
u32
level
)
{
int
i
;
if
(
level
!=
RESUME_ENABLE
)
return
0
;
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
{
struct
uart_8250_port
*
up
=
&
serial8250_ports
[
i
];
if
(
up
->
port
.
type
!=
PORT_UNKNOWN
&&
up
->
port
.
dev
==
dev
)
uart_resume_port
(
&
serial8250_reg
,
&
up
->
port
);
}
return
0
;
}
static
struct
device_driver
serial8250_isa_driver
=
{
.
name
=
"serial8250"
,
.
bus
=
&
platform_bus_type
,
.
suspend
=
serial8250_suspend
,
.
resume
=
serial8250_resume
,
};
/*
* serial8250_register_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
*/
static
DECLARE_MUTEX
(
serial_sem
);
/*
* Are the two ports equivalent?
*/
static
int
uart_match_port
(
struct
uart_port
*
port1
,
struct
uart_port
*
port2
)
{
if
(
port1
->
iotype
!=
port2
->
iotype
)
return
0
;
switch
(
port1
->
iotype
)
{
case
UPIO_PORT
:
return
(
port1
->
iobase
==
port2
->
iobase
);
case
UPIO_HUB6
:
return
(
port1
->
iobase
==
port2
->
iobase
)
&&
(
port1
->
hub6
==
port2
->
hub6
);
case
UPIO_MEM
:
return
(
port1
->
membase
==
port2
->
membase
);
}
return
0
;
}
static
struct
uart_8250_port
*
serial8250_find_match_or_unused
(
struct
uart_port
*
port
)
{
int
i
;
/*
* First, find a port entry which matches.
*/
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
if
(
uart_match_port
(
&
serial8250_ports
[
i
].
port
,
port
))
return
&
serial8250_ports
[
i
];
/*
* We didn't find a matching entry, so look for the first
* free entry. We look for one which hasn't been previously
* used (indicated by zero iobase).
*/
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
if
(
serial8250_ports
[
i
].
port
.
type
==
PORT_UNKNOWN
&&
serial8250_ports
[
i
].
port
.
iobase
==
0
)
return
&
serial8250_ports
[
i
];
/*
* That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it.
*/
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
if
(
serial8250_ports
[
i
].
port
.
type
==
PORT_UNKNOWN
)
return
&
serial8250_ports
[
i
];
return
NULL
;
}
/**
* serial8250_register_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
* port exists and is in use, it is hung up and unregistered
* first.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int
serial8250_register_port
(
struct
uart_port
*
port
)
{
struct
uart_8250_port
*
uart
;
int
ret
=
-
ENOSPC
;
down
(
&
serial_sem
);
uart
=
serial8250_find_match_or_unused
(
port
);
if
(
uart
)
{
uart_remove_one_port
(
&
serial8250_reg
,
&
uart
->
port
);
uart
->
port
.
iobase
=
port
->
iobase
;
uart
->
port
.
membase
=
port
->
membase
;
uart
->
port
.
irq
=
port
->
irq
;
uart
->
port
.
uartclk
=
port
->
uartclk
;
uart
->
port
.
fifosize
=
port
->
fifosize
;
uart
->
port
.
regshift
=
port
->
regshift
;
uart
->
port
.
iotype
=
port
->
iotype
;
uart
->
port
.
flags
=
port
->
flags
|
UPF_BOOT_AUTOCONF
;
uart
->
port
.
mapbase
=
port
->
mapbase
;
if
(
port
->
dev
)
uart
->
port
.
dev
=
port
->
dev
;
ret
=
uart_add_one_port
(
&
serial8250_reg
,
&
uart
->
port
);
if
(
ret
==
0
)
ret
=
uart
->
port
.
line
;
}
up
(
&
serial_sem
);
return
ret
;
}
EXPORT_SYMBOL
(
serial8250_register_port
);
/**
* serial8250_unregister_port - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to the our control.
*/
void
serial8250_unregister_port
(
int
line
)
{
struct
uart_8250_port
*
uart
=
&
serial8250_ports
[
line
];
down
(
&
serial_sem
);
uart_remove_one_port
(
&
serial8250_reg
,
&
uart
->
port
);
uart
->
port
.
flags
&=
~
UPF_BOOT_AUTOCONF
;
uart
->
port
.
type
=
PORT_UNKNOWN
;
uart
->
port
.
dev
=
NULL
;
uart_add_one_port
(
&
serial8250_reg
,
&
uart
->
port
);
up
(
&
serial_sem
);
}
EXPORT_SYMBOL
(
serial8250_unregister_port
);
static
int
__init
serial8250_init
(
void
)
{
int
ret
,
i
;
...
...
@@ -2161,13 +2384,23 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled
\n
"
,
(
int
)
UART_NR
,
share_irqs
?
"en"
:
"dis"
);
ret
=
driver_register
(
&
serial8250_isa_driver
);
if
(
ret
)
goto
out
;
for
(
i
=
0
;
i
<
NR_IRQS
;
i
++
)
spin_lock_init
(
&
irq_lists
[
i
].
lock
);
ret
=
uart_register_driver
(
&
serial8250_reg
);
if
(
ret
>=
0
)
serial8250_register_ports
(
&
serial8250_reg
)
;
if
(
ret
)
goto
unreg
;
serial8250_register_ports
(
&
serial8250_reg
,
NULL
);
goto
out
;
unreg:
driver_unregister
(
&
serial8250_isa_driver
);
out:
return
ret
;
}
...
...
@@ -2179,13 +2412,12 @@ static void __exit serial8250_exit(void)
uart_remove_one_port
(
&
serial8250_reg
,
&
serial8250_ports
[
i
].
port
);
uart_unregister_driver
(
&
serial8250_reg
);
driver_unregister
(
&
serial8250_isa_driver
);
}
module_init
(
serial8250_init
);
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
);
...
...
@@ -2202,3 +2434,61 @@ module_param_array(probe_rsa, ulong, probe_rsa_count, 0444);
MODULE_PARM_DESC
(
probe_rsa
,
"Probe I/O ports for RSA"
);
#endif
MODULE_ALIAS_CHARDEV_MAJOR
(
TTY_MAJOR
);
/**
* register_serial - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
* port exists and is in use an error is returned. If the port
* is not currently in the table it is added.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int
register_serial
(
struct
serial_struct
*
req
)
{
struct
uart_port
port
;
port
.
iobase
=
req
->
port
;
port
.
membase
=
req
->
iomem_base
;
port
.
irq
=
req
->
irq
;
port
.
uartclk
=
req
->
baud_base
*
16
;
port
.
fifosize
=
req
->
xmit_fifo_size
;
port
.
regshift
=
req
->
iomem_reg_shift
;
port
.
iotype
=
req
->
io_type
;
port
.
flags
=
req
->
flags
|
UPF_BOOT_AUTOCONF
;
port
.
mapbase
=
req
->
iomap_base
;
port
.
dev
=
NULL
;
if
(
share_irqs
)
port
.
flags
|=
UPF_SHARE_IRQ
;
if
(
HIGH_BITS_OFFSET
)
port
.
iobase
|=
(
long
)
req
->
port_high
<<
HIGH_BITS_OFFSET
;
/*
* If a clock rate wasn't specified by the low level
* driver, then default to the standard clock rate.
*/
if
(
port
.
uartclk
==
0
)
port
.
uartclk
=
BASE_BAUD
*
16
;
return
serial8250_register_port
(
&
port
);
}
EXPORT_SYMBOL
(
register_serial
);
/**
* unregister_serial - remove a 16x50 serial port at runtime
* @line: serial line number
*
* Remove one serial port. This may not be called from interrupt
* context. We hand the port back to our local PM control.
*/
void
unregister_serial
(
int
line
)
{
serial8250_unregister_port
(
line
);
}
EXPORT_SYMBOL
(
unregister_serial
);
drivers/serial/8250.h
View file @
d8b3edf1
...
...
@@ -17,6 +17,8 @@
#include <linux/config.h>
int
serial8250_register_port
(
struct
uart_port
*
);
void
serial8250_unregister_port
(
int
line
);
void
serial8250_get_irq_map
(
unsigned
int
*
map
);
void
serial8250_suspend_port
(
int
line
);
void
serial8250_resume_port
(
int
line
);
...
...
@@ -38,14 +40,16 @@ struct old_serial_port {
*/
struct
serial8250_config
{
const
char
*
name
;
unsigned
int
fifo_size
;
unsigned
int
tx_loadsz
;
unsigned
short
fifo_size
;
unsigned
short
tx_loadsz
;
unsigned
char
fcr
;
unsigned
int
flags
;
};
#define UART_CAP_FIFO (1 << 8)
/* UART has FIFO */
#define UART_CAP_EFR (1 << 9)
/* UART has EFR */
#define UART_CAP_SLEEP (1 << 10)
/* UART has IER sleep */
#define UART_CAP_AFE (1 << 11)
/* MCR-based hw flow control */
#undef SERIAL_DEBUG_PCI
...
...
drivers/serial/8250_pci.c
View file @
d8b3edf1
...
...
@@ -22,7 +22,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
...
...
@@ -75,7 +74,7 @@ struct pci_serial_quirk {
u32
subdevice
;
int
(
*
init
)(
struct
pci_dev
*
dev
);
int
(
*
setup
)(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
);
struct
uart_port
*
port
,
int
idx
);
void
(
*
exit
)(
struct
pci_dev
*
dev
);
};
...
...
@@ -100,34 +99,32 @@ static void moan_device(const char *str, struct pci_dev *dev)
}
static
int
setup_port
(
struct
pci_dev
*
dev
,
struct
serial_struct
*
req
,
setup_port
(
struct
pci_dev
*
dev
,
struct
uart_port
*
port
,
int
bar
,
int
offset
,
int
regshift
)
{
struct
serial_private
*
priv
=
pci_get_drvdata
(
dev
);
unsigned
long
port
,
len
;
unsigned
long
base
,
len
;
if
(
bar
>=
PCI_NUM_BAR_RESOURCES
)
return
-
EINVAL
;
if
(
pci_resource_flags
(
dev
,
bar
)
&
IORESOURCE_MEM
)
{
port
=
pci_resource_start
(
dev
,
bar
);
base
=
pci_resource_start
(
dev
,
bar
);
len
=
pci_resource_len
(
dev
,
bar
);
if
(
!
priv
->
remapped_bar
[
bar
])
priv
->
remapped_bar
[
bar
]
=
ioremap
(
port
,
len
);
priv
->
remapped_bar
[
bar
]
=
ioremap
(
base
,
len
);
if
(
!
priv
->
remapped_bar
[
bar
])
return
-
ENOMEM
;
req
->
io_
type
=
UPIO_MEM
;
req
->
iomap_base
=
port
+
offset
;
req
->
iomem_
base
=
priv
->
remapped_bar
[
bar
]
+
offset
;
req
->
iomem_reg_
shift
=
regshift
;
port
->
io
type
=
UPIO_MEM
;
port
->
mapbase
=
base
+
offset
;
port
->
mem
base
=
priv
->
remapped_bar
[
bar
]
+
offset
;
port
->
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
;
base
=
pci_resource_start
(
dev
,
bar
)
+
offset
;
port
->
iotype
=
UPIO_PORT
;
port
->
iobase
=
base
;
}
return
0
;
}
...
...
@@ -138,7 +135,7 @@ setup_port(struct pci_dev *dev, struct serial_struct *req,
*/
static
int
afavlab_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
;
...
...
@@ -150,7 +147,7 @@ afavlab_setup(struct pci_dev *dev, struct pci_board *board,
offset
+=
(
idx
-
4
)
*
board
->
uart_offset
;
}
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
...
...
@@ -191,7 +188,7 @@ static int __devinit pci_hp_diva_init(struct pci_dev *dev)
*/
static
int
pci_hp_diva_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
offset
=
board
->
first_offset
;
unsigned
int
bar
=
FL_GET_BASE
(
board
->
flags
);
...
...
@@ -213,7 +210,7 @@ pci_hp_diva_setup(struct pci_dev *dev, struct pci_board *board,
offset
+=
idx
*
board
->
uart_offset
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
...
...
@@ -309,7 +306,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static
int
sbs_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
;
...
...
@@ -324,7 +321,7 @@ sbs_setup(struct pci_dev *dev, struct pci_board *board,
}
else
/* we have only 8 ports on PMC-OCTALPRO */
return
1
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
...
...
@@ -522,7 +519,7 @@ static int __devinit pci_timedia_init(struct pci_dev *dev)
*/
static
int
pci_timedia_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
bar
=
0
,
offset
=
board
->
first_offset
;
...
...
@@ -547,7 +544,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
bar
=
idx
-
2
;
}
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
/*
...
...
@@ -555,7 +552,7 @@ pci_timedia_setup(struct pci_dev *dev, struct pci_board *board,
*/
static
int
titan_400l_800l_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
;
...
...
@@ -571,7 +568,7 @@ titan_400l_800l_setup(struct pci_dev *dev, struct pci_board *board,
offset
=
(
idx
-
2
)
*
board
->
uart_offset
;
}
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
static
int
__devinit
pci_xircom_init
(
struct
pci_dev
*
dev
)
...
...
@@ -582,7 +579,7 @@ static int __devinit pci_xircom_init(struct pci_dev *dev)
static
int
pci_default_setup
(
struct
pci_dev
*
dev
,
struct
pci_board
*
board
,
struct
serial_struct
*
req
,
int
idx
)
struct
uart_port
*
port
,
int
idx
)
{
unsigned
int
bar
,
offset
=
board
->
first_offset
,
maxnr
;
...
...
@@ -598,7 +595,7 @@ pci_default_setup(struct pci_dev *dev, struct pci_board *board,
if
(
board
->
flags
&
FL_REGION_SZ_CAP
&&
idx
>=
maxnr
)
return
1
;
return
setup_port
(
dev
,
req
,
bar
,
offset
,
board
->
reg_shift
);
return
setup_port
(
dev
,
port
,
bar
,
offset
,
board
->
reg_shift
);
}
/* This should be in linux/pci_ids.h */
...
...
@@ -1610,7 +1607,6 @@ pciserial_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
rc
,
nr_ports
,
i
;
if
(
ent
->
driver_data
>=
ARRAY_SIZE
(
pci_boards
))
{
...
...
@@ -1690,19 +1686,22 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
pci_set_drvdata
(
dev
,
priv
);
for
(
i
=
0
;
i
<
nr_ports
;
i
++
)
{
memset
(
&
serial_req
,
0
,
sizeof
(
serial_req
));
serial_req
.
flags
=
UPF_SKIP_TEST
|
UPF_AUTOPROBE
|
struct
uart_port
serial_port
;
memset
(
&
serial_port
,
0
,
sizeof
(
struct
uart_port
));
serial_port
.
flags
=
UPF_SKIP_TEST
|
UPF_AUTOPROBE
|
UPF_SHARE_IRQ
;
serial_req
.
baud_base
=
board
->
base_baud
;
serial_req
.
irq
=
get_pci_irq
(
dev
,
board
,
i
);
if
(
quirk
->
setup
(
dev
,
board
,
&
serial_req
,
i
))
serial_port
.
uartclk
=
board
->
base_baud
*
16
;
serial_port
.
irq
=
get_pci_irq
(
dev
,
board
,
i
);
serial_port
.
dev
=
&
dev
->
dev
;
if
(
quirk
->
setup
(
dev
,
board
,
&
serial_port
,
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
);
serial_
port
.
iobase
,
serial_port
.
irq
,
serial_port
.
io
type
);
#endif
priv
->
line
[
i
]
=
register_serial
(
&
serial_req
);
priv
->
line
[
i
]
=
serial8250_register_port
(
&
serial_port
);
if
(
priv
->
line
[
i
]
<
0
)
{
printk
(
KERN_WARNING
"Couldn't register serial port %s: %d
\n
"
,
pci_name
(
dev
),
priv
->
line
[
i
]);
break
;
...
...
@@ -1732,7 +1731,7 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
int
i
;
for
(
i
=
0
;
i
<
priv
->
nr
;
i
++
)
unregister_serial
(
priv
->
line
[
i
]);
serial8250_unregister_port
(
priv
->
line
[
i
]);
for
(
i
=
0
;
i
<
PCI_NUM_BAR_RESOURCES
;
i
++
)
{
if
(
priv
->
remapped_bar
[
i
])
...
...
drivers/serial/serial_core.c
View file @
d8b3edf1
...
...
@@ -2225,6 +2225,15 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
*/
tty_register_device
(
drv
->
tty_driver
,
port
->
line
,
port
->
dev
);
/*
* If this driver supports console, and it hasn't been
* successfully registered yet, try to re-register it.
* It may be that the port was not available.
*/
if
(
port
->
type
!=
PORT_UNKNOWN
&&
port
->
cons
&&
!
(
port
->
cons
->
flags
&
CON_ENABLED
))
register_console
(
port
->
cons
);
out:
up
(
&
port_sem
);
...
...
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