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
130ca59d
Commit
130ca59d
authored
Aug 03, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://gkernel.bkbits.net/misc-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
c3b26786
0b520647
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
938 additions
and
2430 deletions
+938
-2430
arch/sparc64/kernel/devices.c
arch/sparc64/kernel/devices.c
+6
-0
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/smp.c
+77
-88
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sparc64_ksyms.c
+4
-0
arch/sparc64/solaris/systbl.S
arch/sparc64/solaris/systbl.S
+2
-2
drivers/net/myri_sbus.c
drivers/net/myri_sbus.c
+8
-2
drivers/net/myri_sbus.h
drivers/net/myri_sbus.h
+1
-0
drivers/sbus/char/openprom.c
drivers/sbus/char/openprom.c
+0
-27
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.c
+21
-19
drivers/serial/sunsab.c
drivers/serial/sunsab.c
+767
-2213
drivers/serial/sunsab.h
drivers/serial/sunsab.h
+4
-63
drivers/serial/sunsu.c
drivers/serial/sunsu.c
+16
-5
drivers/serial/sunzilog.c
drivers/serial/sunzilog.c
+20
-9
include/asm-sparc64/ns87303.h
include/asm-sparc64/ns87303.h
+8
-2
include/linux/serial_core.h
include/linux/serial_core.h
+4
-0
No files found.
arch/sparc64/kernel/devices.c
View file @
130ca59d
...
@@ -10,6 +10,7 @@
...
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <asm/page.h>
#include <asm/page.h>
#include <asm/oplib.h>
#include <asm/oplib.h>
...
@@ -17,6 +18,11 @@
...
@@ -17,6 +18,11 @@
#include <asm/smp.h>
#include <asm/smp.h>
#include <asm/spitfire.h>
#include <asm/spitfire.h>
/* Used to synchronize acceses to NatSemi SUPER I/O chip configure
* operations in asm/ns87303.h
*/
spinlock_t
ns87303_lock
=
SPIN_LOCK_UNLOCKED
;
struct
prom_cpuinfo
linux_cpus
[
NR_CPUS
]
__initdata
=
{
{
0
}
};
struct
prom_cpuinfo
linux_cpus
[
NR_CPUS
]
__initdata
=
{
{
0
}
};
unsigned
prom_cpu_nodes
[
NR_CPUS
];
unsigned
prom_cpu_nodes
[
NR_CPUS
];
int
linux_num_cpus
=
0
;
int
linux_num_cpus
=
0
;
...
...
arch/sparc64/kernel/smp.c
View file @
130ca59d
...
@@ -45,7 +45,6 @@ cpuinfo_sparc cpu_data[NR_CPUS];
...
@@ -45,7 +45,6 @@ cpuinfo_sparc cpu_data[NR_CPUS];
/* Please don't make this stuff initdata!!! --DaveM */
/* Please don't make this stuff initdata!!! --DaveM */
static
unsigned
char
boot_cpu_id
;
static
unsigned
char
boot_cpu_id
;
static
int
smp_activated
;
/* Kernel spinlock */
/* Kernel spinlock */
spinlock_t
kernel_flag
__cacheline_aligned_in_smp
=
SPIN_LOCK_UNLOCKED
;
spinlock_t
kernel_flag
__cacheline_aligned_in_smp
=
SPIN_LOCK_UNLOCKED
;
...
@@ -223,85 +222,46 @@ extern unsigned long sparc64_cpu_startup;
...
@@ -223,85 +222,46 @@ extern unsigned long sparc64_cpu_startup;
*/
*/
static
struct
thread_info
*
cpu_new_thread
=
NULL
;
static
struct
thread_info
*
cpu_new_thread
=
NULL
;
static
void
__init
smp_boot_cpus
(
unsigned
int
max_cpus
)
static
int
__devinit
smp_boot_one_cpu
(
unsigned
int
cpu
)
{
{
int
cpucount
=
0
,
i
;
printk
(
"Entering UltraSMPenguin Mode...
\n
"
);
local_irq_enable
();
smp_store_cpu_info
(
boot_cpu_id
);
if
(
linux_num_cpus
==
1
)
return
;
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
i
==
boot_cpu_id
)
continue
;
if
((
cpucount
+
1
)
==
max_cpus
)
goto
ignorecpu
;
if
(
test_bit
(
i
,
&
phys_cpu_present_map
))
{
unsigned
long
entry
=
unsigned
long
entry
=
(
unsigned
long
)(
&
sparc64_cpu_startup
);
(
unsigned
long
)(
&
sparc64_cpu_startup
);
unsigned
long
cookie
=
unsigned
long
cookie
=
(
unsigned
long
)(
&
cpu_new_thread
);
(
unsigned
long
)(
&
cpu_new_thread
);
struct
task_struct
*
p
;
struct
task_struct
*
p
;
int
timeout
;
int
timeout
,
no
,
ret
;
int
no
;
prom_printf
(
"Starting CPU %d... "
,
i
);
kernel_thread
(
NULL
,
NULL
,
CLONE_IDLETASK
);
kernel_thread
(
NULL
,
NULL
,
CLONE_IDLETASK
);
cpucount
++
;
p
=
prev_task
(
&
init_task
);
p
=
prev_task
(
&
init_task
);
init_idle
(
p
,
i
);
init_idle
(
p
,
cpu
);
unhash_process
(
p
);
unhash_process
(
p
);
callin_flag
=
0
;
callin_flag
=
0
;
for
(
no
=
0
;
no
<
linux_num_cpus
;
no
++
)
for
(
no
=
0
;
no
<
linux_num_cpus
;
no
++
)
if
(
linux_cpus
[
no
].
mid
==
i
)
if
(
linux_cpus
[
no
].
mid
==
cpu
)
break
;
break
;
cpu_new_thread
=
p
->
thread_info
;
cpu_new_thread
=
p
->
thread_info
;
set_bit
(
i
,
&
cpu_callout_map
);
set_bit
(
cpu
,
&
cpu_callout_map
);
prom_startcpu
(
linux_cpus
[
no
].
prom_node
,
prom_startcpu
(
linux_cpus
[
no
].
prom_node
,
entry
,
cookie
);
entry
,
cookie
);
for
(
timeout
=
0
;
timeout
<
5000000
;
timeout
++
)
{
for
(
timeout
=
0
;
timeout
<
5000000
;
timeout
++
)
{
if
(
callin_flag
)
if
(
callin_flag
)
break
;
break
;
udelay
(
100
);
udelay
(
100
);
}
}
if
(
callin_flag
)
{
if
(
callin_flag
)
{
prom_cpu_nodes
[
i
]
=
linux_cpus
[
no
].
prom_node
;
prom_cpu_nodes
[
cpu
]
=
linux_cpus
[
no
].
prom_node
;
prom_printf
(
"OK
\n
"
)
;
ret
=
0
;
}
else
{
}
else
{
cpucount
--
;
printk
(
"Processor %d is stuck.
\n
"
,
cpu
);
printk
(
"Processor %d is stuck.
\n
"
,
i
);
clear_bit
(
cpu
,
&
cpu_callout_map
);
prom_printf
(
"FAILED
\n
"
);
ret
=
-
ENODEV
;
clear_bit
(
i
,
&
cpu_callout_map
);
}
ignorecpu:
}
}
}
cpu_new_thread
=
NULL
;
cpu_new_thread
=
NULL
;
if
(
cpucount
==
0
)
{
if
(
max_cpus
!=
1
)
printk
(
"Error: only one processor found.
\n
"
);
}
else
{
unsigned
long
bogosum
=
0
;
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
return
ret
;
if
(
cpu_online
(
i
))
bogosum
+=
cpu_data
[
i
].
udelay_val
;
}
printk
(
"Total of %d processors activated "
"(%lu.%02lu BogoMIPS).
\n
"
,
cpucount
+
1
,
bogosum
/
(
500000
/
HZ
),
(
bogosum
/
(
5000
/
HZ
))
%
100
);
smp_activated
=
1
;
}
}
}
static
void
spitfire_xcall_helper
(
u64
data0
,
u64
data1
,
u64
data2
,
u64
pstate
,
unsigned
long
cpu
)
static
void
spitfire_xcall_helper
(
u64
data0
,
u64
data1
,
u64
data2
,
u64
pstate
,
unsigned
long
cpu
)
...
@@ -1119,8 +1079,6 @@ static void __init smp_setup_percpu_timer(void)
...
@@ -1119,8 +1079,6 @@ static void __init smp_setup_percpu_timer(void)
void
__init
smp_tick_init
(
void
)
void
__init
smp_tick_init
(
void
)
{
{
int
i
;
boot_cpu_id
=
hard_smp_processor_id
();
boot_cpu_id
=
hard_smp_processor_id
();
current_tick_offset
=
timer_tick_offset
;
current_tick_offset
=
timer_tick_offset
;
...
@@ -1129,19 +1087,10 @@ void __init smp_tick_init(void)
...
@@ -1129,19 +1087,10 @@ void __init smp_tick_init(void)
prom_halt
();
prom_halt
();
}
}
atomic_set
(
&
sparc64_num_cpus_online
,
1
);
atomic_inc
(
&
sparc64_num_cpus_online
);
memset
(
&
cpu_online_map
,
0
,
sizeof
(
cpu_online_map
));
set_bit
(
boot_cpu_id
,
&
cpu_online_map
);
set_bit
(
boot_cpu_id
,
&
cpu_online_map
);
prom_cpu_nodes
[
boot_cpu_id
]
=
linux_cpus
[
0
].
prom_node
;
prom_cpu_nodes
[
boot_cpu_id
]
=
linux_cpus
[
0
].
prom_node
;
prof_counter
(
boot_cpu_id
)
=
prof_multiplier
(
boot_cpu_id
)
=
1
;
prof_counter
(
boot_cpu_id
)
=
prof_multiplier
(
boot_cpu_id
)
=
1
;
for
(
i
=
0
;
i
<
linux_num_cpus
;
i
++
)
{
if
(
linux_cpus
[
i
].
mid
<
NR_CPUS
)
{
set_bit
(
linux_cpus
[
i
].
mid
,
&
phys_cpu_present_map
);
atomic_inc
(
&
sparc64_num_cpus_possible
);
}
}
}
}
cycles_t
cacheflush_time
;
cycles_t
cacheflush_time
;
...
@@ -1272,19 +1221,59 @@ int setup_profiling_timer(unsigned int multiplier)
...
@@ -1272,19 +1221,59 @@ int setup_profiling_timer(unsigned int multiplier)
void
__init
smp_prepare_cpus
(
unsigned
int
max_cpus
)
void
__init
smp_prepare_cpus
(
unsigned
int
max_cpus
)
{
{
smp_boot_cpus
(
max_cpus
);
int
i
;
for
(
i
=
0
;
i
<
linux_num_cpus
;
i
++
)
{
if
(
linux_cpus
[
i
].
mid
<
max_cpus
)
{
set_bit
(
linux_cpus
[
i
].
mid
,
&
phys_cpu_present_map
);
atomic_inc
(
&
sparc64_num_cpus_possible
);
}
}
if
(
atomic_read
(
&
sparc64_num_cpus_possible
)
>
max_cpus
)
{
for
(
i
=
linux_num_cpus
-
1
;
i
>=
0
;
i
--
)
{
if
(
linux_cpus
[
i
].
mid
!=
boot_cpu_id
)
{
clear_bit
(
linux_cpus
[
i
].
mid
,
&
phys_cpu_present_map
);
atomic_dec
(
&
sparc64_num_cpus_possible
);
if
(
atomic_read
(
&
sparc64_num_cpus_possible
)
<=
max_cpus
)
break
;
}
}
}
smp_store_cpu_info
(
boot_cpu_id
);
}
}
int
__devinit
__cpu_up
(
unsigned
int
cpu
)
int
__devinit
__cpu_up
(
unsigned
int
cpu
)
{
{
int
ret
=
smp_boot_one_cpu
(
cpu
);
if
(
!
ret
)
{
set_bit
(
cpu
,
&
smp_commenced_mask
);
set_bit
(
cpu
,
&
smp_commenced_mask
);
while
(
!
test_bit
(
cpu
,
&
cpu_online_map
))
while
(
!
test_bit
(
cpu
,
&
cpu_online_map
))
mb
();
mb
();
return
0
;
if
(
!
test_bit
(
cpu
,
&
cpu_online_map
))
ret
=
-
ENODEV
;
}
return
ret
;
}
}
void
__init
smp_cpus_done
(
unsigned
int
max_cpus
)
void
__init
smp_cpus_done
(
unsigned
int
max_cpus
)
{
{
unsigned
long
bogosum
=
0
;
int
i
;
for
(
i
=
0
;
i
<
NR_CPUS
;
i
++
)
{
if
(
cpu_online
(
i
))
bogosum
+=
cpu_data
[
i
].
udelay_val
;
}
printk
(
"Total of %d processors activated "
"(%lu.%02lu BogoMIPS).
\n
"
,
num_online_cpus
(),
bogosum
/
(
500000
/
HZ
),
(
bogosum
/
(
5000
/
HZ
))
%
100
);
/* We want to run this with all the other cpus spinning
/* We want to run this with all the other cpus spinning
* in the kernel.
* in the kernel.
*/
*/
...
...
arch/sparc64/kernel/sparc64_ksyms.c
View file @
130ca59d
...
@@ -52,6 +52,7 @@
...
@@ -52,6 +52,7 @@
#include <asm/isa.h>
#include <asm/isa.h>
#endif
#endif
#include <asm/a.out.h>
#include <asm/a.out.h>
#include <asm/ns87303.h>
struct
poll
{
struct
poll
{
int
fd
;
int
fd
;
...
@@ -373,3 +374,6 @@ EXPORT_SYMBOL(kbd_pt_regs);
...
@@ -373,3 +374,6 @@ EXPORT_SYMBOL(kbd_pt_regs);
#ifdef CONFIG_DEBUG_BUGVERBOSE
#ifdef CONFIG_DEBUG_BUGVERBOSE
EXPORT_SYMBOL
(
do_BUG
);
EXPORT_SYMBOL
(
do_BUG
);
#endif
#endif
/* for ns8703 */
EXPORT_SYMBOL
(
ns87303_lock
);
arch/sparc64/solaris/systbl.S
View file @
130ca59d
...
@@ -250,8 +250,8 @@ solaris_sys_table:
...
@@ -250,8 +250,8 @@ solaris_sys_table:
.
word
solaris_fstatvfs64
/*
fstatvfs64
dP
219
*/
.
word
solaris_fstatvfs64
/*
fstatvfs64
dP
219
*/
.
word
solaris_setrlimit64
/*
setrlimit64
dP
220
*/
.
word
solaris_setrlimit64
/*
setrlimit64
dP
220
*/
.
word
solaris_getrlimit64
/*
getrlimit64
dP
221
*/
.
word
solaris_getrlimit64
/*
getrlimit64
dP
221
*/
.
word
CHAIN
(
pread
)
/*
pread64
dpdD
222
*/
.
word
CHAIN
(
pread
64
)
/*
pread64
dpdD
222
*/
.
word
CHAIN
(
pwrite
)
/*
pwrite64
dpdD
223
*/
.
word
CHAIN
(
pwrite
64
)
/*
pwrite64
dpdD
223
*/
.
word
CHAIN
(
creat
)
/*
creat64
so
224
*/
.
word
CHAIN
(
creat
)
/*
creat64
so
224
*/
.
word
solaris_open
/*
open64
soo
225
*/
.
word
solaris_open
/*
open64
soo
225
*/
.
word
solaris_unimplemented
/*
226
*/
.
word
solaris_unimplemented
/*
226
*/
...
...
drivers/net/myri_sbus.c
View file @
130ca59d
...
@@ -546,8 +546,11 @@ static void myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
...
@@ -546,8 +546,11 @@ static void myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct
myri_eth
*
mp
=
(
struct
myri_eth
*
)
dev
->
priv
;
struct
myri_eth
*
mp
=
(
struct
myri_eth
*
)
dev
->
priv
;
unsigned
long
lregs
=
mp
->
lregs
;
unsigned
long
lregs
=
mp
->
lregs
;
struct
myri_channel
*
chan
=
&
mp
->
shmem
->
channel
;
struct
myri_channel
*
chan
=
&
mp
->
shmem
->
channel
;
unsigned
long
flags
;
u32
status
;
u32
status
;
spin_lock_irqsave
(
&
mp
->
irq_lock
,
flags
);
status
=
sbus_readl
(
lregs
+
LANAI_ISTAT
);
status
=
sbus_readl
(
lregs
+
LANAI_ISTAT
);
DIRQ
((
"myri_interrupt: status[%08x] "
,
status
));
DIRQ
((
"myri_interrupt: status[%08x] "
,
status
));
if
(
status
&
ISTAT_HOST
)
{
if
(
status
&
ISTAT_HOST
)
{
...
@@ -569,6 +572,8 @@ static void myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
...
@@ -569,6 +572,8 @@ static void myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
myri_enable_irq
(
lregs
,
mp
->
cregs
);
myri_enable_irq
(
lregs
,
mp
->
cregs
);
}
}
DIRQ
((
"
\n
"
));
DIRQ
((
"
\n
"
));
spin_unlock_irqrestore
(
&
mp
->
irq_lock
,
flags
);
}
}
static
int
myri_open
(
struct
net_device
*
dev
)
static
int
myri_open
(
struct
net_device
*
dev
)
...
@@ -622,7 +627,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -622,7 +627,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
return
1
;
return
1
;
}
}
s
ave_and_cli
(
flags
);
s
pin_lock_irqsave
(
&
mp
->
irq_lock
,
flags
);
DHDR
((
"xmit[skbdata(%p)]
\n
"
,
skb
->
data
));
DHDR
((
"xmit[skbdata(%p)]
\n
"
,
skb
->
data
));
#ifdef DEBUG_HEADER
#ifdef DEBUG_HEADER
...
@@ -669,7 +674,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -669,7 +674,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
DTX
((
"tbusy=0, returning 0
\n
"
));
DTX
((
"tbusy=0, returning 0
\n
"
));
netif_start_queue
(
dev
);
netif_start_queue
(
dev
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
mp
->
irq_lock
,
flags
);
return
0
;
return
0
;
}
}
...
@@ -900,6 +905,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev,
...
@@ -900,6 +905,7 @@ static int __init myri_ether_init(struct net_device *dev, struct sbus_dev *sdev,
printk
(
"%s: MyriCOM MyriNET Ethernet "
,
dev
->
name
);
printk
(
"%s: MyriCOM MyriNET Ethernet "
,
dev
->
name
);
mp
=
(
struct
myri_eth
*
)
dev
->
priv
;
mp
=
(
struct
myri_eth
*
)
dev
->
priv
;
spin_lock_init
(
&
mp
->
irq_lock
);
mp
->
myri_sdev
=
sdev
;
mp
->
myri_sdev
=
sdev
;
/* Clean out skb arrays. */
/* Clean out skb arrays. */
...
...
drivers/net/myri_sbus.h
View file @
130ca59d
...
@@ -269,6 +269,7 @@ struct myri_eth {
...
@@ -269,6 +269,7 @@ struct myri_eth {
/* These are frequently accessed, keep together
/* These are frequently accessed, keep together
* to obtain good cache hit rates.
* to obtain good cache hit rates.
*/
*/
spinlock_t
irq_lock
;
struct
myri_shmem
*
shmem
;
/* Shared data structures. */
struct
myri_shmem
*
shmem
;
/* Shared data structures. */
unsigned
long
cregs
;
/* Control register space. */
unsigned
long
cregs
;
/* Control register space. */
struct
recvq
*
rqack
;
/* Where we ack rx's. */
struct
recvq
*
rqack
;
/* Where we ack rx's. */
...
...
drivers/sbus/char/openprom.c
View file @
130ca59d
...
@@ -147,7 +147,6 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -147,7 +147,6 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
char
buffer
[
OPROMMAXPARAM
+
1
],
*
buf
;
char
buffer
[
OPROMMAXPARAM
+
1
],
*
buf
;
struct
openpromio
*
opp
;
struct
openpromio
*
opp
;
unsigned
long
flags
;
int
bufsize
,
len
,
error
=
0
;
int
bufsize
,
len
,
error
=
0
;
extern
char
saved_command_line
[];
extern
char
saved_command_line
[];
static
int
cnt
;
static
int
cnt
;
...
@@ -163,18 +162,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -163,18 +162,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
switch
(
cmd
)
{
switch
(
cmd
)
{
case
OPROMGETOPT
:
case
OPROMGETOPT
:
case
OPROMGETPROP
:
case
OPROMGETPROP
:
save_and_cli
(
flags
);
len
=
prom_getproplen
(
node
,
opp
->
oprom_array
);
len
=
prom_getproplen
(
node
,
opp
->
oprom_array
);
restore_flags
(
flags
);
if
(
len
<=
0
||
len
>
bufsize
)
{
if
(
len
<=
0
||
len
>
bufsize
)
{
error
=
copyout
((
void
*
)
arg
,
opp
,
sizeof
(
int
));
error
=
copyout
((
void
*
)
arg
,
opp
,
sizeof
(
int
));
break
;
break
;
}
}
save_and_cli
(
flags
);
len
=
prom_getproperty
(
node
,
opp
->
oprom_array
,
buffer
,
bufsize
);
len
=
prom_getproperty
(
node
,
opp
->
oprom_array
,
buffer
,
bufsize
);
restore_flags
(
flags
);
memcpy
(
opp
->
oprom_array
,
buffer
,
len
);
memcpy
(
opp
->
oprom_array
,
buffer
,
len
);
opp
->
oprom_array
[
len
]
=
'\0'
;
opp
->
oprom_array
[
len
]
=
'\0'
;
...
@@ -185,9 +180,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -185,9 +180,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
case
OPROMNXTOPT
:
case
OPROMNXTOPT
:
case
OPROMNXTPROP
:
case
OPROMNXTPROP
:
save_and_cli
(
flags
);
buf
=
prom_nextprop
(
node
,
opp
->
oprom_array
,
buffer
);
buf
=
prom_nextprop
(
node
,
opp
->
oprom_array
,
buffer
);
restore_flags
(
flags
);
len
=
strlen
(
buf
);
len
=
strlen
(
buf
);
if
(
len
==
0
||
len
+
1
>
bufsize
)
{
if
(
len
==
0
||
len
+
1
>
bufsize
)
{
...
@@ -207,10 +200,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -207,10 +200,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
buf
=
opp
->
oprom_array
+
strlen
(
opp
->
oprom_array
)
+
1
;
buf
=
opp
->
oprom_array
+
strlen
(
opp
->
oprom_array
)
+
1
;
len
=
opp
->
oprom_array
+
bufsize
-
buf
;
len
=
opp
->
oprom_array
+
bufsize
-
buf
;
save_and_cli
(
flags
);
error
=
prom_setprop
(
options_node
,
opp
->
oprom_array
,
error
=
prom_setprop
(
options_node
,
opp
->
oprom_array
,
buf
,
len
);
buf
,
len
);
restore_flags
(
flags
);
if
(
error
<
0
)
if
(
error
<
0
)
error
=
-
EINVAL
;
error
=
-
EINVAL
;
...
@@ -226,13 +217,11 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -226,13 +217,11 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
node
=
*
((
int
*
)
opp
->
oprom_array
);
node
=
*
((
int
*
)
opp
->
oprom_array
);
save_and_cli
(
flags
);
switch
(
cmd
)
{
switch
(
cmd
)
{
case
OPROMNEXT
:
node
=
__prom_getsibling
(
node
);
break
;
case
OPROMNEXT
:
node
=
__prom_getsibling
(
node
);
break
;
case
OPROMCHILD
:
node
=
__prom_getchild
(
node
);
break
;
case
OPROMCHILD
:
node
=
__prom_getchild
(
node
);
break
;
case
OPROMSETCUR
:
break
;
case
OPROMSETCUR
:
break
;
}
}
restore_flags
(
flags
);
data
->
current_node
=
node
;
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
...
@@ -264,9 +253,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -264,9 +253,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
break
;
break
;
case
OPROMPATH2NODE
:
case
OPROMPATH2NODE
:
save_and_cli
(
flags
);
node
=
prom_finddevice
(
opp
->
oprom_array
);
node
=
prom_finddevice
(
opp
->
oprom_array
);
restore_flags
(
flags
);
data
->
current_node
=
node
;
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
opp
->
oprom_size
=
sizeof
(
int
);
opp
->
oprom_size
=
sizeof
(
int
);
...
@@ -361,7 +348,6 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -361,7 +348,6 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
{
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
struct
opiocdesc
op
;
struct
opiocdesc
op
;
unsigned
long
flags
;
int
error
,
node
,
len
;
int
error
,
node
,
len
;
char
*
str
,
*
tmp
;
char
*
str
,
*
tmp
;
char
buffer
[
64
];
char
buffer
[
64
];
...
@@ -379,9 +365,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -379,9 +365,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
if
(
error
)
if
(
error
)
return
error
;
return
error
;
save_and_cli
(
flags
);
len
=
prom_getproplen
(
op
.
op_nodeid
,
str
);
len
=
prom_getproplen
(
op
.
op_nodeid
,
str
);
restore_flags
(
flags
);
if
(
len
>
op
.
op_buflen
)
{
if
(
len
>
op
.
op_buflen
)
{
kfree
(
str
);
kfree
(
str
);
...
@@ -405,9 +389,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -405,9 +389,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
save_and_cli
(
flags
);
prom_getproperty
(
op
.
op_nodeid
,
str
,
tmp
,
len
);
prom_getproperty
(
op
.
op_nodeid
,
str
,
tmp
,
len
);
restore_flags
(
flags
);
tmp
[
len
]
=
'\0'
;
tmp
[
len
]
=
'\0'
;
...
@@ -431,9 +413,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -431,9 +413,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
if
(
error
)
if
(
error
)
return
error
;
return
error
;
save_and_cli
(
flags
);
tmp
=
prom_nextprop
(
op
.
op_nodeid
,
str
,
buffer
);
tmp
=
prom_nextprop
(
op
.
op_nodeid
,
str
,
buffer
);
restore_flags
(
flags
);
if
(
tmp
)
{
if
(
tmp
)
{
len
=
strlen
(
tmp
);
len
=
strlen
(
tmp
);
...
@@ -481,9 +461,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -481,9 +461,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
return
error
;
return
error
;
}
}
save_and_cli
(
flags
);
len
=
prom_setprop
(
op
.
op_nodeid
,
str
,
tmp
,
op
.
op_buflen
+
1
);
len
=
prom_setprop
(
op
.
op_nodeid
,
str
,
tmp
,
op
.
op_buflen
+
1
);
restore_flags
(
flags
);
if
(
len
!=
op
.
op_buflen
)
if
(
len
!=
op
.
op_buflen
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -503,12 +481,10 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
...
@@ -503,12 +481,10 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
if
(
copy_from_user
(
&
node
,
(
void
*
)
arg
,
sizeof
(
int
)))
if
(
copy_from_user
(
&
node
,
(
void
*
)
arg
,
sizeof
(
int
)))
return
-
EFAULT
;
return
-
EFAULT
;
save_and_cli
(
flags
);
if
(
cmd
==
OPIOCGETNEXT
)
if
(
cmd
==
OPIOCGETNEXT
)
node
=
__prom_getsibling
(
node
);
node
=
__prom_getsibling
(
node
);
else
else
node
=
__prom_getchild
(
node
);
node
=
__prom_getchild
(
node
);
restore_flags
(
flags
);
if
(
__copy_to_user
((
void
*
)
arg
,
&
node
,
sizeof
(
int
)))
if
(
__copy_to_user
((
void
*
)
arg
,
&
node
,
sizeof
(
int
)))
return
-
EFAULT
;
return
-
EFAULT
;
...
@@ -624,7 +600,6 @@ static struct miscdevice openprom_dev = {
...
@@ -624,7 +600,6 @@ static struct miscdevice openprom_dev = {
static
int
__init
openprom_init
(
void
)
static
int
__init
openprom_init
(
void
)
{
{
unsigned
long
flags
;
int
error
;
int
error
;
error
=
misc_register
(
&
openprom_dev
);
error
=
misc_register
(
&
openprom_dev
);
...
@@ -633,10 +608,8 @@ static int __init openprom_init(void)
...
@@ -633,10 +608,8 @@ static int __init openprom_init(void)
return
error
;
return
error
;
}
}
save_and_cli
(
flags
);
options_node
=
prom_getchild
(
prom_root_node
);
options_node
=
prom_getchild
(
prom_root_node
);
options_node
=
prom_searchsiblings
(
options_node
,
"options"
);
options_node
=
prom_searchsiblings
(
options_node
,
"options"
);
restore_flags
(
flags
);
if
(
options_node
==
0
||
options_node
==
-
1
)
{
if
(
options_node
==
0
||
options_node
==
-
1
)
{
printk
(
KERN_ERR
"openprom: unable to find options node
\n
"
);
printk
(
KERN_ERR
"openprom: unable to find options node
\n
"
);
...
...
drivers/scsi/qlogicpti.c
View file @
130ca59d
...
@@ -318,7 +318,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -318,7 +318,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
risc_code_addr
=
0x1000
;
/* all load addresses are at 0x1000 */
risc_code_addr
=
0x1000
;
/* all load addresses are at 0x1000 */
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_irqsave
(
&
qpti
->
lock
,
flags
);
sbus_writew
(
HCCTRL_PAUSE
,
qpti
->
qregs
+
HCCTRL
);
sbus_writew
(
HCCTRL_PAUSE
,
qpti
->
qregs
+
HCCTRL
);
...
@@ -366,7 +366,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -366,7 +366,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
printk
(
KERN_EMERG
"qlogicpti%d: Cannot execute ISP firmware.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: Cannot execute ISP firmware.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -377,7 +377,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -377,7 +377,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
printk
(
KERN_EMERG
"qlogicpti%d: Cannot set initiator SCSI ID.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: Cannot set initiator SCSI ID.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -392,7 +392,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -392,7 +392,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
printk
(
KERN_EMERG
"qlogicpti%d: Cannot init response queue.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: Cannot init response queue.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -404,7 +404,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -404,7 +404,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
printk
(
KERN_EMERG
"qlogicpti%d: Cannot init request queue.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: Cannot init request queue.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -450,7 +450,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
...
@@ -450,7 +450,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
qlogicpti_mbox_command
(
qpti
,
param
,
0
);
qlogicpti_mbox_command
(
qpti
,
param
,
0
);
qpti
->
send_marker
=
1
;
qpti
->
send_marker
=
1
;
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
0
;
return
0
;
}
}
...
@@ -468,7 +468,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -468,7 +468,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
risc_code_addr
=
0x1000
;
/* all f/w modules load at 0x1000 */
risc_code_addr
=
0x1000
;
/* all f/w modules load at 0x1000 */
risc_code_length
=
sbus_risc_code_length01
;
risc_code_length
=
sbus_risc_code_length01
;
s
ave_flags
(
flags
);
cli
(
);
s
pin_lock_irqsave
(
&
qpti
->
lock
,
flags
);
/* Verify the checksum twice, one before loading it, and once
/* Verify the checksum twice, one before loading it, and once
* afterwards via the mailbox commands.
* afterwards via the mailbox commands.
...
@@ -476,7 +476,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -476,7 +476,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
for
(
i
=
0
;
i
<
risc_code_length
;
i
++
)
for
(
i
=
0
;
i
<
risc_code_length
;
i
++
)
csum
+=
risc_code
[
i
];
csum
+=
risc_code
[
i
];
if
(
csum
)
{
if
(
csum
)
{
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
printk
(
KERN_EMERG
"qlogicpti%d: Aieee, firmware checksum failed!"
,
printk
(
KERN_EMERG
"qlogicpti%d: Aieee, firmware checksum failed!"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
return
1
;
return
1
;
...
@@ -488,7 +488,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -488,7 +488,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
while
(
--
timeout
&&
(
sbus_readw
(
qpti
->
qregs
+
SBUS_CTRL
)
&
SBUS_CTRL_RESET
))
while
(
--
timeout
&&
(
sbus_readw
(
qpti
->
qregs
+
SBUS_CTRL
)
&
SBUS_CTRL_RESET
))
udelay
(
20
);
udelay
(
20
);
if
(
!
timeout
)
{
if
(
!
timeout
)
{
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
printk
(
KERN_EMERG
"qlogicpti%d: Cannot reset the ISP."
,
qpti
->
qpti_id
);
printk
(
KERN_EMERG
"qlogicpti%d: Cannot reset the ISP."
,
qpti
->
qpti_id
);
return
1
;
return
1
;
}
}
...
@@ -528,7 +528,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -528,7 +528,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
if
(
qlogicpti_mbox_command
(
qpti
,
param
,
1
))
{
printk
(
KERN_EMERG
"qlogicpti%d: Cannot stop firmware for reload.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: Cannot stop firmware for reload.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -541,7 +541,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -541,7 +541,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
)
{
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
)
{
printk
(
"qlogicpti%d: Firmware dload failed, I'm bolixed!
\n
"
,
printk
(
"qlogicpti%d: Firmware dload failed, I'm bolixed!
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
}
}
...
@@ -561,7 +561,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -561,7 +561,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
printk
(
KERN_EMERG
"qlogicpti%d: New firmware csum failure!
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: New firmware csum failure!
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -575,7 +575,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -575,7 +575,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
printk
(
KERN_EMERG
"qlogicpti%d: AboutFirmware cmd fails.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: AboutFirmware cmd fails.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -591,7 +591,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -591,7 +591,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
(
param
[
0
]
!=
MBOX_COMMAND_COMPLETE
))
{
printk
(
KERN_EMERG
"qlogicpti%d: could not set clock rate.
\n
"
,
printk
(
KERN_EMERG
"qlogicpti%d: could not set clock rate.
\n
"
,
qpti
->
qpti_id
);
qpti
->
qpti_id
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
1
;
return
1
;
}
}
...
@@ -608,7 +608,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
...
@@ -608,7 +608,7 @@ static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
qlogicpti_mbox_command
(
qpti
,
param
,
1
);
qlogicpti_mbox_command
(
qpti
,
param
,
1
);
}
}
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
0
;
return
0
;
}
}
...
@@ -1166,8 +1166,8 @@ static void ourdone(Scsi_Cmnd *Cmnd)
...
@@ -1166,8 +1166,8 @@ static void ourdone(Scsi_Cmnd *Cmnd)
int
qlogicpti_queuecommand_slow
(
Scsi_Cmnd
*
Cmnd
,
void
(
*
done
)(
Scsi_Cmnd
*
))
int
qlogicpti_queuecommand_slow
(
Scsi_Cmnd
*
Cmnd
,
void
(
*
done
)(
Scsi_Cmnd
*
))
{
{
unsigned
long
flags
;
struct
qlogicpti
*
qpti
=
(
struct
qlogicpti
*
)
Cmnd
->
host
->
hostdata
;
struct
qlogicpti
*
qpti
=
(
struct
qlogicpti
*
)
Cmnd
->
host
->
hostdata
;
unsigned
long
flags
;
/*
/*
* done checking this host adapter?
* done checking this host adapter?
...
@@ -1178,12 +1178,13 @@ int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
...
@@ -1178,12 +1178,13 @@ int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
if
(
qpti
->
sbits
&&
qpti
->
sbits
!=
0xffff
)
{
if
(
qpti
->
sbits
&&
qpti
->
sbits
!=
0xffff
)
{
/* See above about in ourdone this ugliness... */
/* See above about in ourdone this ugliness... */
Cmnd
->
SCp
.
Message
=
((
unsigned
long
)
done
)
&
0xffffffff
;
Cmnd
->
SCp
.
Message
=
((
unsigned
long
)
done
)
&
0xffffffff
;
#ifdef
__sparc_v9__
#ifdef
CONFIG_SPARC64
Cmnd
->
SCp
.
Status
=
((
unsigned
long
)
done
>>
32UL
)
&
0xffffffff
;
Cmnd
->
SCp
.
Status
=
((
unsigned
long
)
done
>>
32UL
)
&
0xffffffff
;
#endif
#endif
return
qlogicpti_queuecommand
(
Cmnd
,
ourdone
);
return
qlogicpti_queuecommand
(
Cmnd
,
ourdone
);
}
}
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
qpti
->
lock
,
flags
);
/*
/*
* We've peeked at all targets for this bus- time
* We've peeked at all targets for this bus- time
...
@@ -1226,7 +1227,8 @@ int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
...
@@ -1226,7 +1227,8 @@ int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
if
(
qpti
==
NULL
)
if
(
qpti
==
NULL
)
Cmnd
->
host
->
hostt
->
queuecommand
=
qlogicpti_queuecommand
;
Cmnd
->
host
->
hostt
->
queuecommand
=
qlogicpti_queuecommand
;
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
qpti
->
lock
,
flags
);
return
qlogicpti_queuecommand
(
Cmnd
,
done
);
return
qlogicpti_queuecommand
(
Cmnd
,
done
);
}
}
...
...
drivers/serial/sunsab.c
View file @
130ca59d
/* $Id: sab82532.c,v 1.66 2002/01/08 16:00:16 davem Exp $
/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*
*
* Rewrote buffer handling to use CIRC(Circular Buffer) macros.
* Rewrote buffer handling to use CIRC(Circular Buffer) macros.
* Maxim Krasnyanskiy <maxk@qualcomm.com>
* Maxim Krasnyanskiy <maxk@qualcomm.com>
...
@@ -10,92 +10,61 @@
...
@@ -10,92 +10,61 @@
* rates to be programmed into the UART. Also eliminated a lot of
* rates to be programmed into the UART. Also eliminated a lot of
* duplicated code in the console setup.
* duplicated code in the console setup.
* Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
* Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
*
* Ported to new 2.5.x UART layer.
* David S. Miller <davem@redhat.com>
*/
*/
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serialP.h>
#include <linux/serial_reg.h>
#include <linux/console.h>
#include <linux/major.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/circ_buf.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/sab82532.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/ebus.h>
#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/oplib.h>
#include <asm/ebus.h>
#include "sunserial.h"
#include <linux/serial_core.h>
static
DECLARE_TASK_QUEUE
(
tq_serial
);
#include "suncore.h"
#include "sunsab.h"
/* This is (one of many) a special gross hack to allow SU and
* SAB serials to co-exist on the same machine. -DaveM
struct
uart_sunsab_port
{
*/
struct
uart_port
port
;
/* Generic UART port */
#undef SERIAL_BH
union
sab82532_async_regs
*
regs
;
/* Chip registers */
#define SERIAL_BH AURORA_BH
unsigned
long
irqflags
;
/* IRQ state flags */
int
xmit_fifo_size
;
/* TX fifo size */
static
struct
tty_driver
serial_driver
,
callout_driver
;
int
recv_fifo_size
;
/* RX fifo size */
static
int
sab82532_refcount
;
int
dsr
;
/* Current DSR state */
unsigned
int
cec_timeout
;
/* Chip poll timeout... */
#undef SERIAL_PARANOIA_CHECK
unsigned
int
tec_timeout
;
/* likewise */
#define SERIAL_DO_RESTART
unsigned
char
interrupt_mask0
;
/* ISR0 masking */
unsigned
char
interrupt_mask1
;
/* ISR1 masking */
/* Set of debugging defines */
unsigned
char
pvr_dtr_bit
;
/* Which PVR bit is DTR */
#undef SERIAL_DEBUG_OPEN
unsigned
char
pvr_dsr_bit
;
/* Which PVR bit is DSR */
#undef SERIAL_DEBUG_FLOW
int
type
;
/* SAB82532 version */
#undef SERIAL_DEBUG_MODEM
int
sab_line
;
/* Internal numbering */
#undef SERIAL_DEBUG_WAIT_UNTIL_SENT
unsigned
int
irq
;
/* Device interrupt */
#undef SERIAL_DEBUG_SEND_BREAK
};
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_FIFO
#define SERIAL_DEBUG_OVERFLOW 1
/* Trace things on serial device, useful for console debugging: */
#undef SERIAL_LOG_DEVICE
#ifdef SERIAL_LOG_DEVICE
static
void
dprint_init
(
int
tty
);
#endif
static
void
change_speed
(
struct
sab82532
*
info
);
static
void
sab82532_wait_until_sent
(
struct
tty_struct
*
tty
,
int
timeout
);
/*
/*
* This assumes you have a 29.4912 MHz clock for your UART.
* This assumes you have a 29.4912 MHz clock for your UART.
*/
*/
#define BASE_BAUD ( 29491200 / 16 )
#define SAB_BASE_BAUD ( 29491200 / 16 )
static
struct
sab82532
*
sab82532_chain
=
0
;
static
struct
tty_struct
*
sab82532_table
[
NR_PORTS
];
static
struct
termios
*
sab82532_termios
[
NR_PORTS
];
static
struct
termios
*
sab82532_termios_locked
[
NR_PORTS
];
#ifdef CONFIG_SERIAL_CONSOLE
extern
int
serial_console
;
static
struct
console
sab82532_console
;
static
int
sab82532_console_init
(
void
);
static
void
batten_down_hatches
(
struct
sab82532
*
info
);
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
static
char
*
sab82532_version
[
16
]
=
{
static
char
*
sab82532_version
[
16
]
=
{
"V1.0"
,
"V2.0"
,
"V3.2"
,
"V(0x03)"
,
"V1.0"
,
"V2.0"
,
"V3.2"
,
"V(0x03)"
,
...
@@ -103,841 +72,601 @@ static char *sab82532_version[16] = {
...
@@ -103,841 +72,601 @@ static char *sab82532_version[16] = {
"V(0x08)"
,
"V(0x09)"
,
"V(0x0a)"
,
"V(0x0b)"
,
"V(0x08)"
,
"V(0x09)"
,
"V(0x0a)"
,
"V(0x0b)"
,
"V(0x0c)"
,
"V(0x0d)"
,
"V(0x0e)"
,
"V(0x0f)"
"V(0x0c)"
,
"V(0x0d)"
,
"V(0x0e)"
,
"V(0x0f)"
};
};
static
char
serial_version
[
16
];
/*
* tmp_buf is used as a temporary buffer by sab82532_write. We need to
* lock it in case the copy_from_user blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static
unsigned
char
*
tmp_buf
=
0
;
static
DECLARE_MUTEX
(
tmp_buf_sem
);
static
inline
int
serial_paranoia_check
(
struct
sab82532
*
info
,
kdev_t
device
,
const
char
*
routine
)
{
#ifdef SERIAL_PARANOIA_CHECK
static
const
char
*
badmagic
=
"Warning: bad magic number for serial struct (%s) in %s
\n
"
;
static
const
char
*
badinfo
=
"Warning: null sab82532 for (%s) in %s
\n
"
;
if
(
!
info
)
{
printk
(
badinfo
,
kdevname
(
device
),
routine
);
return
1
;
}
if
(
info
->
magic
!=
SERIAL_MAGIC
)
{
printk
(
badmagic
,
kdevname
(
device
),
routine
);
return
1
;
}
#endif
return
0
;
}
/*
* This is used to figure out the divisor speeds.
*
* The formula is: Baud = BASE_BAUD / ((N + 1) * (1 << M)),
*
* with 0 <= N < 64 and 0 <= M < 16
*
* 12-Oct-2001 - Replaced table driven approach with code written by
* Theodore Ts'o <tytso@alum.mit.edu> which exactly replicates the
* table. (Modulo bugs for the 307200 and 61440 baud rates, which
* were clearly incorrectly calculated in the original table. This is
* why tables filled with magic constants are evil.)
*/
static
void
calc_ebrg
(
int
baud
,
int
*
n_ret
,
int
*
m_ret
)
{
int
n
,
m
;
if
(
baud
==
0
)
{
*
n_ret
=
0
;
*
m_ret
=
0
;
return
;
}
/*
* We scale numbers by 10 so that we get better accuracy
* without having to use floating point. Here we increment m
* until n is within the valid range.
*/
n
=
(
BASE_BAUD
*
10
)
/
baud
;
m
=
0
;
while
(
n
>=
640
)
{
n
=
n
/
2
;
m
++
;
}
n
=
(
n
+
5
)
/
10
;
/*
* We try very hard to avoid speeds with M == 0 since they may
* not work correctly for XTAL frequences above 10 MHz.
*/
if
((
m
==
0
)
&&
((
n
&
1
)
==
0
))
{
n
=
n
/
2
;
m
++
;
}
*
n_ret
=
n
-
1
;
*
m_ret
=
m
;
}
#define SAB82532_MAX_TEC_TIMEOUT 200000
/* 1 character time (at 50 baud) */
#define SAB82532_MAX_TEC_TIMEOUT 200000
/* 1 character time (at 50 baud) */
#define SAB82532_MAX_CEC_TIMEOUT 50000
/* 2.5 TX CLKs (at 50 baud) */
#define SAB82532_MAX_CEC_TIMEOUT 50000
/* 2.5 TX CLKs (at 50 baud) */
static
__inline__
void
s
ab82532_tec_wait
(
struct
sab82532
*
info
)
static
__inline__
void
s
unsab_tec_wait
(
struct
uart_sunsab_port
*
up
)
{
{
int
timeout
=
info
->
tec_timeout
;
int
timeout
=
up
->
tec_timeout
;
while
((
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_TEC
)
&&
--
timeout
)
while
((
readb
(
&
up
->
regs
->
r
.
star
)
&
SAB82532_STAR_TEC
)
&&
--
timeout
)
udelay
(
1
);
udelay
(
1
);
}
}
static
__inline__
void
s
ab82532_cec_wait
(
struct
sab82532
*
info
)
static
__inline__
void
s
unsab_cec_wait
(
struct
uart_sunsab_port
*
up
)
{
{
int
timeout
=
info
->
cec_timeout
;
int
timeout
=
up
->
cec_timeout
;
while
((
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_CEC
)
&&
--
timeout
)
while
((
readb
(
&
up
->
regs
->
r
.
star
)
&
SAB82532_STAR_CEC
)
&&
--
timeout
)
udelay
(
1
);
udelay
(
1
);
}
}
static
__inline__
void
sab82532_start_tx
(
struct
sab82532
*
info
)
static
void
receive_chars
(
struct
uart_sunsab_port
*
up
,
{
union
sab82532_irq_status
*
stat
,
unsigned
long
flags
;
struct
pt_regs
*
regs
)
int
i
;
save_flags
(
flags
);
cli
();
if
(
info
->
xmit
.
head
==
info
->
xmit
.
tail
)
goto
out
;
if
(
!
test_bit
(
SAB82532_XPR
,
&
info
->
irqflags
))
goto
out
;
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_ALLS
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
clear_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
);
clear_bit
(
SAB82532_XPR
,
&
info
->
irqflags
);
for
(
i
=
0
;
i
<
info
->
xmit_fifo_size
;
i
++
)
{
writeb
(
info
->
xmit
.
buf
[
info
->
xmit
.
tail
],
&
info
->
regs
->
w
.
xfifo
[
i
]);
info
->
xmit
.
tail
=
(
info
->
xmit
.
tail
+
1
)
&
(
SERIAL_XMIT_SIZE
-
1
);
info
->
icount
.
tx
++
;
if
(
info
->
xmit
.
head
==
info
->
xmit
.
tail
)
break
;
}
/* Issue a Transmit Frame command. */
sab82532_cec_wait
(
info
);
writeb
(
SAB82532_CMDR_XF
,
&
info
->
regs
->
w
.
cmdr
);
out:
restore_flags
(
flags
);
}
/*
* ------------------------------------------------------------
* sab82532_stop() and sab82532_start()
*
* This routines are called before setting or resetting tty->stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
static
void
sab82532_stop
(
struct
tty_struct
*
tty
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_stop"
))
return
;
save_flags
(
flags
);
cli
();
info
->
interrupt_mask1
|=
SAB82532_IMR1_XPR
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
restore_flags
(
flags
);
}
static
void
sab82532_start
(
struct
tty_struct
*
tty
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_start"
))
return
;
save_flags
(
flags
);
cli
();
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_XPR
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
sab82532_start_tx
(
info
);
restore_flags
(
flags
);
}
/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
* subroutines are declared as inline and are folded into
* sab82532_interrupt(). They were separated out for readability's sake.
*
* Note: sab82532_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* sab82532_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
*
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
*
* - Ted Ts'o (tytso@mit.edu), 7-Mar-93
* -----------------------------------------------------------------------
*/
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
static
void
sab82532_sched_event
(
struct
sab82532
*
info
,
int
event
)
{
info
->
event
|=
1
<<
event
;
queue_task
(
&
info
->
tqueue
,
&
tq_serial
);
mark_bh
(
SERIAL_BH
);
}
static
void
receive_chars
(
struct
sab82532
*
info
,
union
sab82532_irq_status
*
stat
)
{
{
struct
tty_struct
*
tty
=
info
->
tty
;
struct
tty_struct
*
tty
=
up
->
port
.
info
->
tty
;
unsigned
char
buf
[
32
];
unsigned
char
buf
[
32
];
unsigned
char
status
;
int
saw_console_brk
=
0
;
int
free_fifo
=
0
;
int
free_fifo
=
0
;
int
i
,
count
=
0
;
int
count
=
0
;
int
i
;
/* Read number of BYTES (Character + Status) available. */
/* Read number of BYTES (Character + Status) available. */
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RPF
)
{
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RPF
)
{
count
=
info
->
recv_fifo_size
;
count
=
up
->
recv_fifo_size
;
free_fifo
++
;
free_fifo
++
;
}
}
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_TCD
)
{
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_TCD
)
{
count
=
readb
(
&
info
->
regs
->
r
.
rbcl
)
&
(
info
->
recv_fifo_size
-
1
);
count
=
readb
(
&
up
->
regs
->
r
.
rbcl
)
&
(
up
->
recv_fifo_size
-
1
);
free_fifo
++
;
free_fifo
++
;
}
}
/* Issue a FIFO read command in case we where idle. */
/* Issue a FIFO read command in case we where idle. */
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_TIME
)
{
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_TIME
)
{
s
ab82532_cec_wait
(
info
);
s
unsab_cec_wait
(
up
);
writeb
(
SAB82532_CMDR_RFRD
,
&
info
->
regs
->
w
.
cmdr
);
writeb
(
SAB82532_CMDR_RFRD
,
&
up
->
regs
->
w
.
cmdr
);
return
;
return
;
}
}
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RFO
)
{
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RFO
)
#ifdef SERIAL_DEBUG_OVERFLOW
printk
(
"sab82532: receive_chars: RFO"
);
#endif
free_fifo
++
;
free_fifo
++
;
}
/* Read the FIFO. */
/* Read the FIFO. */
for
(
i
=
0
;
i
<
count
;
i
++
)
for
(
i
=
0
;
i
<
count
;
i
++
)
buf
[
i
]
=
readb
(
&
info
->
regs
->
r
.
rfifo
[
i
]);
buf
[
i
]
=
readb
(
&
up
->
regs
->
r
.
rfifo
[
i
]);
/* Issue Receive Message Complete command. */
/* Issue Receive Message Complete command. */
if
(
free_fifo
)
{
if
(
free_fifo
)
{
s
ab82532_cec_wait
(
info
);
s
unsab_cec_wait
(
up
);
writeb
(
SAB82532_CMDR_RMC
,
&
info
->
regs
->
w
.
cmdr
);
writeb
(
SAB82532_CMDR_RMC
,
&
up
->
regs
->
w
.
cmdr
);
}
}
if
(
!
tty
)
for
(
i
=
0
;
i
<
count
;
i
++
)
{
return
;
unsigned
char
ch
=
buf
[
i
]
;
for
(
i
=
0
;
i
<
count
;
)
{
if
(
unlikely
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
))
{
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
tty
->
flip
.
tqueue
.
routine
((
void
*
)
tty
);
#ifdef SERIAL_DEBUG_OVERFLOW
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
printk
(
"sab82532: receive_chars: tty overrun
\n
"
);
return
;
// if TTY_DONT_FLIP is set
#endif
info
->
icount
.
buf_overrun
++
;
break
;
}
}
tty
->
flip
.
count
++
;
*
tty
->
flip
.
char_buf_ptr
=
ch
;
*
tty
->
flip
.
char_buf_ptr
++
=
buf
[
i
++
];
*
tty
->
flip
.
flag_buf_ptr
=
TTY_NORMAL
;
status
=
buf
[
i
++
];
up
->
port
.
icount
.
rx
++
;
info
->
icount
.
rx
++
;
#ifdef SERIAL_DEBUG_INTR
if
(
unlikely
(
stat
->
sreg
.
isr0
&
(
SAB82532_ISR0_PERR
|
printk
(
"DR%02x:%02x..."
,
(
unsigned
char
)
*
(
tty
->
flip
.
char_buf_ptr
-
1
),
status
);
SAB82532_ISR0_FERR
|
#endif
SAB82532_ISR0_RFO
))
||
unlikely
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_BRK
))
{
/*
* For statistics only
*/
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_BRK
)
{
stat
->
sreg
.
isr0
&=
~
(
SAB82532_ISR0_PERR
|
SAB82532_ISR0_FERR
);
up
->
port
.
icount
.
brk
++
;
if
(
up
->
port
.
line
==
up
->
port
.
cons
->
index
)
saw_console_brk
=
1
;
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
* or read_status_mask.
*/
if
(
uart_handle_break
(
&
up
->
port
))
continue
;
}
else
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_PERR
)
up
->
port
.
icount
.
parity
++
;
else
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_FERR
)
up
->
port
.
icount
.
frame
++
;
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RFO
)
up
->
port
.
icount
.
overrun
++
;
if
(
status
&
SAB82532_RSTAT_PE
)
{
/*
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_PARITY
;
* Mask off conditions which should be ingored.
info
->
icount
.
parity
++
;
*/
}
else
if
(
status
&
SAB82532_RSTAT_FE
)
{
stat
->
sreg
.
isr0
&=
(
up
->
port
.
read_status_mask
&
0xff
);
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_FRAME
;
stat
->
sreg
.
isr1
&=
((
up
->
port
.
read_status_mask
>>
8
)
&
0xff
);
info
->
icount
.
frame
++
;
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_BRK
)
{
*
tty
->
flip
.
flag_buf_ptr
=
TTY_BREAK
;
}
else
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_PERR
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_PARITY
;
else
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_FERR
)
*
tty
->
flip
.
flag_buf_ptr
=
TTY_FRAME
;
}
}
else
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_NORMAL
;
if
(
uart_handle_sysrq_char
(
&
up
->
port
,
ch
,
regs
))
continue
;
if
((
stat
->
sreg
.
isr0
&
(
up
->
port
.
ignore_status_mask
&
0xff
))
==
0
&&
(
stat
->
sreg
.
isr1
&
((
up
->
port
.
ignore_status_mask
>>
8
)
&
0xff
))
==
0
){
tty
->
flip
.
flag_buf_ptr
++
;
tty
->
flip
.
char_buf_ptr
++
;
tty
->
flip
.
count
++
;
}
}
if
((
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RFO
)
&&
tty
->
flip
.
count
<
TTY_FLIPBUF_SIZE
)
{
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
*
tty
->
flip
.
flag_buf_ptr
=
TTY_OVERRUN
;
tty
->
flip
.
flag_buf_ptr
++
;
tty
->
flip
.
char_buf_ptr
++
;
tty
->
flip
.
count
++
;
}
}
tty_flip_buffer_push
(
tty
);
queue_task
(
&
tty
->
flip
.
tqueue
,
&
tq_timer
);
if
(
saw_console_brk
)
sun_do_break
();
}
}
static
void
transmit_chars
(
struct
sab82532
*
info
,
static
void
sunsab_stop_tx
(
struct
uart_port
*
,
unsigned
int
);
static
void
transmit_chars
(
struct
uart_sunsab_port
*
up
,
union
sab82532_irq_status
*
stat
)
union
sab82532_irq_status
*
stat
)
{
{
struct
circ_buf
*
xmit
=
&
up
->
port
.
info
->
xmit
;
int
i
;
int
i
;
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_ALLS
)
{
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_ALLS
)
{
info
->
interrupt_mask1
|=
SAB82532_IMR1_ALLS
;
up
->
interrupt_mask1
|=
SAB82532_IMR1_ALLS
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
set_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
);
set_bit
(
SAB82532_ALLS
,
&
up
->
irqflags
);
}
}
if
(
!
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_XPR
))
if
(
!
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_XPR
))
return
;
return
;
if
(
!
(
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_XFW
))
{
if
(
!
(
readb
(
&
up
->
regs
->
r
.
star
)
&
SAB82532_STAR_XFW
))
#ifdef SERIAL_DEBUG_FIFO
printk
(
"%s: XPR, but no XFW (?)
\n
"
,
__FUNCTION__
);
#endif
return
;
return
;
}
set_bit
(
SAB82532_XPR
,
&
info
->
irqflags
);
if
(
!
info
->
tty
)
{
set_bit
(
SAB82532_XPR
,
&
up
->
irqflags
);
info
->
interrupt_mask1
|=
SAB82532_IMR1_XPR
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
return
;
}
if
((
info
->
xmit
.
head
==
info
->
xmit
.
tail
)
||
if
(
uart_circ_empty
(
xmit
)
||
uart_tx_stopped
(
&
up
->
port
))
{
info
->
tty
->
stopped
||
info
->
tty
->
hw_stopped
)
{
up
->
interrupt_mask1
|=
SAB82532_IMR1_XPR
;
info
->
interrupt_mask1
|=
SAB82532_IMR1_XPR
;
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
return
;
return
;
}
}
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_ALLS
);
up
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_ALLS
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
clear_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
);
clear_bit
(
SAB82532_ALLS
,
&
up
->
irqflags
);
/* Stuff 32 bytes into Transmit FIFO. */
/* Stuff 32 bytes into Transmit FIFO. */
clear_bit
(
SAB82532_XPR
,
&
info
->
irqflags
);
clear_bit
(
SAB82532_XPR
,
&
up
->
irqflags
);
for
(
i
=
0
;
i
<
info
->
xmit_fifo_size
;
i
++
)
{
for
(
i
=
0
;
i
<
up
->
xmit_fifo_size
;
i
++
)
{
writeb
(
info
->
xmit
.
buf
[
info
->
xmit
.
tail
],
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
info
->
regs
->
w
.
xfifo
[
i
]);
&
up
->
regs
->
w
.
xfifo
[
i
]);
info
->
xmit
.
tail
=
(
info
->
xmit
.
tail
+
1
)
&
(
SERIAL_XMIT_SIZE
-
1
);
xmit
->
tail
=
(
xmit
->
tail
+
1
)
&
(
UART_XMIT_SIZE
-
1
);
info
->
icount
.
tx
++
;
up
->
port
.
icount
.
tx
++
;
if
(
info
->
xmit
.
head
==
info
->
xmit
.
tail
)
if
(
uart_circ_empty
(
xmit
)
)
break
;
break
;
}
}
/* Issue a Transmit Frame command. */
/* Issue a Transmit Frame command. */
s
ab82532_cec_wait
(
info
);
s
unsab_cec_wait
(
up
);
writeb
(
SAB82532_CMDR_XF
,
&
info
->
regs
->
w
.
cmdr
);
writeb
(
SAB82532_CMDR_XF
,
&
up
->
regs
->
w
.
cmdr
);
if
(
CIRC_CNT
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
)
<
WAKEUP_CHARS
)
if
(
uart_circ_chars_pending
(
xmit
)
<
WAKEUP_CHARS
)
sab82532_sched_event
(
info
,
RS_EVEN
T_WRITE_WAKEUP
);
uart_event
(
&
up
->
port
,
EV
T_WRITE_WAKEUP
);
#ifdef SERIAL_DEBUG_INTR
if
(
uart_circ_empty
(
xmit
))
printk
(
"THRE..."
);
sunsab_stop_tx
(
&
up
->
port
,
0
);
#endif
}
}
static
void
check_status
(
struct
sab82532
*
info
,
static
void
check_status
(
struct
uart_sunsab_port
*
up
,
union
sab82532_irq_status
*
stat
)
union
sab82532_irq_status
*
stat
)
{
{
struct
tty_struct
*
tty
=
info
->
tty
;
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
int
modem_change
=
0
;
uart_handle_dcd_change
(
&
up
->
port
,
!
(
readb
(
&
up
->
regs
->
r
.
vstr
)
&
SAB82532_VSTR_CD
));
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_BRK
)
{
#ifdef CONFIG_SERIAL_CONSOLE
if
(
info
->
is_console
)
{
sun_do_break
(
info
);
return
;
}
#endif
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
info
->
icount
.
buf_overrun
++
;
goto
check_modem
;
}
tty
->
flip
.
count
++
;
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_PARITY
;
*
tty
->
flip
.
char_buf_ptr
++
=
0
;
info
->
icount
.
brk
++
;
}
if
(
!
tty
)
return
;
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_RFO
)
{
if
(
tty
->
flip
.
count
>=
TTY_FLIPBUF_SIZE
)
{
info
->
icount
.
buf_overrun
++
;
goto
check_modem
;
}
tty
->
flip
.
count
++
;
*
tty
->
flip
.
flag_buf_ptr
++
=
TTY_PARITY
;
*
tty
->
flip
.
char_buf_ptr
++
=
0
;
info
->
icount
.
overrun
++
;
}
check_modem:
if
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
{
info
->
dcd
=
(
readb
(
&
info
->
regs
->
r
.
vstr
)
&
SAB82532_VSTR_CD
)
?
0
:
1
;
info
->
icount
.
dcd
++
;
modem_change
++
;
#ifdef SERIAL_DEBUG_MODEM
printk
(
"DCD change: %d
\n
"
,
info
->
icount
.
dcd
);
#endif
}
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_CSC
)
{
info
->
cts
=
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_CTS
;
info
->
icount
.
cts
++
;
modem_change
++
;
#ifdef SERIAL_DEBUG_MODEM
printk
(
"CTS change: %d, CTS %s
\n
"
,
info
->
icount
.
cts
,
info
->
cts
?
"on"
:
"off"
);
#endif
}
if
((
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dsr_bit
)
^
info
->
dsr
)
{
info
->
dsr
=
(
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dsr_bit
)
?
0
:
1
;
info
->
icount
.
dsr
++
;
modem_change
++
;
#ifdef SERIAL_DEBUG_MODEM
printk
(
"DSR change: %d
\n
"
,
info
->
icount
.
dsr
);
#endif
}
if
(
modem_change
)
wake_up_interruptible
(
&
info
->
delta_msr_wait
);
if
((
info
->
flags
&
ASYNC_CHECK_CD
)
&&
(
stat
->
sreg
.
isr0
&
SAB82532_ISR0_CDSC
))
{
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk
(
"ttys%d CD now %s..."
,
info
->
line
,
(
info
->
dcd
)
?
"on"
:
"off"
);
#endif
if
(
info
->
dcd
)
wake_up_interruptible
(
&
info
->
open_wait
);
else
if
(
!
((
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
(
info
->
flags
&
ASYNC_CALLOUT_NOHUP
)))
{
#ifdef SERIAL_DEBUG_OPEN
printk
(
"scheduling hangup..."
);
#endif
MOD_INC_USE_COUNT
;
if
(
schedule_task
(
&
info
->
tqueue_hangup
)
==
0
)
MOD_DEC_USE_COUNT
;
}
}
if
(
info
->
flags
&
ASYNC_CTS_FLOW
)
{
if
(
stat
->
sreg
.
isr1
&
SAB82532_ISR1_CSC
)
if
(
info
->
tty
->
hw_stopped
)
{
uart_handle_cts_change
(
&
up
->
port
,
if
(
info
->
cts
)
{
(
readb
(
&
up
->
regs
->
r
.
star
)
&
SAB82532_STAR_CTS
));
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
if
((
readb
(
&
up
->
regs
->
r
.
pvr
)
&
up
->
pvr_dsr_bit
)
^
up
->
dsr
)
{
printk
(
"CTS tx start..."
);
up
->
dsr
=
(
readb
(
&
up
->
regs
->
r
.
pvr
)
&
up
->
pvr_dsr_bit
)
?
0
:
1
;
#endif
up
->
port
.
icount
.
dsr
++
;
info
->
tty
->
hw_stopped
=
0
;
sab82532_sched_event
(
info
,
RS_EVENT_WRITE_WAKEUP
);
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_XPR
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
sab82532_start_tx
(
info
);
}
}
}
else
{
if
(
!
(
info
->
cts
))
{
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
wake_up_interruptible
(
&
up
->
port
.
info
->
delta_msr_wait
);
printk
(
"CTS tx stop..."
);
#endif
info
->
tty
->
hw_stopped
=
1
;
}
}
}
}
}
/*
static
void
sunsab_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
* This is the serial driver's generic interrupt routine
*/
static
void
sab82532_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
{
struct
sab82532
*
info
=
dev_id
;
struct
uart_sunsab_port
*
up
=
dev_id
;
union
sab82532_irq_status
status
;
union
sab82532_irq_status
status
;
unsigned
long
flags
;
#ifdef SERIAL_DEBUG_INTR
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
printk
(
"sab82532_interrupt(%d)..."
,
irq
);
#endif
status
.
stat
=
0
;
status
.
stat
=
0
;
if
(
readb
(
&
info
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISA0
)
if
(
readb
(
&
up
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISA0
)
status
.
sreg
.
isr0
=
readb
(
&
info
->
regs
->
r
.
isr0
);
status
.
sreg
.
isr0
=
readb
(
&
up
->
regs
->
r
.
isr0
);
if
(
readb
(
&
info
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISA1
)
if
(
readb
(
&
up
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISA1
)
status
.
sreg
.
isr1
=
readb
(
&
info
->
regs
->
r
.
isr1
);
status
.
sreg
.
isr1
=
readb
(
&
up
->
regs
->
r
.
isr1
);
#ifdef SERIAL_DEBUG_INTR
printk
(
"%d<%02x.%02x>"
,
info
->
line
,
status
.
sreg
.
isr0
,
status
.
sreg
.
isr1
);
#endif
if
(
!
status
.
stat
)
goto
next
;
if
(
status
.
stat
)
{
if
(
status
.
sreg
.
isr0
&
(
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TIME
|
if
(
status
.
sreg
.
isr0
&
(
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TIME
|
SAB82532_ISR0_RFO
|
SAB82532_ISR0_RPF
))
SAB82532_ISR0_RFO
|
SAB82532_ISR0_RPF
))
receive_chars
(
info
,
&
statu
s
);
receive_chars
(
up
,
&
status
,
reg
s
);
if
((
status
.
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
||
if
((
status
.
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
||
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_BRK
|
SAB82532_ISR1_CSC
)
))
(
status
.
sreg
.
isr1
&
SAB82532_ISR1_CSC
))
check_status
(
info
,
&
status
);
check_status
(
up
,
&
status
);
if
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_ALLS
|
SAB82532_ISR1_XPR
))
if
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_ALLS
|
SAB82532_ISR1_XPR
))
transmit_chars
(
info
,
&
status
);
transmit_chars
(
up
,
&
status
);
}
next:
spin_unlock
(
&
up
->
port
.
lock
);
info
=
info
->
next
;
status
.
stat
=
0
;
up
++
;
if
(
readb
(
&
info
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISB0
)
status
.
sreg
.
isr0
=
readb
(
&
info
->
regs
->
r
.
isr0
);
spin_lock
(
&
up
->
port
.
lock
);
if
(
readb
(
&
info
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISB1
)
status
.
sreg
.
isr1
=
readb
(
&
info
->
regs
->
r
.
isr1
);
#ifdef SERIAL_DEBUG_INTR
printk
(
"%d<%02x.%02x>"
,
info
->
line
,
status
.
sreg
.
isr0
,
status
.
sreg
.
isr1
);
#endif
if
(
!
status
.
stat
)
status
.
stat
=
0
;
goto
done
;
if
(
readb
(
&
up
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISB0
)
status
.
sreg
.
isr0
=
readb
(
&
up
->
regs
->
r
.
isr0
);
if
(
readb
(
&
up
->
regs
->
r
.
gis
)
&
SAB82532_GIS_ISB1
)
status
.
sreg
.
isr1
=
readb
(
&
up
->
regs
->
r
.
isr1
);
if
(
status
.
stat
)
{
if
(
status
.
sreg
.
isr0
&
(
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TIME
|
if
(
status
.
sreg
.
isr0
&
(
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TIME
|
SAB82532_ISR0_RFO
|
SAB82532_ISR0_RPF
))
SAB82532_ISR0_RFO
|
SAB82532_ISR0_RPF
))
receive_chars
(
info
,
&
statu
s
);
receive_chars
(
up
,
&
status
,
reg
s
);
if
((
status
.
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
||
if
((
status
.
sreg
.
isr0
&
SAB82532_ISR0_CDSC
)
||
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_BRK
|
SAB82532_ISR1_CSC
)))
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_BRK
|
SAB82532_ISR1_CSC
)))
check_status
(
info
,
&
status
);
check_status
(
up
,
&
status
);
if
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_ALLS
|
SAB82532_ISR1_XPR
))
if
(
status
.
sreg
.
isr1
&
(
SAB82532_ISR1_ALLS
|
SAB82532_ISR1_XPR
))
transmit_chars
(
info
,
&
status
);
transmit_chars
(
up
,
&
status
);
}
done:
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
;
#ifdef SERIAL_DEBUG_INTR
printk
(
"end.
\n
"
);
#endif
}
}
/*
/*
port->lock is not held. */
* -------------------------------------------------------------------
static
unsigned
int
sunsab_tx_empty
(
struct
uart_port
*
port
)
* Here ends the serial interrupt routines.
{
* -------------------------------------------------------------------
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
*/
int
ret
;
/*
/* Do not need a lock for a state test like this. */
* This routine is used to handle the "bottom half" processing for the
if
(
test_bit
(
SAB82532_ALLS
,
&
up
->
irqflags
))
* serial driver, known also the "software interrupt" processing.
ret
=
TIOCSER_TEMT
;
* This processing is done at the kernel interrupt level, after the
else
* sab82532_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
ret
=
0
;
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
return
ret
;
* them using sab82532_sched_event(), and they get done here.
}
*/
static
void
do_serial_bh
(
void
)
/* port->lock held by caller. */
static
void
sunsab_set_mctrl
(
struct
uart_port
*
port
,
unsigned
int
mctrl
)
{
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
if
(
mctrl
&
TIOCM_RTS
)
{
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
&
~
SAB82532_MODE_FRTS
,
&
up
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
up
->
regs
->
rw
.
mode
);
}
else
{
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
up
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
up
->
regs
->
rw
.
mode
);
}
if
(
mctrl
&
TIOCM_DTR
)
{
writeb
(
readb
(
&
up
->
regs
->
rw
.
pvr
)
&
~
(
up
->
pvr_dtr_bit
),
&
up
->
regs
->
rw
.
pvr
);
}
else
{
writeb
(
readb
(
&
up
->
regs
->
rw
.
pvr
)
|
up
->
pvr_dtr_bit
,
&
up
->
regs
->
rw
.
pvr
);
}
}
/* port->lock is not held. */
static
unsigned
int
sunsab_get_mctrl
(
struct
uart_port
*
port
)
{
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
unsigned
long
flags
;
unsigned
char
val
;
unsigned
int
result
;
result
=
0
;
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
val
=
readb
(
&
up
->
regs
->
r
.
pvr
);
result
|=
(
val
&
up
->
pvr_dsr_bit
)
?
0
:
TIOCM_DSR
;
val
=
readb
(
&
up
->
regs
->
r
.
vstr
);
result
|=
(
val
&
SAB82532_VSTR_CD
)
?
0
:
TIOCM_CAR
;
val
=
readb
(
&
up
->
regs
->
r
.
star
);
result
|=
(
val
&
SAB82532_STAR_CTS
)
?
TIOCM_CTS
:
0
;
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
return
result
;
}
/* port->lock held by caller. */
static
void
sunsab_stop_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_stop
)
{
{
run_task_queue
(
&
tq_serial
);
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
up
->
interrupt_mask1
|=
SAB82532_IMR1_XPR
;
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
}
}
static
void
do_softint
(
void
*
private_
)
/* port->lock held by caller. */
static
void
sunsab_start_tx
(
struct
uart_port
*
port
,
unsigned
int
tty_start
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
private_
;
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
struct
tty_struct
*
tty
;
struct
circ_buf
*
xmit
=
&
up
->
port
.
info
->
xmit
;
int
i
;
tty
=
info
->
tty
;
if
(
!
test_bit
(
SAB82532_XPR
,
&
up
->
irqflags
))
if
(
!
tty
)
return
;
return
;
if
(
test_and_clear_bit
(
RS_EVENT_WRITE_WAKEUP
,
&
info
->
event
))
{
up
->
interrupt_mask1
&=
~
SAB82532_IMR1_XPR
;
if
((
tty
->
flags
&
(
1
<<
TTY_DO_WRITE_WAKEUP
))
&&
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
tty
->
ldisc
.
write_wakeup
)
clear_bit
(
SAB82532_ALLS
,
&
up
->
irqflags
);
(
tty
->
ldisc
.
write_wakeup
)(
tty
);
clear_bit
(
SAB82532_XPR
,
&
up
->
irqflags
);
wake_up_interruptible
(
&
tty
->
write_wait
);
for
(
i
=
0
;
i
<
up
->
xmit_fifo_size
;
i
++
)
{
writeb
(
xmit
->
buf
[
xmit
->
tail
],
&
up
->
regs
->
w
.
xfifo
[
i
]);
xmit
->
tail
=
(
xmit
->
tail
+
1
)
&
(
UART_XMIT_SIZE
-
1
);
up
->
port
.
icount
.
tx
++
;
if
(
uart_circ_empty
(
xmit
))
break
;
}
}
/* Issue a Transmit Frame command. */
sunsab_cec_wait
(
up
);
writeb
(
SAB82532_CMDR_XF
,
&
up
->
regs
->
w
.
cmdr
);
}
}
/*
/* port->lock is not held. */
* This routine is called from the scheduler tqueue when the interrupt
static
void
sunsab_send_xchar
(
struct
uart_port
*
port
,
char
ch
)
* routine has signalled that a hangup has occurred. The path of
* hangup processing is:
*
* serial interrupt routine -> (scheduler tqueue) ->
* do_serial_hangup() -> tty->hangup() -> sab82532_hangup()
*
*/
static
void
do_serial_hangup
(
void
*
private_
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
private_
;
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
struct
tty_struct
*
tty
;
unsigned
long
flags
;
tty
=
info
->
tty
;
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
if
(
tty
)
tty_hangup
(
tty
);
sunsab_tec_wait
(
up
);
MOD_DEC_USE_COUNT
;
writeb
(
ch
,
&
up
->
regs
->
w
.
tic
);
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
}
}
static
void
/* port->lock held by caller. */
s
ab82532_init_line
(
struct
sab82532
*
info
)
s
tatic
void
sunsab_stop_rx
(
struct
uart_port
*
port
)
{
{
unsigned
char
stat
,
tmp
;
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
/*
up
->
interrupt_mask0
|=
SAB82532_ISR0_TCD
;
* Wait for any commands or immediate characters
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr0
);
*/
}
sab82532_cec_wait
(
info
);
sab82532_tec_wait
(
info
);
/*
/* port->lock held by caller. */
* Clear the FIFO buffers.
static
void
sunsab_enable_ms
(
struct
uart_port
*
port
)
*/
{
writeb
(
SAB82532_CMDR_RRES
,
&
info
->
regs
->
w
.
cmdr
);
/* For now we always receive these interrupts. */
sab82532_cec_wait
(
info
);
}
writeb
(
SAB82532_CMDR_XRES
,
&
info
->
regs
->
w
.
cmdr
);
/*
/* port->lock is not held. */
* Clear the interrupt registers.
static
void
sunsab_break_ctl
(
struct
uart_port
*
port
,
int
break_state
)
*/
{
stat
=
readb
(
&
info
->
regs
->
r
.
isr0
);
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
stat
=
readb
(
&
info
->
regs
->
r
.
isr1
);
unsigned
long
flags
;
unsigned
char
val
;
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
val
=
readb
(
&
up
->
regs
->
rw
.
dafo
);
if
(
break_state
)
val
|=
SAB82532_DAFO_XBRK
;
else
val
&=
~
SAB82532_DAFO_XBRK
;
writeb
(
val
,
&
up
->
regs
->
rw
.
dafo
);
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
}
/* port->lock is not held. */
static
int
sunsab_startup
(
struct
uart_port
*
port
)
{
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
unsigned
long
flags
;
unsigned
char
tmp
;
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
/*
* Wait for any commands or immediate characters
*/
sunsab_cec_wait
(
up
);
sunsab_tec_wait
(
up
);
/*
* Clear the FIFO buffers.
*/
writeb
(
SAB82532_CMDR_RRES
,
&
up
->
regs
->
w
.
cmdr
);
sunsab_cec_wait
(
up
);
writeb
(
SAB82532_CMDR_XRES
,
&
up
->
regs
->
w
.
cmdr
);
/*
* Clear the interrupt registers.
*/
(
void
)
readb
(
&
up
->
regs
->
r
.
isr0
);
(
void
)
readb
(
&
up
->
regs
->
r
.
isr1
);
/*
/*
* Now, initialize the UART
* Now, initialize the UART
*/
*/
writeb
(
0
,
&
info
->
regs
->
w
.
ccr0
);
/* power-down */
writeb
(
0
,
&
up
->
regs
->
w
.
ccr0
);
/* power-down */
writeb
(
SAB82532_CCR0_MCE
|
SAB82532_CCR0_SC_NRZ
|
writeb
(
SAB82532_CCR0_MCE
|
SAB82532_CCR0_SC_NRZ
|
SAB82532_CCR0_SM_ASYNC
,
&
info
->
regs
->
w
.
ccr0
);
SAB82532_CCR0_SM_ASYNC
,
&
up
->
regs
->
w
.
ccr0
);
writeb
(
SAB82532_CCR1_ODS
|
SAB82532_CCR1_BCR
|
7
,
&
info
->
regs
->
w
.
ccr1
);
writeb
(
SAB82532_CCR1_ODS
|
SAB82532_CCR1_BCR
|
7
,
&
up
->
regs
->
w
.
ccr1
);
writeb
(
SAB82532_CCR2_BDF
|
SAB82532_CCR2_SSEL
|
writeb
(
SAB82532_CCR2_BDF
|
SAB82532_CCR2_SSEL
|
SAB82532_CCR2_TOE
,
&
info
->
regs
->
w
.
ccr2
);
SAB82532_CCR2_TOE
,
&
up
->
regs
->
w
.
ccr2
);
writeb
(
0
,
&
info
->
regs
->
w
.
ccr3
);
writeb
(
0
,
&
up
->
regs
->
w
.
ccr3
);
writeb
(
SAB82532_CCR4_MCK4
|
SAB82532_CCR4_EBRG
,
&
info
->
regs
->
w
.
ccr4
);
writeb
(
SAB82532_CCR4_MCK4
|
SAB82532_CCR4_EBRG
,
&
up
->
regs
->
w
.
ccr4
);
writeb
(
SAB82532_MODE_RTS
|
SAB82532_MODE_FCTS
|
writeb
(
SAB82532_MODE_RTS
|
SAB82532_MODE_FCTS
|
SAB82532_MODE_RAC
,
&
info
->
regs
->
w
.
mode
);
SAB82532_MODE_RAC
,
&
up
->
regs
->
w
.
mode
);
writeb
(
SAB82532_RFC_DPS
|
SAB82532_RFC_RFDF
,
&
info
->
regs
->
w
.
rfc
);
writeb
(
SAB82532_RFC_DPS
|
SAB82532_RFC_RFDF
,
&
up
->
regs
->
w
.
rfc
);
switch
(
info
->
recv_fifo_size
)
{
switch
(
up
->
recv_fifo_size
)
{
case
1
:
case
1
:
tmp
=
readb
(
&
info
->
regs
->
w
.
rfc
);
tmp
=
readb
(
&
up
->
regs
->
w
.
rfc
);
tmp
|=
SAB82532_RFC_RFTH_1
;
tmp
|=
SAB82532_RFC_RFTH_1
;
writeb
(
tmp
,
&
info
->
regs
->
w
.
rfc
);
writeb
(
tmp
,
&
up
->
regs
->
w
.
rfc
);
break
;
break
;
case
4
:
case
4
:
tmp
=
readb
(
&
info
->
regs
->
w
.
rfc
);
tmp
=
readb
(
&
up
->
regs
->
w
.
rfc
);
tmp
|=
SAB82532_RFC_RFTH_4
;
tmp
|=
SAB82532_RFC_RFTH_4
;
writeb
(
tmp
,
&
info
->
regs
->
w
.
rfc
);
writeb
(
tmp
,
&
up
->
regs
->
w
.
rfc
);
break
;
break
;
case
16
:
case
16
:
tmp
=
readb
(
&
info
->
regs
->
w
.
rfc
);
tmp
=
readb
(
&
up
->
regs
->
w
.
rfc
);
tmp
|=
SAB82532_RFC_RFTH_16
;
tmp
|=
SAB82532_RFC_RFTH_16
;
writeb
(
tmp
,
&
info
->
regs
->
w
.
rfc
);
writeb
(
tmp
,
&
up
->
regs
->
w
.
rfc
);
break
;
break
;
default:
default:
info
->
recv_fifo_size
=
32
;
up
->
recv_fifo_size
=
32
;
/* fall through */
/* fall through */
case
32
:
case
32
:
tmp
=
readb
(
&
info
->
regs
->
w
.
rfc
);
tmp
=
readb
(
&
up
->
regs
->
w
.
rfc
);
tmp
|=
SAB82532_RFC_RFTH_32
;
tmp
|=
SAB82532_RFC_RFTH_32
;
writeb
(
tmp
,
&
info
->
regs
->
w
.
rfc
);
writeb
(
tmp
,
&
up
->
regs
->
w
.
rfc
);
break
;
break
;
}
};
tmp
=
readb
(
&
info
->
regs
->
rw
.
ccr0
);
tmp
|=
SAB82532_CCR0_PU
;
/* power-up */
writeb
(
tmp
,
&
info
->
regs
->
rw
.
ccr0
);
}
static
int
startup
(
struct
sab82532
*
info
)
{
unsigned
long
flags
;
unsigned
long
page
;
int
retval
=
0
;
page
=
get_free_page
(
GFP_KERNEL
);
if
(
!
page
)
return
-
ENOMEM
;
save_flags
(
flags
);
cli
();
if
(
info
->
flags
&
ASYNC_INITIALIZED
)
{
free_page
(
page
);
goto
errout
;
}
if
(
!
info
->
regs
)
{
if
(
info
->
tty
)
set_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
free_page
(
page
);
retval
=
-
ENODEV
;
goto
errout
;
}
if
(
info
->
xmit
.
buf
)
free_page
(
page
);
else
info
->
xmit
.
buf
=
(
unsigned
char
*
)
page
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"starting up serial port %d..."
,
info
->
line
);
#endif
/*
* Initialize the Hardware
*/
sab82532_init_line
(
info
);
if
(
info
->
tty
->
termios
->
c_cflag
&
CBAUD
)
{
u8
tmp
;
tmp
=
readb
(
&
info
->
regs
->
rw
.
mode
);
tmp
=
readb
(
&
up
->
regs
->
rw
.
ccr0
);
tmp
&=
~
(
SAB82532_MODE_FRTS
);
tmp
|=
SAB82532_CCR0_PU
;
/* power-up */
tmp
|=
SAB82532_MODE_RTS
;
writeb
(
tmp
,
&
up
->
regs
->
rw
.
ccr0
);
writeb
(
tmp
,
&
info
->
regs
->
rw
.
mode
);
tmp
=
readb
(
&
info
->
regs
->
rw
.
pvr
);
tmp
&=
~
(
info
->
pvr_dtr_bit
);
writeb
(
tmp
,
&
info
->
regs
->
rw
.
pvr
);
}
/*
/*
* Finally, enable interrupts
* Finally, enable interrupts
*/
*/
info
->
interrupt_mask0
=
SAB82532_IMR0_PERR
|
SAB82532_IMR0_FERR
|
up
->
interrupt_mask0
=
(
SAB82532_IMR0_PERR
|
SAB82532_IMR0_FERR
|
SAB82532_IMR0_PLLA
;
SAB82532_IMR0_PLLA
)
;
writeb
(
info
->
interrupt_mask0
,
&
info
->
regs
->
w
.
imr0
);
writeb
(
up
->
interrupt_mask0
,
&
up
->
regs
->
w
.
imr0
);
info
->
interrupt_mask1
=
SAB82532_IMR1_BRKT
|
SAB82532_IMR1_ALLS
|
up
->
interrupt_mask1
=
(
SAB82532_IMR1_BRKT
|
SAB82532_IMR1_ALLS
|
SAB82532_IMR1_XOFF
|
SAB82532_IMR1_TIN
|
SAB82532_IMR1_XOFF
|
SAB82532_IMR1_TIN
|
SAB82532_IMR1_CSC
|
SAB82532_IMR1_XON
|
SAB82532_IMR1_CSC
|
SAB82532_IMR1_XON
|
SAB82532_IMR1_XPR
;
SAB82532_IMR1_XPR
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
set_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
);
set_bit
(
SAB82532_ALLS
,
&
up
->
irqflags
);
set_bit
(
SAB82532_XPR
,
&
up
->
irqflags
);
if
(
info
->
tty
)
clear_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
info
->
xmit
.
head
=
info
->
xmit
.
tail
=
0
;
set_bit
(
SAB82532_XPR
,
&
info
->
irqflags
);
/*
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
* and set the speed of the serial port
*/
change_speed
(
info
);
info
->
flags
|=
ASYNC_INITIALIZED
;
restore_flags
(
flags
);
return
0
;
return
0
;
errout:
restore_flags
(
flags
);
return
retval
;
}
}
/*
/* port->lock is not held. */
* This routine will shutdown a serial port; interrupts are disabled, and
static
void
sunsab_shutdown
(
struct
uart_port
*
port
)
* DTR is dropped if the hangup on close termio flag is on.
*/
static
void
shutdown
(
struct
sab82532
*
info
)
{
{
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
unsigned
long
flags
;
unsigned
long
flags
;
u8
tmp
;
unsigned
char
tmp
;
if
(
!
(
info
->
flags
&
ASYNC_INITIALIZED
))
return
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"Shutting down serial port %d..."
,
info
->
line
);
#endif
save_flags
(
flags
);
cli
();
/* Disable interrupts */
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
wake_up_interruptible
(
&
info
->
delta_msr_wait
);
if
(
info
->
xmit
.
buf
)
{
free_page
((
unsigned
long
)
info
->
xmit
.
buf
);
info
->
xmit
.
buf
=
0
;
}
if
(
info
->
is_console
)
{
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
info
->
interrupt_mask0
=
SAB82532_IMR0_PERR
|
SAB82532_IMR0_FERR
|
SAB82532_IMR0_PLLA
|
SAB82532_IMR0_CDSC
;
writeb
(
info
->
interrupt_mask0
,
&
info
->
regs
->
w
.
imr0
);
info
->
interrupt_mask1
=
SAB82532_IMR1_BRKT
|
SAB82532_IMR1_ALLS
|
SAB82532_IMR1_XOFF
|
SAB82532_IMR1_TIN
|
SAB82532_IMR1_CSC
|
SAB82532_IMR1_XON
|
SAB82532_IMR1_XPR
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
if
(
info
->
tty
)
set_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
info
->
flags
&=
~
ASYNC_INITIALIZED
;
restore_flags
(
flags
);
return
;
}
/* Disable Interrupts */
/* Disable Interrupts */
info
->
interrupt_mask0
=
0xff
;
up
->
interrupt_mask0
=
0xff
;
writeb
(
info
->
interrupt_mask0
,
&
info
->
regs
->
w
.
imr0
);
writeb
(
up
->
interrupt_mask0
,
&
up
->
regs
->
w
.
imr0
);
info
->
interrupt_mask1
=
0xff
;
up
->
interrupt_mask1
=
0xff
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
if
(
!
info
->
tty
||
(
info
->
tty
->
termios
->
c_cflag
&
HUPCL
))
{
tmp
=
readb
(
&
info
->
regs
->
r
.
mode
);
tmp
|=
(
SAB82532_MODE_FRTS
|
SAB82532_MODE_RTS
);
writeb
(
tmp
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
|
info
->
pvr_dtr_bit
,
&
info
->
regs
->
rw
.
pvr
);
}
/* Disable break condition */
/* Disable break condition */
tmp
=
readb
(
&
info
->
regs
->
rw
.
dafo
);
tmp
=
readb
(
&
up
->
regs
->
rw
.
dafo
);
tmp
&=
~
(
SAB82532_DAFO_XBRK
)
;
tmp
&=
~
SAB82532_DAFO_XBRK
;
writeb
(
tmp
,
&
info
->
regs
->
rw
.
dafo
);
writeb
(
tmp
,
&
up
->
regs
->
rw
.
dafo
);
/* Disable Receiver */
/* Disable Receiver */
tmp
=
readb
(
&
info
->
regs
->
rw
.
mode
);
tmp
=
readb
(
&
up
->
regs
->
rw
.
mode
);
tmp
&=
~
(
SAB82532_MODE_RAC
)
;
tmp
&=
~
SAB82532_MODE_RAC
;
writeb
(
tmp
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
tmp
,
&
up
->
regs
->
rw
.
mode
);
/* Power Down */
/* Power Down */
tmp
=
readb
(
&
info
->
regs
->
rw
.
ccr0
);
tmp
=
readb
(
&
up
->
regs
->
rw
.
ccr0
);
tmp
&=
~
(
SAB82532_CCR0_PU
)
;
tmp
&=
~
SAB82532_CCR0_PU
;
writeb
(
tmp
,
&
info
->
regs
->
rw
.
ccr0
);
writeb
(
tmp
,
&
up
->
regs
->
rw
.
ccr0
);
if
(
info
->
tty
)
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
set_bit
(
TTY_IO_ERROR
,
&
info
->
tty
->
flags
);
info
->
flags
&=
~
ASYNC_INITIALIZED
;
restore_flags
(
flags
);
}
}
/*
/*
* This routine is called to set the UART divisor registers to match
* This is used to figure out the divisor speeds.
* the specified baud rate for a serial port.
*
* The formula is: Baud = SAB_BASE_BAUD / ((N + 1) * (1 << M)),
*
* with 0 <= N < 64 and 0 <= M < 16
*/
*/
static
void
change_speed
(
struct
sab82532
*
info
)
static
void
calc_ebrg
(
int
baud
,
int
*
n_ret
,
int
*
m_ret
)
{
int
n
,
m
;
if
(
baud
==
0
)
{
*
n_ret
=
0
;
*
m_ret
=
0
;
return
;
}
/*
* We scale numbers by 10 so that we get better accuracy
* without having to use floating point. Here we increment m
* until n is within the valid range.
*/
n
=
(
SAB_BASE_BAUD
*
10
)
/
baud
;
m
=
0
;
while
(
n
>=
640
)
{
n
=
n
/
2
;
m
++
;
}
n
=
(
n
+
5
)
/
10
;
/*
* We try very hard to avoid speeds with M == 0 since they may
* not work correctly for XTAL frequences above 10 MHz.
*/
if
((
m
==
0
)
&&
((
n
&
1
)
==
0
))
{
n
=
n
/
2
;
m
++
;
}
*
n_ret
=
n
-
1
;
*
m_ret
=
m
;
}
/* Internal routine, port->lock is held and local interrupts are disabled. */
static
void
sunsab_convert_to_sab
(
struct
uart_sunsab_port
*
up
,
unsigned
int
cflag
,
unsigned
int
iflag
,
int
baud
)
{
{
unsigned
long
flags
;
unsigned
int
ebrg
;
unsigned
int
ebrg
;
tcflag_t
cflag
;
unsigned
char
dafo
;
unsigned
char
dafo
;
int
bits
,
n
,
m
;
int
bits
,
n
,
m
;
if
(
!
info
->
tty
||
!
info
->
tty
->
termios
)
return
;
cflag
=
info
->
tty
->
termios
->
c_cflag
;
/* Byte size and parity */
/* Byte size and parity */
switch
(
cflag
&
CSIZE
)
{
switch
(
cflag
&
CSIZE
)
{
case
CS5
:
dafo
=
SAB82532_DAFO_CHL5
;
bits
=
7
;
break
;
case
CS5
:
dafo
=
SAB82532_DAFO_CHL5
;
bits
=
7
;
break
;
...
@@ -959,1658 +688,483 @@ static void change_speed(struct sab82532 *info)
...
@@ -959,1658 +688,483 @@ static void change_speed(struct sab82532 *info)
}
}
if
(
cflag
&
PARODD
)
{
if
(
cflag
&
PARODD
)
{
#ifdef CMSPAR
if
(
cflag
&
CMSPAR
)
dafo
|=
SAB82532_DAFO_PAR_MARK
;
else
#endif
dafo
|=
SAB82532_DAFO_PAR_ODD
;
dafo
|=
SAB82532_DAFO_PAR_ODD
;
}
else
{
}
else
{
#ifdef CMSPAR
if
(
cflag
&
CMSPAR
)
dafo
|=
SAB82532_DAFO_PAR_SPACE
;
else
#endif
dafo
|=
SAB82532_DAFO_PAR_EVEN
;
dafo
|=
SAB82532_DAFO_PAR_EVEN
;
}
}
/* Determine EBRG values based on baud rate */
calc_ebrg
(
baud
,
&
n
,
&
m
);
info
->
baud
=
tty_get_baud_rate
(
info
->
tty
);
calc_ebrg
(
info
->
baud
,
&
n
,
&
m
);
ebrg
=
n
|
(
m
<<
6
);
ebrg
=
n
|
(
m
<<
6
);
if
(
info
->
baud
)
{
up
->
tec_timeout
=
(
10
*
1000000
)
/
baud
;
info
->
timeout
=
(
info
->
xmit_fifo_size
*
HZ
*
bits
)
/
info
->
baud
;
up
->
cec_timeout
=
up
->
tec_timeout
>>
2
;
info
->
tec_timeout
=
(
10
*
1000000
)
/
info
->
baud
;
info
->
cec_timeout
=
info
->
tec_timeout
>>
2
;
}
else
{
info
->
timeout
=
0
;
info
->
tec_timeout
=
SAB82532_MAX_TEC_TIMEOUT
;
info
->
cec_timeout
=
SAB82532_MAX_CEC_TIMEOUT
;
}
info
->
timeout
+=
HZ
/
50
;
/* Add .02 seconds of slop */
/* CTS flow control flags */
/* CTS flow control flags */
if
(
cflag
&
CRTSCTS
)
/* We encode read_status_mask and ignore_status_mask like so:
info
->
flags
|=
ASYNC_CTS_FLOW
;
*
else
* ---------------------
info
->
flags
&=
~
(
ASYNC_CTS_FLOW
);
* | ... | ISR1 | ISR0 |
* ---------------------
if
(
cflag
&
CLOCAL
)
* .. 15 8 7 0
info
->
flags
&=
~
(
ASYNC_CHECK_CD
);
*/
else
info
->
flags
|=
ASYNC_CHECK_CD
;
up
->
port
.
read_status_mask
=
(
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TIME
|
if
(
info
->
tty
)
SAB82532_ISR0_RFO
|
SAB82532_ISR0_RPF
|
info
->
tty
->
hw_stopped
=
0
;
SAB82532_ISR0_CDSC
);
up
->
port
.
read_status_mask
|=
(
SAB82532_ISR1_CSC
|
SAB82532_ISR1_ALLS
|
SAB82532_ISR1_XPR
)
<<
8
;
if
(
iflag
&
INPCK
)
up
->
port
.
read_status_mask
|=
(
SAB82532_ISR0_PERR
|
SAB82532_ISR0_FERR
);
if
(
iflag
&
(
BRKINT
|
PARMRK
))
up
->
port
.
read_status_mask
|=
(
SAB82532_ISR1_BRK
<<
8
);
/*
/*
* Set up parity check flag
* Characteres to ignore
* XXX: not implemented, yet.
*/
*/
up
->
port
.
ignore_status_mask
=
0
;
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
if
(
iflag
&
IGNPAR
)
up
->
port
.
ignore_status_mask
|=
(
SAB82532_ISR0_PERR
|
SAB82532_ISR0_FERR
);
if
(
iflag
&
IGNBRK
)
{
up
->
port
.
ignore_status_mask
|=
(
SAB82532_ISR1_BRK
<<
8
);
/*
/*
* Characters to ignore
* If we're ignoring parity and break indicators,
* XXX: not implemented, yet
.
* ignore overruns too (for real raw support)
.
*/
*/
if
(
iflag
&
IGNPAR
)
up
->
port
.
ignore_status_mask
|=
SAB82532_ISR0_RFO
;
}
/*
/*
* !!! ignore all characters if CREAD is not set
* ignore all characters if CREAD is not set
* XXX: not implemented, yet.
*/
*/
if
((
cflag
&
CREAD
)
==
0
)
if
((
cflag
&
CREAD
)
==
0
)
info
->
ignore_status_mask
|=
SAB82532_ISR0_RPF
|
up
->
port
.
ignore_status_mask
|=
(
SAB82532_ISR0_RPF
|
SAB82532_ISR0_TCD
|
SAB82532_ISR0_TCD
);
SAB82532_ISR0_TIME
;
/* Now bang the new settings into the chip. */
save_flags
(
flags
);
cli
();
sunsab_cec_wait
(
up
);
sab82532_cec_wait
(
info
);
sunsab_tec_wait
(
up
);
sab82532_tec_wait
(
info
);
writeb
(
dafo
,
&
up
->
regs
->
w
.
dafo
);
writeb
(
dafo
,
&
info
->
regs
->
w
.
dafo
);
writeb
(
ebrg
&
0xff
,
&
up
->
regs
->
w
.
bgr
);
writeb
(
ebrg
&
0xff
,
&
info
->
regs
->
w
.
bgr
);
writeb
((
readb
(
&
up
->
regs
->
rw
.
ccr2
)
&
~
0xc0
)
|
((
ebrg
>>
2
)
&
0xc0
),
writeb
(
readb
(
&
info
->
regs
->
rw
.
ccr2
)
&
~
(
0xc0
),
&
info
->
regs
->
rw
.
ccr2
);
&
up
->
regs
->
rw
.
ccr2
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
ccr2
)
|
((
ebrg
>>
2
)
&
0xc0
),
&
info
->
regs
->
rw
.
ccr2
);
if
(
info
->
flags
&
ASYNC_CTS_FLOW
)
{
if
(
cflag
&
CRTSCTS
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_RTS
),
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
&
~
SAB82532_MODE_RTS
,
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
rw
.
mode
);
&
up
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_FCTS
),
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_CSC
);
&
up
->
regs
->
rw
.
mode
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
&
~
SAB82532_MODE_FCTS
,
&
up
->
regs
->
rw
.
mode
);
up
->
interrupt_mask1
&=
~
SAB82532_IMR1_CSC
;
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
}
else
{
}
else
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_FRTS
),
&
info
->
regs
->
rw
.
mode
);
&
up
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FCTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
&
~
SAB82532_MODE_FRTS
,
info
->
interrupt_mask1
|=
SAB82532_IMR1_CSC
;
&
up
->
regs
->
rw
.
mode
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FCTS
,
&
up
->
regs
->
rw
.
mode
);
up
->
interrupt_mask1
|=
SAB82532_IMR1_CSC
;
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
}
}
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RAC
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RAC
,
&
up
->
regs
->
rw
.
mode
);
restore_flags
(
flags
);
}
}
static
void
sab82532_put_char
(
struct
tty_struct
*
tty
,
unsigned
char
ch
)
/* port->lock is not held. */
static
void
sunsab_change_speed
(
struct
uart_port
*
port
,
unsigned
int
cflag
,
unsigned
int
iflag
,
unsigned
int
quot
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
struct
uart_sunsab_port
*
up
=
(
struct
uart_sunsab_port
*
)
port
;
unsigned
long
flags
;
unsigned
long
flags
;
int
baud
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_put_char"
))
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
return
;
if
(
!
tty
||
!
info
->
xmit
.
buf
)
/* Undo what generic UART core did. */
return
;
baud
=
(
SAB_BASE_BAUD
/
(
quot
*
16
))
;
save_flags
(
flags
);
cli
();
sunsab_convert_to_sab
(
up
,
cflag
,
iflag
,
baud
);
if
(
!
CIRC_SPACE
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
))
{
restore_flags
(
flags
);
return
;
}
info
->
xmit
.
buf
[
info
->
xmit
.
head
]
=
ch
;
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
info
->
xmit
.
head
=
(
info
->
xmit
.
head
+
1
)
&
(
SERIAL_XMIT_SIZE
-
1
);
restore_flags
(
flags
);
}
}
static
void
sab82532_flush_chars
(
struct
tty_struct
*
tty
)
static
const
char
*
sunsab_type
(
struct
uart_port
*
port
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
return
"SunSAB"
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_flush_chars"
))
return
;
if
((
info
->
xmit
.
head
==
info
->
xmit
.
tail
)
||
tty
->
stopped
||
tty
->
hw_stopped
||
!
info
->
xmit
.
buf
)
return
;
save_flags
(
flags
);
cli
();
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_XPR
);
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
sab82532_start_tx
(
info
);
restore_flags
(
flags
);
}
}
static
int
sab82532_write
(
struct
tty_struct
*
tty
,
int
from_user
,
static
void
sunsab_release_port
(
struct
uart_port
*
port
)
const
unsigned
char
*
buf
,
int
count
)
{
{
int
c
,
ret
=
0
;
}
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_write"
))
static
int
sunsab_request_port
(
struct
uart_port
*
port
)
{
return
0
;
return
0
;
}
if
(
!
tty
||
!
info
->
xmit
.
buf
||
!
tmp_buf
)
static
void
sunsab_config_port
(
struct
uart_port
*
port
,
int
flags
)
return
0
;
{
}
save_flags
(
flags
);
static
int
sunsab_verify_port
(
struct
uart_port
*
port
,
struct
serial_struct
*
ser
)
if
(
from_user
)
{
{
down
(
&
tmp_buf_sem
);
return
-
EINVAL
;
while
(
1
)
{
}
int
c1
;
c
=
CIRC_SPACE_TO_END
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
);
if
(
count
<
c
)
c
=
count
;
if
(
c
<=
0
)
break
;
c
-=
copy_from_user
(
tmp_buf
,
buf
,
c
);
static
struct
uart_ops
sunsab_pops
=
{
if
(
!
c
)
{
.
tx_empty
=
sunsab_tx_empty
,
if
(
!
ret
)
.
set_mctrl
=
sunsab_set_mctrl
,
ret
=
-
EFAULT
;
.
get_mctrl
=
sunsab_get_mctrl
,
break
;
.
stop_tx
=
sunsab_stop_tx
,
}
.
start_tx
=
sunsab_start_tx
,
cli
();
.
send_xchar
=
sunsab_send_xchar
,
c1
=
CIRC_SPACE_TO_END
(
info
->
xmit
.
head
,
.
stop_rx
=
sunsab_stop_rx
,
info
->
xmit
.
tail
,
.
enable_ms
=
sunsab_enable_ms
,
SERIAL_XMIT_SIZE
);
.
break_ctl
=
sunsab_break_ctl
,
if
(
c1
<
c
)
.
startup
=
sunsab_startup
,
c
=
c1
;
.
shutdown
=
sunsab_shutdown
,
memcpy
(
info
->
xmit
.
buf
+
info
->
xmit
.
head
,
tmp_buf
,
c
);
.
change_speed
=
sunsab_change_speed
,
info
->
xmit
.
head
=
(
info
->
xmit
.
head
+
c
)
&
(
SERIAL_XMIT_SIZE
-
1
);
.
type
=
sunsab_type
,
restore_flags
(
flags
);
.
release_port
=
sunsab_release_port
,
buf
+=
c
;
.
request_port
=
sunsab_request_port
,
count
-=
c
;
.
config_port
=
sunsab_config_port
,
ret
+=
c
;
.
verify_port
=
sunsab_verify_port
,
}
};
up
(
&
tmp_buf_sem
);
}
else
{
cli
();
while
(
1
)
{
c
=
CIRC_SPACE_TO_END
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
);
if
(
count
<
c
)
c
=
count
;
if
(
c
<=
0
)
break
;
memcpy
(
info
->
xmit
.
buf
+
info
->
xmit
.
head
,
buf
,
c
);
info
->
xmit
.
head
=
(
info
->
xmit
.
head
+
c
)
&
(
SERIAL_XMIT_SIZE
-
1
);
buf
+=
c
;
count
-=
c
;
ret
+=
c
;
}
restore_flags
(
flags
);
}
if
((
info
->
xmit
.
head
!=
info
->
xmit
.
tail
)
&&
static
struct
uart_driver
sunsab_reg
=
{
!
tty
->
stopped
&&
!
tty
->
hw_stopped
)
{
.
owner
=
THIS_MODULE
,
info
->
interrupt_mask1
&=
~
(
SAB82532_IMR1_XPR
);
.
driver_name
=
"serial"
,
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
#ifdef CONFIG_DEVFS_FS
sab82532_start_tx
(
info
);
.
dev_name
=
"tts/%d"
,
}
#else
.
dev_name
=
"ttyS"
,
#endif
.
major
=
TTY_MAJOR
,
};
restore_flags
(
flags
);
static
struct
uart_sunsab_port
*
sunsab_ports
;
return
ret
;
static
int
num_channels
;
}
static
int
sab82532_write_room
(
struct
tty_struct
*
tty
)
static
__inline__
void
sunsab_console_putchar
(
struct
uart_sunsab_port
*
up
,
char
c
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_write_room"
))
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
return
0
;
return
CIRC_SPACE
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
);
sunsab_tec_wait
(
up
);
writeb
(
c
,
&
up
->
regs
->
w
.
tic
);
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
}
}
static
int
sab82532_chars_in_buffer
(
struct
tty_struct
*
tty
)
static
void
sunsab_console_write
(
struct
console
*
con
,
const
char
*
s
,
unsigned
n
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
con
->
index
];
int
i
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_chars_in_buffer"
))
for
(
i
=
0
;
i
<
n
;
i
++
)
{
return
0
;
if
(
*
s
==
'\n'
)
sunsab_console_putchar
(
up
,
'\r'
);
sunsab_console_putchar
(
up
,
*
s
++
);
}
sunsab_tec_wait
(
up
);
}
return
CIRC_CNT
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
);
static
kdev_t
sunsab_console_device
(
struct
console
*
con
)
{
return
mk_kdev
(
sunsab_reg
.
major
,
sunsab_reg
.
minor
+
con
->
index
);
}
}
static
void
sab82532_flush_buffer
(
struct
tty_struct
*
tty
)
static
int
sunsab_console_setup
(
struct
console
*
con
,
char
*
options
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
con
->
index
]
;
unsigned
long
flags
;
unsigned
long
flags
;
int
baud
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_flush_buffer"
))
printk
(
"Console: ttyS%d (SAB82532)
\n
"
,
return
;
(
sunsab_reg
.
minor
-
64
)
+
con
->
index
)
;
save_flags
(
flags
);
cli
();
sunserial_console_termios
(
con
);
info
->
xmit
.
head
=
info
->
xmit
.
tail
=
0
;
restore_flags
(
flags
);
wake_up_interruptible
(
&
tty
->
write_wait
);
/* Firmware console speed is limited to 150-->38400 baud so
if
((
tty
->
flags
&
(
1
<<
TTY_DO_WRITE_WAKEUP
))
&&
* this hackish cflag thing is OK.
tty
->
ldisc
.
write_wakeup
)
*/
(
tty
->
ldisc
.
write_wakeup
)(
tty
);
switch
(
con
->
cflag
&
CBAUD
)
{
}
case
B150
:
baud
=
150
;
break
;
case
B300
:
baud
=
300
;
break
;
case
B600
:
baud
=
600
;
break
;
case
B1200
:
baud
=
1200
;
break
;
case
B2400
:
baud
=
2400
;
break
;
case
B4800
:
baud
=
4800
;
break
;
default:
case
B9600
:
baud
=
9600
;
break
;
case
B19200
:
baud
=
19200
;
break
;
case
B38400
:
baud
=
38400
;
break
;
};
/*
/*
* This function is used to send a high-priority XON/XOFF character to
* Temporary fix.
* the device
*/
*/
static
void
sab82532_send_xchar
(
struct
tty_struct
*
tty
,
char
ch
)
spin_lock_init
(
&
up
->
port
.
lock
);
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_send_xchar"
))
/*
return
;
* Initialize the hardware
*/
sunsab_startup
(
&
up
->
port
);
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
up
->
port
.
lock
,
flags
);
sab82532_tec_wait
(
info
);
writeb
(
ch
,
&
info
->
regs
->
w
.
tic
);
restore_flags
(
flags
);
}
/*
/*
* ------------------------------------------------------------
* Finally, enable interrupts
* sab82532_throttle()
*
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
*/
static
void
sab82532_throttle
(
struct
tty_struct
*
tty
)
up
->
interrupt_mask0
=
SAB82532_IMR0_PERR
|
SAB82532_IMR0_FERR
|
{
SAB82532_IMR0_PLLA
|
SAB82532_IMR0_CDSC
;
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
writeb
(
up
->
interrupt_mask0
,
&
up
->
regs
->
w
.
imr0
);
#ifdef SERIAL_DEBUG_THROTTLE
up
->
interrupt_mask1
=
SAB82532_IMR1_BRKT
|
SAB82532_IMR1_ALLS
|
char
buf
[
64
];
SAB82532_IMR1_XOFF
|
SAB82532_IMR1_TIN
|
SAB82532_IMR1_CSC
|
SAB82532_IMR1_XON
|
printk
(
"throttle %s: %d....
\n
"
,
_tty_name
(
tty
,
buf
),
SAB82532_IMR1_XPR
;
tty
->
ldisc
.
chars_in_buffer
(
tty
));
writeb
(
up
->
interrupt_mask1
,
&
up
->
regs
->
w
.
imr1
);
#endif
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_throttle"
))
sunsab_convert_to_sab
(
up
,
con
->
cflag
,
0
,
baud
);
return
;
if
(
I_IXOFF
(
tty
))
spin_unlock_irqrestore
(
&
up
->
port
.
lock
,
flags
);
sab82532_send_xchar
(
tty
,
STOP_CHAR
(
tty
));
if
(
tty
->
termios
->
c_cflag
&
CRTSCTS
)
{
return
0
;
u8
mode
=
readb
(
&
info
->
regs
->
r
.
mode
);
mode
&=
~
(
SAB82532_MODE_FRTS
|
SAB82532_MODE_RTS
);
writeb
(
mode
,
&
info
->
regs
->
w
.
mode
);
}
}
}
static
void
sab82532_unthrottle
(
struct
tty_struct
*
tty
)
static
struct
console
sunsab_console
=
{
{
.
name
=
"ttyS"
,
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
.
write
=
sunsab_console_write
,
#ifdef SERIAL_DEBUG_THROTTLE
.
device
=
sunsab_console_device
,
char
buf
[
64
];
.
setup
=
sunsab_console_setup
,
.
flags
=
CON_PRINTBUFFER
,
.
index
=
-
1
,
};
printk
(
"unthrottle %s: %d....
\n
"
,
_tty_name
(
tty
,
buf
),
static
void
__init
sunsab_console_init
(
void
)
tty
->
ldisc
.
chars_in_buffer
(
tty
));
{
#endif
int
i
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_unthrottle"
))
if
(
con_is_present
(
))
return
;
return
;
if
(
I_IXOFF
(
tty
))
{
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
if
(
info
->
x_char
)
int
this_minor
=
sunsab_reg
.
minor
+
i
;
info
->
x_char
=
0
;
else
sab82532_send_xchar
(
tty
,
START_CHAR
(
tty
));
}
if
(
tty
->
termios
->
c_cflag
&
CRTSCTS
)
{
if
((
this_minor
-
64
)
==
(
serial_console
-
1
))
u8
mode
=
readb
(
&
info
->
regs
->
r
.
mode
);
break
;
mode
&=
~
(
SAB82532_MODE_RTS
);
mode
|=
SAB82532_MODE_FRTS
;
writeb
(
mode
,
&
info
->
regs
->
w
.
mode
);
}
}
}
if
(
i
==
num_channels
)
return
;
/*
* ------------------------------------------------------------
* sab82532_ioctl() and friends
* ------------------------------------------------------------
*/
static
int
get_serial_info
(
struct
sab82532
*
info
,
sunsab_console
.
index
=
i
;
struct
serial_struct
*
retinfo
)
register_console
(
&
sunsab_console
);
{
struct
serial_struct
tmp
;
if
(
!
retinfo
)
return
-
EFAULT
;
memset
(
&
tmp
,
0
,
sizeof
(
tmp
));
tmp
.
type
=
info
->
type
;
tmp
.
line
=
info
->
line
;
tmp
.
port
=
(
unsigned
long
)
info
->
regs
;
tmp
.
irq
=
info
->
irq
;
tmp
.
flags
=
info
->
flags
;
tmp
.
xmit_fifo_size
=
info
->
xmit_fifo_size
;
tmp
.
baud_base
=
info
->
baud_base
;
tmp
.
close_delay
=
info
->
close_delay
;
tmp
.
closing_wait
=
info
->
closing_wait
;
tmp
.
custom_divisor
=
info
->
custom_divisor
;
tmp
.
hub6
=
0
;
if
(
copy_to_user
(
retinfo
,
&
tmp
,
sizeof
(
*
retinfo
)))
return
-
EFAULT
;
return
0
;
}
}
static
int
set_serial_info
(
struct
sab82532
*
info
,
static
void
__init
for_each_sab_edev
(
void
(
*
callback
)(
struct
linux_ebus_device
*
,
void
*
),
void
*
arg
)
struct
serial_struct
*
new_info
)
{
{
return
0
;
struct
linux_ebus
*
ebus
;
}
struct
linux_ebus_device
*
edev
=
NULL
;
for_each_ebus
(
ebus
)
{
for_each_ebusdev
(
edev
,
ebus
)
{
if
(
!
strcmp
(
edev
->
prom_name
,
"se"
))
{
callback
(
edev
,
arg
);
continue
;
}
else
if
(
!
strcmp
(
edev
->
prom_name
,
"serial"
))
{
char
compat
[
32
];
int
clen
;
/*
/* On RIO this can be an SE, check it. We could
* get_lsr_info - get line status register info
* just check ebus->is_rio, but this is more portable.
*
* Purpose: Let user call ioctl() to get info when the UART physically
* is emptied. On bus types like RS485, the transmitter must
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
*/
static
int
get_lsr_info
(
struct
sab82532
*
info
,
unsigned
int
*
value
)
clen
=
prom_getproperty
(
edev
->
prom_node
,
"compatible"
,
{
compat
,
sizeof
(
compat
));
unsigned
int
result
;
if
(
clen
>
0
)
{
if
(
strncmp
(
compat
,
"sab82532"
,
8
)
==
0
)
{
result
=
(
!
info
->
xmit
.
buf
&&
test_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
))
callback
(
edev
,
arg
);
?
TIOCSER_TEMT
:
0
;
continue
;
return
put_user
(
result
,
value
);
}
static
int
get_modem_info
(
struct
sab82532
*
info
,
unsigned
int
*
value
)
{
unsigned
int
result
;
result
=
((
readb
(
&
info
->
regs
->
r
.
mode
)
&
SAB82532_MODE_RTS
)
?
((
readb
(
&
info
->
regs
->
r
.
mode
)
&
SAB82532_MODE_FRTS
)
?
0
:
TIOCM_RTS
)
:
TIOCM_RTS
)
|
((
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dtr_bit
)
?
0
:
TIOCM_DTR
)
|
((
readb
(
&
info
->
regs
->
r
.
vstr
)
&
SAB82532_VSTR_CD
)
?
0
:
TIOCM_CAR
)
|
((
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dsr_bit
)
?
0
:
TIOCM_DSR
)
|
((
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_CTS
)
?
TIOCM_CTS
:
0
);
return
put_user
(
result
,
value
);
}
static
int
set_modem_info
(
struct
sab82532
*
info
,
unsigned
int
cmd
,
unsigned
int
*
value
)
{
unsigned
int
arg
;
if
(
get_user
(
arg
,
value
))
return
-
EFAULT
;
switch
(
cmd
)
{
case
TIOCMBIS
:
if
(
arg
&
TIOCM_RTS
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_FRTS
),
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
}
if
(
arg
&
TIOCM_DTR
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
&
~
(
info
->
pvr_dtr_bit
),
&
info
->
regs
->
rw
.
pvr
);
}
break
;
case
TIOCMBIC
:
if
(
arg
&
TIOCM_RTS
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
}
}
if
(
arg
&
TIOCM_DTR
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
|
info
->
pvr_dtr_bit
,
&
info
->
regs
->
rw
.
pvr
);
}
}
break
;
case
TIOCMSET
:
if
(
arg
&
TIOCM_RTS
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_FRTS
),
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
}
else
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
}
}
if
(
arg
&
TIOCM_DTR
)
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
&
~
(
info
->
pvr_dtr_bit
),
&
info
->
regs
->
rw
.
pvr
);
}
else
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
|
info
->
pvr_dtr_bit
,
&
info
->
regs
->
rw
.
pvr
);
}
}
break
;
default:
return
-
EINVAL
;
}
}
return
0
;
}
}
/*
static
void
__init
sab_count_callback
(
struct
linux_ebus_device
*
edev
,
void
*
arg
)
* This routine sends a break character out the serial port.
*/
static
void
sab82532_break
(
struct
tty_struct
*
tty
,
int
break_state
)
{
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
int
*
count_p
=
arg
;
unsigned
long
flags
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_break"
))
(
*
count_p
)
++
;
return
;
if
(
!
info
->
regs
)
return
;
#ifdef SERIAL_DEBUG_SEND_BREAK
printk
(
"sab82532_break(%d) jiff=%lu..."
,
break_state
,
jiffies
);
#endif
save_flags
(
flags
);
cli
();
if
(
break_state
==
-
1
)
writeb
(
readb
(
&
info
->
regs
->
rw
.
dafo
)
|
SAB82532_DAFO_XBRK
,
&
info
->
regs
->
rw
.
dafo
);
else
writeb
(
readb
(
&
info
->
regs
->
rw
.
dafo
)
&
~
(
SAB82532_DAFO_XBRK
),
&
info
->
regs
->
rw
.
dafo
);
restore_flags
(
flags
);
}
static
int
sab82532_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
struct
async_icount
cprev
,
cnow
;
/* kernel counter temps */
struct
serial_icounter_struct
*
p_cuser
;
/* user space */
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_ioctl"
))
return
-
ENODEV
;
if
((
cmd
!=
TIOCGSERIAL
)
&&
(
cmd
!=
TIOCSSERIAL
)
&&
(
cmd
!=
TIOCSERCONFIG
)
&&
(
cmd
!=
TIOCSERGWILD
)
&&
(
cmd
!=
TIOCSERSWILD
)
&&
(
cmd
!=
TIOCSERGSTRUCT
)
&&
(
cmd
!=
TIOCMIWAIT
)
&&
(
cmd
!=
TIOCGICOUNT
))
{
if
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
))
return
-
EIO
;
}
switch
(
cmd
)
{
case
TIOCGSOFTCAR
:
return
put_user
(
C_CLOCAL
(
tty
)
?
1
:
0
,
(
int
*
)
arg
);
case
TIOCSSOFTCAR
:
if
(
get_user
(
arg
,
(
unsigned
int
*
)
arg
))
return
-
EFAULT
;
tty
->
termios
->
c_cflag
=
((
tty
->
termios
->
c_cflag
&
~
CLOCAL
)
|
(
arg
?
CLOCAL
:
0
));
return
0
;
case
TIOCMGET
:
return
get_modem_info
(
info
,
(
unsigned
int
*
)
arg
);
case
TIOCMBIS
:
case
TIOCMBIC
:
case
TIOCMSET
:
return
set_modem_info
(
info
,
cmd
,
(
unsigned
int
*
)
arg
);
case
TIOCGSERIAL
:
return
get_serial_info
(
info
,
(
struct
serial_struct
*
)
arg
);
case
TIOCSSERIAL
:
return
set_serial_info
(
info
,
(
struct
serial_struct
*
)
arg
);
case
TIOCSERGETLSR
:
/* Get line status register */
return
get_lsr_info
(
info
,
(
unsigned
int
*
)
arg
);
case
TIOCSERGSTRUCT
:
if
(
copy_to_user
((
struct
sab82532
*
)
arg
,
info
,
sizeof
(
struct
sab82532
)))
return
-
EFAULT
;
return
0
;
/*
* 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
:
cli
();
/* note the counters on entry */
cprev
=
info
->
icount
;
sti
();
while
(
1
)
{
interruptible_sleep_on
(
&
info
->
delta_msr_wait
);
/* see if a signal did it */
if
(
signal_pending
(
current
))
return
-
ERESTARTSYS
;
cli
();
cnow
=
info
->
icount
;
/* atomic copy */
sti
();
if
(
cnow
.
rng
==
cprev
.
rng
&&
cnow
.
dsr
==
cprev
.
dsr
&&
cnow
.
dcd
==
cprev
.
dcd
&&
cnow
.
cts
==
cprev
.
cts
)
return
-
EIO
;
/* no change => error */
if
(
((
arg
&
TIOCM_RNG
)
&&
(
cnow
.
rng
!=
cprev
.
rng
))
||
((
arg
&
TIOCM_DSR
)
&&
(
cnow
.
dsr
!=
cprev
.
dsr
))
||
((
arg
&
TIOCM_CD
)
&&
(
cnow
.
dcd
!=
cprev
.
dcd
))
||
((
arg
&
TIOCM_CTS
)
&&
(
cnow
.
cts
!=
cprev
.
cts
))
)
{
return
0
;
}
cprev
=
cnow
;
}
/* NOTREACHED */
/*
* 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
:
cli
();
cnow
=
info
->
icount
;
sti
();
p_cuser
=
(
struct
serial_icounter_struct
*
)
arg
;
if
(
put_user
(
cnow
.
cts
,
&
p_cuser
->
cts
)
||
put_user
(
cnow
.
dsr
,
&
p_cuser
->
dsr
)
||
put_user
(
cnow
.
rng
,
&
p_cuser
->
rng
)
||
put_user
(
cnow
.
dcd
,
&
p_cuser
->
dcd
))
return
-
EFAULT
;
return
0
;
default:
return
-
ENOIOCTLCMD
;
}
return
0
;
}
static
void
sab82532_set_termios
(
struct
tty_struct
*
tty
,
struct
termios
*
old_termios
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
if
(
(
tty
->
termios
->
c_cflag
==
old_termios
->
c_cflag
)
&&
(
RELEVANT_IFLAG
(
tty
->
termios
->
c_iflag
)
==
RELEVANT_IFLAG
(
old_termios
->
c_iflag
)))
return
;
change_speed
(
info
);
/* Handle transition to B0 status */
if
((
old_termios
->
c_cflag
&
CBAUD
)
&&
!
(
tty
->
termios
->
c_cflag
&
CBAUD
))
{
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
w
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
w
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
w
.
pvr
)
|
info
->
pvr_dtr_bit
,
&
info
->
regs
->
w
.
pvr
);
}
/* Handle transition away from B0 status */
if
(
!
(
old_termios
->
c_cflag
&
CBAUD
)
&&
(
tty
->
termios
->
c_cflag
&
CBAUD
))
{
writeb
(
readb
(
&
info
->
regs
->
w
.
pvr
)
&
~
(
info
->
pvr_dtr_bit
),
&
info
->
regs
->
w
.
pvr
);
if
(
tty
->
termios
->
c_cflag
&
CRTSCTS
)
{
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
&
~
(
SAB82532_MODE_RTS
),
&
info
->
regs
->
w
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
w
.
mode
);
}
else
if
(
test_bit
(
TTY_THROTTLED
,
&
tty
->
flags
))
{
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
&
~
(
SAB82532_MODE_FRTS
|
SAB82532_MODE_RTS
),
&
info
->
regs
->
w
.
mode
);
}
else
{
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
&
~
(
SAB82532_MODE_FRTS
),
&
info
->
regs
->
w
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
w
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
w
.
mode
);
}
}
/* Handle turning off CRTSCTS */
if
((
old_termios
->
c_cflag
&
CRTSCTS
)
&&
!
(
tty
->
termios
->
c_cflag
&
CRTSCTS
))
{
tty
->
hw_stopped
=
0
;
sab82532_start
(
tty
);
}
}
/*
* ------------------------------------------------------------
* sab82532_close()
*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
static
void
sab82532_close
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
flags
;
if
(
!
info
||
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_close"
))
return
;
save_flags
(
flags
);
cli
();
if
(
tty_hung_up_p
(
filp
))
{
MOD_DEC_USE_COUNT
;
restore_flags
(
flags
);
return
;
}
#ifdef SERIAL_DEBUG_OPEN
printk
(
"sab82532_close ttys%d, count = %d
\n
"
,
info
->
line
,
info
->
count
);
#endif
if
((
tty
->
count
==
1
)
&&
(
info
->
count
!=
1
))
{
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. info->count should always
* be one in these conditions. If it's greater than
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
printk
(
"sab82532_close: bad serial port count; tty->count is 1,"
" info->count is %d
\n
"
,
info
->
count
);
info
->
count
=
1
;
}
if
(
--
info
->
count
<
0
)
{
printk
(
"sab82532_close: bad serial port count for ttys%d: %d
\n
"
,
info
->
line
,
info
->
count
);
info
->
count
=
0
;
}
if
(
info
->
count
)
{
MOD_DEC_USE_COUNT
;
restore_flags
(
flags
);
return
;
}
info
->
flags
|=
ASYNC_CLOSING
;
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
*/
if
(
info
->
flags
&
ASYNC_NORMAL_ACTIVE
)
info
->
normal_termios
=
*
tty
->
termios
;
if
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
info
->
callout_termios
=
*
tty
->
termios
;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty
->
closing
=
1
;
if
(
info
->
closing_wait
!=
ASYNC_CLOSING_WAIT_NONE
)
tty_wait_until_sent
(
tty
,
info
->
closing_wait
);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and turn off
* the receiver.
*/
info
->
interrupt_mask0
|=
SAB82532_IMR0_TCD
;
writeb
(
info
->
interrupt_mask0
,
&
info
->
regs
->
w
.
imr0
);
if
(
info
->
flags
&
ASYNC_INITIALIZED
)
{
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
sab82532_wait_until_sent
(
tty
,
info
->
timeout
);
}
shutdown
(
info
);
if
(
tty
->
driver
.
flush_buffer
)
tty
->
driver
.
flush_buffer
(
tty
);
if
(
tty
->
ldisc
.
flush_buffer
)
tty
->
ldisc
.
flush_buffer
(
tty
);
tty
->
closing
=
0
;
info
->
event
=
0
;
info
->
tty
=
0
;
if
(
info
->
blocked_open
)
{
if
(
info
->
close_delay
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
info
->
close_delay
);
}
wake_up_interruptible
(
&
info
->
open_wait
);
}
info
->
flags
&=
~
(
ASYNC_NORMAL_ACTIVE
|
ASYNC_CALLOUT_ACTIVE
|
ASYNC_CLOSING
);
wake_up_interruptible
(
&
info
->
close_wait
);
MOD_DEC_USE_COUNT
;
restore_flags
(
flags
);
}
/*
* sab82532_wait_until_sent() --- wait until the transmitter is empty
*/
static
void
sab82532_wait_until_sent
(
struct
tty_struct
*
tty
,
int
timeout
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
unsigned
long
orig_jiffies
,
char_time
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_wait_until_sent"
))
return
;
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
* interval should also be less than the timeout.
*
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
char_time
=
(
info
->
timeout
-
HZ
/
50
)
/
info
->
xmit_fifo_size
;
char_time
=
char_time
/
5
;
if
(
char_time
==
0
)
char_time
=
1
;
if
(
timeout
)
char_time
=
MIN
(
char_time
,
timeout
);
#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT
printk
(
"In sab82532_wait_until_sent(%d) check=%lu "
"xmit_cnt = %ld, alls = %d (jiff=%lu)...
\n
"
,
timeout
,
char_time
,
CIRC_CNT
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
),
test_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
),
jiffies
);
#endif
orig_jiffies
=
jiffies
;
while
((
info
->
xmit
.
head
!=
info
->
xmit
.
tail
)
||
!
test_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
))
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
char_time
);
if
(
signal_pending
(
current
))
break
;
if
(
timeout
&&
time_after
(
jiffies
,
orig_jiffies
+
timeout
))
break
;
}
#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT
printk
(
"xmit_cnt = %ld, alls = %d (jiff=%lu)...done
\n
"
,
CIRC_CNT
(
info
->
xmit
.
head
,
info
->
xmit
.
tail
,
SERIAL_XMIT_SIZE
),
test_bit
(
SAB82532_ALLS
,
&
info
->
irqflags
),
jiffies
);
#endif
}
/*
* sab82532_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
static
void
sab82532_hangup
(
struct
tty_struct
*
tty
)
{
struct
sab82532
*
info
=
(
struct
sab82532
*
)
tty
->
driver_data
;
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_hangup"
))
return
;
#ifdef CONFIG_SERIAL_CONSOLE
if
(
info
->
is_console
)
return
;
#endif
sab82532_flush_buffer
(
tty
);
shutdown
(
info
);
info
->
event
=
0
;
info
->
count
=
0
;
info
->
flags
&=
~
(
ASYNC_NORMAL_ACTIVE
|
ASYNC_CALLOUT_ACTIVE
);
info
->
tty
=
0
;
wake_up_interruptible
(
&
info
->
open_wait
);
}
/*
* ------------------------------------------------------------
* sab82532_open() and friends
* ------------------------------------------------------------
*/
static
int
block_til_ready
(
struct
tty_struct
*
tty
,
struct
file
*
filp
,
struct
sab82532
*
info
)
{
DECLARE_WAITQUEUE
(
wait
,
current
);
int
retval
;
int
do_clocal
=
0
;
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
if
(
tty_hung_up_p
(
filp
)
||
(
info
->
flags
&
ASYNC_CLOSING
))
{
if
(
info
->
flags
&
ASYNC_CLOSING
)
interruptible_sleep_on
(
&
info
->
close_wait
);
#ifdef SERIAL_DO_RESTART
if
(
info
->
flags
&
ASYNC_HUP_NOTIFY
)
return
-
EAGAIN
;
else
return
-
ERESTARTSYS
;
#else
return
-
EAGAIN
;
#endif
}
/*
* If this is a callout device, then just make sure the normal
* device isn't being used.
*/
if
(
tty
->
driver
.
subtype
==
SERIAL_TYPE_CALLOUT
)
{
if
(
info
->
flags
&
ASYNC_NORMAL_ACTIVE
)
return
-
EBUSY
;
if
((
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
(
info
->
flags
&
ASYNC_SESSION_LOCKOUT
)
&&
(
info
->
session
!=
current
->
session
))
return
-
EBUSY
;
if
((
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
(
info
->
flags
&
ASYNC_PGRP_LOCKOUT
)
&&
(
info
->
pgrp
!=
current
->
pgrp
))
return
-
EBUSY
;
info
->
flags
|=
ASYNC_CALLOUT_ACTIVE
;
return
0
;
}
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if
((
filp
->
f_flags
&
O_NONBLOCK
)
||
(
tty
->
flags
&
(
1
<<
TTY_IO_ERROR
)))
{
if
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
return
-
EBUSY
;
info
->
flags
|=
ASYNC_NORMAL_ACTIVE
;
return
0
;
}
if
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
{
if
(
info
->
normal_termios
.
c_cflag
&
CLOCAL
)
do_clocal
=
1
;
}
else
{
if
(
tty
->
termios
->
c_cflag
&
CLOCAL
)
do_clocal
=
1
;
}
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
* this loop, info->count is dropped by one, so that
* sab82532_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval
=
0
;
add_wait_queue
(
&
info
->
open_wait
,
&
wait
);
#ifdef SERIAL_DEBUG_OPEN
printk
(
"block_til_ready before block: ttyS%d, count = %d
\n
"
,
info
->
line
,
info
->
count
);
#endif
cli
();
if
(
!
tty_hung_up_p
(
filp
))
info
->
count
--
;
sti
();
info
->
blocked_open
++
;
while
(
1
)
{
cli
();
if
(
!
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
(
tty
->
termios
->
c_cflag
&
CBAUD
))
{
writeb
(
readb
(
&
info
->
regs
->
rw
.
pvr
)
&
~
(
info
->
pvr_dtr_bit
),
&
info
->
regs
->
rw
.
pvr
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
&
~
(
SAB82532_MODE_RTS
),
&
info
->
regs
->
rw
.
mode
);
}
sti
();
set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
tty_hung_up_p
(
filp
)
||
!
(
info
->
flags
&
ASYNC_INITIALIZED
))
{
#ifdef SERIAL_DO_RESTART
if
(
info
->
flags
&
ASYNC_HUP_NOTIFY
)
retval
=
-
EAGAIN
;
else
retval
=
-
ERESTARTSYS
;
#else
retval
=
-
EAGAIN
;
#endif
break
;
}
if
(
!
(
info
->
flags
&
ASYNC_CALLOUT_ACTIVE
)
&&
!
(
info
->
flags
&
ASYNC_CLOSING
)
&&
(
do_clocal
||
!
(
readb
(
&
info
->
regs
->
r
.
vstr
)
&
SAB82532_VSTR_CD
)))
break
;
if
(
signal_pending
(
current
))
{
retval
=
-
ERESTARTSYS
;
break
;
}
#ifdef SERIAL_DEBUG_OPEN
printk
(
"block_til_ready blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x
\n
"
,
info
->
line
,
info
->
count
,
info
->
flags
,
do_clocal
,
readb
(
&
info
->
regs
->
r
.
vstr
));
#endif
schedule
();
}
current
->
state
=
TASK_RUNNING
;
remove_wait_queue
(
&
info
->
open_wait
,
&
wait
);
if
(
!
tty_hung_up_p
(
filp
))
info
->
count
++
;
info
->
blocked_open
--
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"block_til_ready after blocking: ttys%d, count = %d
\n
"
,
info
->
line
,
info
->
count
);
#endif
if
(
retval
)
return
retval
;
info
->
flags
|=
ASYNC_NORMAL_ACTIVE
;
return
0
;
}
/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its async structure into
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
static
int
sab82532_open
(
struct
tty_struct
*
tty
,
struct
file
*
filp
)
{
struct
sab82532
*
info
=
sab82532_chain
;
int
retval
,
line
;
unsigned
long
page
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"sab82532_open: count = %d
\n
"
,
info
->
count
);
#endif
line
=
minor
(
tty
->
device
)
-
tty
->
driver
.
minor_start
;
if
((
line
<
0
)
||
(
line
>=
NR_PORTS
))
return
-
ENODEV
;
while
(
info
)
{
if
(
info
->
line
==
line
)
break
;
info
=
info
->
next
;
}
if
(
!
info
)
{
printk
(
"sab82532_open: can't find info for line %d
\n
"
,
line
);
return
-
ENODEV
;
}
if
(
serial_paranoia_check
(
info
,
tty
->
device
,
"sab82532_open"
))
return
-
ENODEV
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"sab82532_open %s%d, count = %d
\n
"
,
tty
->
driver
.
name
,
info
->
line
,
info
->
count
);
#endif
if
(
!
tmp_buf
)
{
page
=
get_free_page
(
GFP_KERNEL
);
if
(
!
page
)
return
-
ENOMEM
;
if
(
tmp_buf
)
free_page
(
page
);
else
tmp_buf
=
(
unsigned
char
*
)
page
;
}
info
->
count
++
;
tty
->
driver_data
=
info
;
info
->
tty
=
tty
;
/*
* If the port is in the middle of closing, bail out now.
*/
if
(
tty_hung_up_p
(
filp
)
||
(
info
->
flags
&
ASYNC_CLOSING
))
{
if
(
info
->
flags
&
ASYNC_CLOSING
)
interruptible_sleep_on
(
&
info
->
close_wait
);
#ifdef SERIAL_DO_RESTART
return
((
info
->
flags
&
ASYNC_HUP_NOTIFY
)
?
-
EAGAIN
:
-
ERESTARTSYS
);
#else
return
-
EAGAIN
;
#endif
}
/*
* Start up serial port
*/
retval
=
startup
(
info
);
if
(
retval
)
return
retval
;
MOD_INC_USE_COUNT
;
retval
=
block_til_ready
(
tty
,
filp
,
info
);
if
(
retval
)
{
#ifdef SERIAL_DEBUG_OPEN
printk
(
"sab82532_open returning after block_til_ready with %d
\n
"
,
retval
);
#endif
return
retval
;
}
if
((
info
->
count
==
1
)
&&
(
info
->
flags
&
ASYNC_SPLIT_TERMIOS
))
{
if
(
tty
->
driver
.
subtype
==
SERIAL_TYPE_NORMAL
)
*
tty
->
termios
=
info
->
normal_termios
;
else
*
tty
->
termios
=
info
->
callout_termios
;
change_speed
(
info
);
}
#ifdef CONFIG_SERIAL_CONSOLE
if
(
sab82532_console
.
cflag
&&
sab82532_console
.
index
==
line
)
{
tty
->
termios
->
c_cflag
=
sab82532_console
.
cflag
;
sab82532_console
.
cflag
=
0
;
change_speed
(
info
);
}
#endif
info
->
session
=
current
->
session
;
info
->
pgrp
=
current
->
pgrp
;
#ifdef SERIAL_DEBUG_OPEN
printk
(
"sab82532_open ttys%d successful... count %d"
,
info
->
line
,
info
->
count
);
#endif
return
0
;
}
}
/*
static
void
__init
sab_attach_callback
(
struct
linux_ebus_device
*
edev
,
void
*
arg
)
* /proc fs routines....
*/
static
__inline__
int
line_info
(
char
*
buf
,
struct
sab82532
*
info
)
{
unsigned
long
flags
;
char
stat_buf
[
30
];
int
ret
;
ret
=
sprintf
(
buf
,
"%u: uart:SAB82532 "
,
info
->
line
);
switch
(
info
->
type
)
{
case
0
:
ret
+=
sprintf
(
buf
+
ret
,
"V1.0 "
);
break
;
case
1
:
ret
+=
sprintf
(
buf
+
ret
,
"V2.0 "
);
break
;
case
2
:
ret
+=
sprintf
(
buf
+
ret
,
"V3.2 "
);
break
;
default:
ret
+=
sprintf
(
buf
+
ret
,
"V?.? "
);
break
;
}
ret
+=
sprintf
(
buf
+
ret
,
"port:%lX irq:%s"
,
(
unsigned
long
)
info
->
regs
,
__irq_itoa
(
info
->
irq
));
if
(
!
info
->
regs
)
{
ret
+=
sprintf
(
buf
+
ret
,
"
\n
"
);
return
ret
;
}
/*
* Figure out the current RS-232 lines
*/
stat_buf
[
0
]
=
0
;
stat_buf
[
1
]
=
0
;
save_flags
(
flags
);
cli
();
if
(
readb
(
&
info
->
regs
->
r
.
mode
)
&
SAB82532_MODE_RTS
)
{
if
(
!
(
readb
(
&
info
->
regs
->
r
.
mode
)
&
SAB82532_MODE_FRTS
))
strcat
(
stat_buf
,
"|RTS"
);
}
else
{
strcat
(
stat_buf
,
"|RTS"
);
}
if
(
readb
(
&
info
->
regs
->
r
.
star
)
&
SAB82532_STAR_CTS
)
strcat
(
stat_buf
,
"|CTS"
);
if
(
!
(
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dtr_bit
))
strcat
(
stat_buf
,
"|DTR"
);
if
(
!
(
readb
(
&
info
->
regs
->
r
.
pvr
)
&
info
->
pvr_dsr_bit
))
strcat
(
stat_buf
,
"|DSR"
);
if
(
!
(
readb
(
&
info
->
regs
->
r
.
vstr
)
&
SAB82532_VSTR_CD
))
strcat
(
stat_buf
,
"|CD"
);
restore_flags
(
flags
);
if
(
info
->
baud
)
ret
+=
sprintf
(
buf
+
ret
,
" baud:%u"
,
info
->
baud
);
ret
+=
sprintf
(
buf
+
ret
,
" tx:%u rx:%u"
,
info
->
icount
.
tx
,
info
->
icount
.
rx
);
if
(
info
->
icount
.
frame
)
ret
+=
sprintf
(
buf
+
ret
,
" fe:%u"
,
info
->
icount
.
frame
);
if
(
info
->
icount
.
parity
)
ret
+=
sprintf
(
buf
+
ret
,
" pe:%u"
,
info
->
icount
.
parity
);
if
(
info
->
icount
.
brk
)
ret
+=
sprintf
(
buf
+
ret
,
" brk:%u"
,
info
->
icount
.
brk
);
if
(
info
->
icount
.
overrun
)
ret
+=
sprintf
(
buf
+
ret
,
" oe:%u"
,
info
->
icount
.
overrun
);
/*
* Last thing is the RS-232 status lines.
*/
ret
+=
sprintf
(
buf
+
ret
,
" %s
\n
"
,
stat_buf
+
1
);
return
ret
;
}
int
sab82532_read_proc
(
char
*
page
,
char
**
start
,
off_t
off
,
int
count
,
int
*
eof
,
void
*
data
)
{
struct
sab82532
*
info
=
sab82532_chain
;
off_t
begin
=
0
;
int
len
=
0
;
len
+=
sprintf
(
page
,
"serinfo:1.0 driver:%s
\n
"
,
serial_version
);
for
(
info
=
sab82532_chain
;
info
&&
len
<
4000
;
info
=
info
->
next
)
{
len
+=
line_info
(
page
+
len
,
info
);
if
(
len
+
begin
>
off
+
count
)
goto
done
;
if
(
len
+
begin
<
off
)
{
begin
+=
len
;
len
=
0
;
}
}
*
eof
=
1
;
done:
if
(
off
>=
len
+
begin
)
return
0
;
*
start
=
page
+
(
off
-
begin
);
return
((
count
<
begin
+
len
-
off
)
?
count
:
begin
+
len
-
off
);
}
/*
* ---------------------------------------------------------------------
* sab82532_init() and friends
*
* sab82532_init() is called at boot-time to initialize the serial driver.
* ---------------------------------------------------------------------
*/
static
int
__init
get_sab82532
(
unsigned
long
*
memory_start
)
{
{
struct
linux_ebus
*
ebus
;
int
*
instance_p
=
arg
;
struct
linux_ebus_device
*
edev
=
0
;
struct
uart_sunsab_port
*
up
;
struct
sab82532
*
sab
;
unsigned
long
regs
,
offset
;
unsigned
long
regs
,
offset
;
int
i
;
int
i
;
for_each_ebus
(
ebus
)
{
for_each_ebusdev
(
edev
,
ebus
)
{
if
(
!
strcmp
(
edev
->
prom_name
,
"se"
))
goto
ebus_done
;
if
(
!
strcmp
(
edev
->
prom_name
,
"serial"
))
{
char
compat
[
32
];
int
clen
;
/* On RIO this can be an SE, check it. We could
* just check ebus->is_rio, but this is more portable.
*/
clen
=
prom_getproperty
(
edev
->
prom_node
,
"compatible"
,
compat
,
sizeof
(
compat
));
if
(
clen
>
0
)
{
if
(
strncmp
(
compat
,
"sab82532"
,
8
)
==
0
)
{
/* Yep. */
goto
ebus_done
;
}
}
}
}
}
ebus_done:
if
(
!
edev
)
return
-
ENODEV
;
regs
=
edev
->
resource
[
0
].
start
;
regs
=
edev
->
resource
[
0
].
start
;
offset
=
sizeof
(
union
sab82532_async_regs
);
offset
=
sizeof
(
union
sab82532_async_regs
);
for
(
i
=
0
;
i
<
2
;
i
++
)
{
for
(
i
=
0
;
i
<
2
;
i
++
)
{
if
(
memory_start
)
{
up
=
&
sunsab_ports
[(
*
instance_p
*
2
)
+
i
];
*
memory_start
=
(
*
memory_start
+
7
)
&
~
(
7
);
sab
=
(
struct
sab82532
*
)
*
memory_start
;
*
memory_start
+=
sizeof
(
struct
sab82532
);
}
else
{
sab
=
(
struct
sab82532
*
)
kmalloc
(
sizeof
(
struct
sab82532
),
GFP_KERNEL
);
if
(
!
sab
)
{
printk
(
"sab82532: can't alloc sab struct
\n
"
);
break
;
}
}
memset
(
sab
,
0
,
sizeof
(
struct
sab82532
));
sab
->
regs
=
ioremap
(
regs
+
offset
,
sizeof
(
union
sab82532_async_regs
));
sab
->
irq
=
edev
->
irqs
[
0
];
sab
->
line
=
1
-
i
;
sab
->
xmit_fifo_size
=
32
;
sab
->
recv_fifo_size
=
32
;
writeb
(
SAB82532_IPC_IC_ACT_LOW
,
&
sab
->
regs
->
w
.
ipc
);
memset
(
up
,
0
,
sizeof
(
*
up
));
up
->
regs
=
ioremap
(
regs
+
offset
,
sizeof
(
union
sab82532_async_regs
));
up
->
irq
=
edev
->
irqs
[
0
];
up
->
sab_line
=
1
-
i
;
up
->
xmit_fifo_size
=
32
;
up
->
recv_fifo_size
=
32
;
sab
->
next
=
sab82532_chain
;
writeb
(
SAB82532_IPC_IC_ACT_LOW
,
&
up
->
regs
->
w
.
ipc
);
sab82532_chain
=
sab
;
offset
-=
sizeof
(
union
sab82532_async_regs
);
offset
-=
sizeof
(
union
sab82532_async_regs
);
}
}
return
0
;
}
}
#ifndef MODULE
static
int
__init
probe_for_sabs
(
void
)
static
void
__init
sab82532_kgdb_hook
(
int
line
)
{
{
prom_printf
(
"sab82532: kgdb support is not implemented, yet
\n
"
);
int
this_sab
=
0
;
prom_halt
();
}
#endif
static
inline
void
__init
show_serial_version
(
void
)
{
char
*
revision
=
"$Revision: 1.66 $"
;
char
*
version
,
*
p
;
version
=
strchr
(
revision
,
' '
);
strcpy
(
serial_version
,
++
version
);
p
=
strchr
(
serial_version
,
' '
);
*
p
=
'\0'
;
printk
(
"SAB82532 serial driver version %s
\n
"
,
serial_version
);
}
extern
int
su_num_ports
;
/*
/* Find device instances. */
* The serial driver boot-time initialization code!
for_each_sab_edev
(
&
sab_count_callback
,
&
this_sab
);
*/
if
(
!
this_sab
)
int
__init
sab82532_init
(
void
)
{
struct
sab82532
*
info
;
int
i
;
if
(
!
sab82532_chain
)
get_sab82532
(
0
);
if
(
!
sab82532_chain
)
return
-
ENODEV
;
return
-
ENODEV
;
init_bh
(
SERIAL_BH
,
do_serial_bh
);
/* Allocate tables. */
sunsab_ports
=
kmalloc
(
sizeof
(
struct
uart_sunsab_port
)
*
this_sab
*
2
,
show_serial_version
();
GFP_KERNEL
);
if
(
!
sunsab_ports
)
/* Initialize the tty_driver structure */
return
-
ENOMEM
;
memset
(
&
serial_driver
,
0
,
sizeof
(
struct
tty_driver
));
serial_driver
.
magic
=
TTY_DRIVER_MAGIC
;
serial_driver
.
driver_name
=
"serial"
;
#ifdef CONFIG_DEVFS_FS
serial_driver
.
name
=
"tts/%d"
;
#else
serial_driver
.
name
=
"ttyS"
;
#endif
serial_driver
.
major
=
TTY_MAJOR
;
serial_driver
.
minor_start
=
64
+
su_num_ports
;
serial_driver
.
num
=
NR_PORTS
;
serial_driver
.
type
=
TTY_DRIVER_TYPE_SERIAL
;
serial_driver
.
subtype
=
SERIAL_TYPE_NORMAL
;
serial_driver
.
init_termios
=
tty_std_termios
;
serial_driver
.
init_termios
.
c_cflag
=
B9600
|
CS8
|
CREAD
|
HUPCL
|
CLOCAL
;
serial_driver
.
flags
=
TTY_DRIVER_REAL_RAW
;
serial_driver
.
refcount
=
&
sab82532_refcount
;
serial_driver
.
table
=
sab82532_table
;
serial_driver
.
termios
=
sab82532_termios
;
serial_driver
.
termios_locked
=
sab82532_termios_locked
;
serial_driver
.
open
=
sab82532_open
;
serial_driver
.
close
=
sab82532_close
;
serial_driver
.
write
=
sab82532_write
;
serial_driver
.
put_char
=
sab82532_put_char
;
serial_driver
.
flush_chars
=
sab82532_flush_chars
;
serial_driver
.
write_room
=
sab82532_write_room
;
serial_driver
.
chars_in_buffer
=
sab82532_chars_in_buffer
;
serial_driver
.
flush_buffer
=
sab82532_flush_buffer
;
serial_driver
.
ioctl
=
sab82532_ioctl
;
serial_driver
.
throttle
=
sab82532_throttle
;
serial_driver
.
unthrottle
=
sab82532_unthrottle
;
serial_driver
.
send_xchar
=
sab82532_send_xchar
;
serial_driver
.
set_termios
=
sab82532_set_termios
;
serial_driver
.
stop
=
sab82532_stop
;
serial_driver
.
start
=
sab82532_start
;
serial_driver
.
hangup
=
sab82532_hangup
;
serial_driver
.
break_ctl
=
sab82532_break
;
serial_driver
.
wait_until_sent
=
sab82532_wait_until_sent
;
serial_driver
.
read_proc
=
sab82532_read_proc
;
/*
* The callout device is just like normal device except for
* major number and the subtype code.
*/
callout_driver
=
serial_driver
;
#ifdef CONFIG_DEVFS_FS
callout_driver
.
name
=
"cua/%d"
;
#else
callout_driver
.
name
=
"cua"
;
#endif
callout_driver
.
major
=
TTYAUX_MAJOR
;
callout_driver
.
subtype
=
SERIAL_TYPE_CALLOUT
;
callout_driver
.
read_proc
=
0
;
callout_driver
.
proc_entry
=
0
;
if
(
tty_register_driver
(
&
serial_driver
))
panic
(
"Couldn't register serial driver
\n
"
);
if
(
tty_register_driver
(
&
callout_driver
))
panic
(
"Couldn't register callout driver
\n
"
);
for
(
info
=
sab82532_chain
,
i
=
0
;
info
;
info
=
info
->
next
,
i
++
)
{
info
->
magic
=
SERIAL_MAGIC
;
info
->
type
=
readb
(
&
info
->
regs
->
r
.
vstr
)
&
0x0f
;
writeb
(
~
((
1
<<
1
)
|
(
1
<<
2
)
|
(
1
<<
4
)),
&
info
->
regs
->
w
.
pcr
);
writeb
(
0xff
,
&
info
->
regs
->
w
.
pim
);
if
(
info
->
line
==
0
)
{
info
->
pvr_dsr_bit
=
(
1
<<
0
);
info
->
pvr_dtr_bit
=
(
1
<<
1
);
}
else
{
info
->
pvr_dsr_bit
=
(
1
<<
3
);
info
->
pvr_dtr_bit
=
(
1
<<
2
);
}
writeb
((
1
<<
1
)
|
(
1
<<
2
)
|
(
1
<<
4
),
&
info
->
regs
->
w
.
pvr
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
info
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
info
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
info
->
regs
->
rw
.
mode
);
info
->
custom_divisor
=
16
;
info
->
close_delay
=
5
*
HZ
/
10
;
info
->
closing_wait
=
30
*
HZ
;
info
->
tec_timeout
=
SAB82532_MAX_TEC_TIMEOUT
;
info
->
cec_timeout
=
SAB82532_MAX_CEC_TIMEOUT
;
info
->
x_char
=
0
;
info
->
event
=
0
;
info
->
blocked_open
=
0
;
info
->
tqueue
.
routine
=
do_softint
;
info
->
tqueue
.
data
=
info
;
info
->
tqueue_hangup
.
routine
=
do_serial_hangup
;
info
->
tqueue_hangup
.
data
=
info
;
info
->
callout_termios
=
callout_driver
.
init_termios
;
info
->
normal_termios
=
serial_driver
.
init_termios
;
init_waitqueue_head
(
&
info
->
open_wait
);
init_waitqueue_head
(
&
info
->
close_wait
);
init_waitqueue_head
(
&
info
->
delta_msr_wait
);
info
->
icount
.
cts
=
info
->
icount
.
dsr
=
info
->
icount
.
rng
=
info
->
icount
.
dcd
=
0
;
info
->
icount
.
rx
=
info
->
icount
.
tx
=
0
;
info
->
icount
.
frame
=
info
->
icount
.
parity
=
0
;
info
->
icount
.
overrun
=
info
->
icount
.
brk
=
0
;
if
(
!
(
info
->
line
&
0x01
))
{
if
(
request_irq
(
info
->
irq
,
sab82532_interrupt
,
SA_SHIRQ
,
"serial(sab82532)"
,
info
))
{
printk
(
"sab82532: can't get IRQ %x
\n
"
,
info
->
irq
);
panic
(
"sab82532 initialization failed"
);
}
}
printk
(
KERN_INFO
num_channels
=
this_sab
*
2
;
"ttyS%02d at 0x%lx (irq = %s) is a SAB82532 %s
\n
"
,
info
->
line
+
su_num_ports
,
(
unsigned
long
)
info
->
regs
,
__irq_itoa
(
info
->
irq
),
sab82532_version
[
info
->
type
]);
}
#ifdef SERIAL_LOG_DEVICE
this_sab
=
0
;
dprint_init
(
SERIAL_LOG_DEVICE
);
for_each_sab_edev
(
&
sab_attach_callback
,
&
this_sab
);
#endif
return
0
;
return
0
;
}
}
int
__init
sab82532_probe
(
void
)
static
void
__init
sunsab_init_hw
(
void
)
{
{
int
node
,
enode
,
snode
;
int
i
;
char
model
[
32
];
int
len
;
node
=
prom_getchild
(
prom_root_node
);
node
=
prom_searchsiblings
(
node
,
"pci"
);
/*
* Check for SUNW,sabre on Ultra 5/10/AXi.
*/
len
=
prom_getproperty
(
node
,
"model"
,
model
,
sizeof
(
model
));
if
((
len
>
0
)
&&
!
strncmp
(
model
,
"SUNW,sabre"
,
len
))
{
node
=
prom_getchild
(
node
);
node
=
prom_searchsiblings
(
node
,
"pci"
);
}
/*
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
* For each PCI bus...
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
i
];
*/
while
(
node
)
{
enode
=
prom_getchild
(
node
);
enode
=
prom_searchsiblings
(
enode
,
"ebus"
);
/*
up
->
port
.
line
=
i
;
* For each EBus on this PCI...
up
->
port
.
ops
=
&
sunsab_pops
;
*/
up
->
port
.
type
=
PORT_SUNSAB
;
while
(
enode
)
{
up
->
port
.
uartclk
=
SAB_BASE_BAUD
;
int
child
;
child
=
prom_getchild
(
enode
);
up
->
type
=
readb
(
&
up
->
regs
->
r
.
vstr
)
&
0x0f
;
snode
=
prom_searchsiblings
(
child
,
"se"
);
writeb
(
~
((
1
<<
1
)
|
(
1
<<
2
)
|
(
1
<<
4
)),
&
up
->
regs
->
w
.
pcr
);
if
(
snode
)
writeb
(
0xff
,
&
up
->
regs
->
w
.
pim
);
goto
found
;
if
(
up
->
sab_line
==
0
)
{
up
->
pvr_dsr_bit
=
(
1
<<
0
);
up
->
pvr_dtr_bit
=
(
1
<<
1
);
}
else
{
up
->
pvr_dsr_bit
=
(
1
<<
3
);
up
->
pvr_dtr_bit
=
(
1
<<
2
);
}
writeb
((
1
<<
1
)
|
(
1
<<
2
)
|
(
1
<<
4
),
&
up
->
regs
->
w
.
pvr
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_FRTS
,
&
up
->
regs
->
rw
.
mode
);
writeb
(
readb
(
&
up
->
regs
->
rw
.
mode
)
|
SAB82532_MODE_RTS
,
&
up
->
regs
->
rw
.
mode
);
snode
=
prom_searchsiblings
(
child
,
"serial"
);
up
->
tec_timeout
=
SAB82532_MAX_TEC_TIMEOUT
;
if
(
snode
)
{
up
->
cec_timeout
=
SAB82532_MAX_CEC_TIMEOUT
;
char
compat
[
32
];
int
clen
;
clen
=
prom_getproperty
(
snode
,
"compatible"
,
if
(
!
(
up
->
sab_line
&
0x01
))
{
compat
,
sizeof
(
compat
));
if
(
request_irq
(
up
->
irq
,
sunsab_interrupt
,
SA_SHIRQ
,
if
(
clen
>
0
)
{
"serial(sab82532)"
,
up
))
{
if
(
strncmp
(
compat
,
"sab82532"
,
8
)
==
0
)
printk
(
"sunsab%d: can't get IRQ %x
\n
"
,
goto
found
;
i
,
up
->
irq
);
continue
;
}
}
}
}
enode
=
prom_getsibling
(
enode
);
printk
(
KERN_INFO
enode
=
prom_searchsiblings
(
enode
,
"ebus"
);
"sunsab%d at 0x%lx (irq = %s) is a SAB82532 %s
\n
"
,
}
i
,
(
unsigned
long
)
up
->
regs
,
node
=
prom_getsibling
(
node
);
__irq_itoa
(
up
->
irq
),
sab82532_version
[
up
->
type
]);
node
=
prom_searchsiblings
(
node
,
"pci"
);
}
}
return
-
ENODEV
;
found:
#ifdef CONFIG_SERIAL_CONSOLE
sunserial_setinitfunc
(
sab82532_console_init
);
#endif
#ifndef MODULE
sunserial_setinitfunc
(
sab82532_init
);
rs_ops
.
rs_kgdb_hook
=
sab82532_kgdb_hook
;
#endif
return
0
;
}
}
#ifdef MODULE
static
int
__init
sunsab_init
(
void
)
MODULE_LICENSE
(
"GPL"
);
int
init_module
(
void
)
{
{
i
f
(
get_sab82532
(
0
))
i
nt
ret
=
probe_for_sabs
();
return
-
ENODEV
;
int
i
;
return
sab82532_init
();
if
(
ret
<
0
)
}
return
ret
;
void
cleanup_module
(
void
)
sunsab_init_hw
();
{
struct
sab82532
*
sab
;
unsigned
long
flags
;
int
e1
,
e2
;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
save_flags
(
flags
);
cli
();
remove_bh
(
SERIAL_BH
);
if
((
e1
=
tty_unregister_driver
(
&
serial_driver
)))
printk
(
"SERIAL: failed to unregister serial driver (%d)
\n
"
,
e1
);
if
((
e2
=
tty_unregister_driver
(
&
callout_driver
)))
printk
(
"SERIAL: failed to unregister callout driver (%d)
\n
"
,
e2
);
restore_flags
(
flags
);
if
(
tmp_buf
)
{
free_page
((
unsigned
long
)
tmp_buf
);
tmp_buf
=
NULL
;
}
for
(
sab
=
sab82532_chain
;
sab
;
sab
=
sab
->
next
)
{
if
(
!
(
sab
->
line
&
0x01
))
free_irq
(
sab
->
irq
,
sab
);
iounmap
(
sab
->
regs
);
}
}
#endif
/* MODULE */
#ifdef CONFIG_SERIAL_CONSOLE
sunsab_reg
.
minor
=
sunserial_current_minor
;
static
__inline__
void
sunserial_current_minor
+=
num_channels
;
sab82532_console_putchar
(
struct
sab82532
*
info
,
char
c
)
{
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
sunsab_reg
.
nr
=
num_channels
;
sab82532_tec_wait
(
info
);
sunsab_reg
.
cons
=
&
sunsab_console
;
writeb
(
c
,
&
info
->
regs
->
w
.
tic
);
restore_flags
(
flags
);
}
static
void
ret
=
uart_register_driver
(
&
sunsab_reg
);
sab82532_console_write
(
struct
console
*
con
,
const
char
*
s
,
unsigned
n
)
if
(
ret
<
0
)
{
{
struct
sab82532
*
info
;
int
i
;
int
i
;
info
=
sab82532_chain
;
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
for
(
i
=
con
->
index
;
i
;
i
--
)
{
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
i
];
info
=
info
->
next
;
if
(
!
info
)
return
;
}
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
!
(
up
->
sab_line
&
0x01
))
if
(
*
s
==
'\n'
)
free_irq
(
up
->
irq
,
up
);
sab82532_console_putchar
(
info
,
'\r'
);
iounmap
(
up
->
regs
);
sab82532_console_putchar
(
info
,
*
s
++
);
}
}
sab82532_tec_wait
(
info
);
kfree
(
sunsab_ports
);
}
sunsab_ports
=
NULL
;
static
kdev_t
sab82532_console_device
(
struct
console
*
con
)
{
return
mk_kdev
(
TTY_MAJOR
,
64
+
con
->
index
);
}
static
int
sab82532_console_setup
(
struct
console
*
con
,
char
*
options
)
{
static
struct
tty_struct
c_tty
;
static
struct
termios
c_termios
;
struct
sab82532
*
info
;
tcflag_t
cflag
;
int
i
;
info
=
sab82532_chain
;
return
ret
;
for
(
i
=
con
->
index
;
i
;
i
--
)
{
info
=
info
->
next
;
if
(
!
info
)
return
-
ENODEV
;
}
}
info
->
is_console
=
1
;
/*
* Initialize the hardware
*/
sab82532_init_line
(
info
);
/*
* Finally, enable interrupts
*/
info
->
interrupt_mask0
=
SAB82532_IMR0_PERR
|
SAB82532_IMR0_FERR
|
SAB82532_IMR0_PLLA
|
SAB82532_IMR0_CDSC
;
writeb
(
info
->
interrupt_mask0
,
&
info
->
regs
->
w
.
imr0
);
info
->
interrupt_mask1
=
SAB82532_IMR1_BRKT
|
SAB82532_IMR1_ALLS
|
SAB82532_IMR1_XOFF
|
SAB82532_IMR1_TIN
|
SAB82532_IMR1_CSC
|
SAB82532_IMR1_XON
|
SAB82532_IMR1_XPR
;
writeb
(
info
->
interrupt_mask1
,
&
info
->
regs
->
w
.
imr1
);
printk
(
"Console: ttyS%d (SAB82532)
\n
"
,
info
->
line
);
sunserial_console_termios
(
con
);
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
cflag
=
con
->
cflag
;
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
i
]
;
/*
uart_add_one_port
(
&
sunsab_reg
,
&
up
->
port
);
* Fake up the tty and tty->termios structures so we can use
* change_speed (and eliminate a lot of duplicate code).
*/
if
(
!
info
->
tty
)
{
memset
(
&
c_tty
,
0
,
sizeof
(
c_tty
));
info
->
tty
=
&
c_tty
;
}
if
(
!
info
->
tty
->
termios
)
{
memset
(
&
c_termios
,
0
,
sizeof
(
c_termios
));
info
->
tty
->
termios
=
&
c_termios
;
}
}
info
->
tty
->
termios
->
c_cflag
=
con
->
cflag
;
change_speed
(
info
);
sunsab_console_init
();
/* Now take out the pointers to static structures if necessary */
if
(
info
->
tty
->
termios
==
&
c_termios
)
info
->
tty
->
termios
=
0
;
if
(
info
->
tty
==
&
c_tty
)
info
->
tty
=
0
;
return
0
;
return
0
;
}
}
static
struct
console
sab82532_console
=
{
static
void
__exit
sunsab_exit
(
void
)
.
name
=
"ttyS"
,
.
write
=
sab82532_console_write
,
.
device
=
sab82532_console_device
,
.
setup
=
sab82532_console_setup
,
.
flags
=
CON_PRINTBUFFER
,
.
index
=
-
1
,
};
int
__init
sab82532_console_init
(
void
)
{
{
extern
int
su_console_registered
;
int
i
;
if
(
con_is_present
()
||
su_console_registered
)
for
(
i
=
0
;
i
<
num_channels
;
i
++
)
{
return
0
;
struct
uart_sunsab_port
*
up
=
&
sunsab_ports
[
i
]
;
if
(
!
sab82532_chain
)
{
uart_remove_one_port
(
&
sunsab_reg
,
&
up
->
port
);
prom_printf
(
"sab82532_console_setup: can't get SAB82532 chain"
);
prom_halt
();
}
sab82532_console
.
index
=
serial_console
-
1
;
if
(
!
(
up
->
sab_line
&
0x01
))
register_console
(
&
sab82532_console
);
free_irq
(
up
->
irq
,
up
);
return
0
;
iounmap
(
up
->
regs
);
}
}
#ifdef SERIAL_LOG_DEVICE
static
int
serial_log_device
=
0
;
uart_unregister_driver
(
&
sunsab_reg
)
;
static
void
kfree
(
sunsab_ports
);
dprint_init
(
int
tty
)
sunsab_ports
=
NULL
;
{
serial_console
=
tty
+
1
;
sab82532_console
.
index
=
tty
;
sab82532_console_setup
(
&
sab82532_console
,
""
);
serial_console
=
0
;
serial_log_device
=
tty
+
1
;
}
}
int
module_init
(
sunsab_init
);
dprintf
(
const
char
*
fmt
,
...)
module_exit
(
sunsab_exit
);
{
static
char
buffer
[
4096
];
va_list
args
;
int
i
;
if
(
!
serial_log_device
)
return
0
;
va_start
(
args
,
fmt
);
MODULE_AUTHOR
(
"Eddie C. Dost and David S. Miller"
);
i
=
vsprintf
(
buffer
,
fmt
,
args
);
MODULE_DESCRIPTION
(
"Sun SAB82532 serial port driver"
);
va_end
(
args
);
MODULE_LICENSE
(
"GPL"
);
sab82532_console
.
write
(
&
sab82532_console
,
buffer
,
i
);
return
i
;
}
#endif
/* SERIAL_LOG_DEVICE */
#endif
/* CONFIG_SERIAL_CONSOLE */
include/asm-sparc64/sab82532
.h
→
drivers/serial/sunsab
.h
View file @
130ca59d
/* $Id: sab82532.h,v 1.7 2001/05/23 23:09:10 ecd Exp $
/* sunsab.h: Register Definitions for the Siemens SAB82532 DUSCC
* sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
*
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
*/
#ifndef _SPARC64_SAB82532_H
#ifndef _SUNSAB_H
#define _SPARC64_SAB82532_H
#define _SUNSAB_H
#include <linux/types.h>
#include <linux/serial.h>
#include <linux/circ_buf.h>
struct
sab82532_async_rd_regs
{
struct
sab82532_async_rd_regs
{
u8
rfifo
[
0x20
];
/* Receive FIFO */
u8
rfifo
[
0x20
];
/* Receive FIFO */
...
@@ -120,8 +115,6 @@ union sab82532_async_regs {
...
@@ -120,8 +115,6 @@ union sab82532_async_regs {
__volatile__
struct
sab82532_async_rw_regs
rw
;
__volatile__
struct
sab82532_async_rw_regs
rw
;
};
};
#define NR_PORTS 2
union
sab82532_irq_status
{
union
sab82532_irq_status
{
unsigned
short
stat
;
unsigned
short
stat
;
struct
{
struct
{
...
@@ -130,62 +123,10 @@ union sab82532_irq_status {
...
@@ -130,62 +123,10 @@ union sab82532_irq_status {
}
sreg
;
}
sreg
;
};
};
struct
sab82532
{
int
magic
;
int
baud_base
;
union
sab82532_async_regs
*
regs
;
int
irq
;
int
flags
;
/* defined in tty.h */
int
type
;
/* SAB82532 version */
struct
tty_struct
*
tty
;
int
read_status_mask
;
int
ignore_status_mask
;
int
timeout
;
int
xmit_fifo_size
;
int
recv_fifo_size
;
int
custom_divisor
;
int
baud
;
unsigned
int
cec_timeout
;
unsigned
int
tec_timeout
;
int
x_char
;
int
close_delay
;
unsigned
short
closing_wait
;
unsigned
short
closing_wait2
;
unsigned
long
irqflags
;
int
is_console
;
unsigned
char
interrupt_mask0
;
unsigned
char
interrupt_mask1
;
unsigned
char
pvr_dtr_bit
;
unsigned
char
pvr_dsr_bit
;
unsigned
char
dcd
;
unsigned
char
cts
;
unsigned
char
dsr
;
unsigned
long
event
;
unsigned
long
last_active
;
int
line
;
int
count
;
int
blocked_open
;
long
session
;
long
pgrp
;
struct
circ_buf
xmit
;
struct
tq_struct
tqueue
;
struct
tq_struct
tqueue_hangup
;
struct
async_icount
icount
;
struct
termios
normal_termios
;
struct
termios
callout_termios
;
wait_queue_head_t
open_wait
;
wait_queue_head_t
close_wait
;
wait_queue_head_t
delta_msr_wait
;
struct
sab82532
*
next
;
struct
sab82532
*
prev
;
};
/* irqflags bits */
/* irqflags bits */
#define SAB82532_ALLS 0x00000001
#define SAB82532_ALLS 0x00000001
#define SAB82532_XPR 0x00000002
#define SAB82532_XPR 0x00000002
/* RFIFO Status Byte */
/* RFIFO Status Byte */
#define SAB82532_RSTAT_PE 0x80
#define SAB82532_RSTAT_PE 0x80
#define SAB82532_RSTAT_FE 0x40
#define SAB82532_RSTAT_FE 0x40
...
@@ -377,4 +318,4 @@ struct sab82532 {
...
@@ -377,4 +318,4 @@ struct sab82532 {
#define SAB82532_CCR4_ICD 0x10
#define SAB82532_CCR4_ICD 0x10
#endif
/* !(_S
PARC64_SAB82532
_H) */
#endif
/* !(_S
UNSAB
_H) */
drivers/serial/sunsu.c
View file @
130ca59d
...
@@ -1362,7 +1362,7 @@ static void sunsu_console_write(struct console *co, const char *s,
...
@@ -1362,7 +1362,7 @@ static void sunsu_console_write(struct console *co, const char *s,
static
kdev_t
sunsu_console_device
(
struct
console
*
co
)
static
kdev_t
sunsu_console_device
(
struct
console
*
co
)
{
{
return
mk_kdev
(
TTY_MAJOR
,
64
+
co
->
index
);
return
mk_kdev
(
sunsu_reg
.
major
,
sunsu_reg
.
minor
+
co
->
index
);
}
}
/*
/*
...
@@ -1379,6 +1379,9 @@ static int __init sunsu_console_setup(struct console *co, char *options)
...
@@ -1379,6 +1379,9 @@ static int __init sunsu_console_setup(struct console *co, char *options)
int
parity
=
'n'
;
int
parity
=
'n'
;
int
flow
=
'n'
;
int
flow
=
'n'
;
printk
(
"Console: ttyS%d (SU)
\n
"
,
(
sunsu_reg
.
minor
-
64
)
+
co
->
index
);
/*
/*
* Check whether an invalid uart number has been specified, and
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* if so, search for the first available port that does have
...
@@ -1414,15 +1417,23 @@ static struct console sunsu_cons = {
...
@@ -1414,15 +1417,23 @@ static struct console sunsu_cons = {
static
int
__init
sunsu_serial_console_init
(
void
)
static
int
__init
sunsu_serial_console_init
(
void
)
{
{
int
i
ndex
;
int
i
;
if
(
con_is_present
())
if
(
con_is_present
())
return
0
;
return
0
;
index
=
serial_console
-
1
;
for
(
i
=
0
;
i
<
UART_NR
;
i
++
)
{
if
(
sunsu_ports
[
index
].
port_node
==
0
)
int
this_minor
=
sunsu_reg
.
minor
+
i
;
if
((
this_minor
-
64
)
==
(
serial_console
-
1
))
break
;
}
if
(
i
==
UART_NR
)
return
0
;
return
0
;
sunsu_cons
.
index
=
index
;
if
(
sunsu_ports
[
i
].
port_node
==
0
)
return
0
;
sunsu_cons
.
index
=
i
;
register_console
(
&
sunsu_cons
);
register_console
(
&
sunsu_cons
);
return
0
;
return
0
;
}
}
...
...
drivers/serial/sunzilog.c
View file @
130ca59d
...
@@ -1013,7 +1013,6 @@ static struct uart_driver sunzilog_reg = {
...
@@ -1013,7 +1013,6 @@ static struct uart_driver sunzilog_reg = {
.
dev_name
=
"ttyS"
,
.
dev_name
=
"ttyS"
,
#endif
#endif
.
major
=
TTY_MAJOR
,
.
major
=
TTY_MAJOR
,
.
minor
=
64
,
};
};
static
void
*
__init
alloc_one_table
(
unsigned
long
size
)
static
void
*
__init
alloc_one_table
(
unsigned
long
size
)
...
@@ -1386,7 +1385,7 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
...
@@ -1386,7 +1385,7 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
static
kdev_t
sunzilog_console_device
(
struct
console
*
con
)
static
kdev_t
sunzilog_console_device
(
struct
console
*
con
)
{
{
return
mk_kdev
(
TTY_MAJOR
,
64
+
con
->
index
);
return
mk_kdev
(
sunzilog_reg
.
major
,
sunzilog_reg
.
minor
+
con
->
index
);
}
}
static
int
__init
sunzilog_console_setup
(
struct
console
*
con
,
char
*
options
)
static
int
__init
sunzilog_console_setup
(
struct
console
*
con
,
char
*
options
)
...
@@ -1395,7 +1394,8 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
...
@@ -1395,7 +1394,8 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
unsigned
long
flags
;
unsigned
long
flags
;
int
baud
,
brg
;
int
baud
,
brg
;
printk
(
"Console: ttyS%d (Zilog8530)
\n
"
,
con
->
index
/
2
);
printk
(
"Console: ttyS%d (Zilog8530)
\n
"
,
(
sunzilog_reg
.
minor
-
64
)
+
con
->
index
);
/* Get firmware console settings. */
/* Get firmware console settings. */
sunserial_console_termios
(
con
);
sunserial_console_termios
(
con
);
...
@@ -1447,10 +1447,21 @@ static struct console sunzilog_console = {
...
@@ -1447,10 +1447,21 @@ static struct console sunzilog_console = {
static
int
__init
sunzilog_console_init
(
void
)
static
int
__init
sunzilog_console_init
(
void
)
{
{
int
i
;
if
(
con_is_present
())
if
(
con_is_present
())
return
0
;
return
0
;
sunzilog_console
.
index
=
serial_console
-
1
;
for
(
i
=
0
;
i
<
NUM_CHANNELS
;
i
++
)
{
int
this_minor
=
sunzilog_reg
.
minor
+
i
;
if
((
this_minor
-
64
)
==
(
serial_console
-
1
))
break
;
}
if
(
i
==
NUM_CHANNELS
)
return
0
;
sunzilog_console
.
index
=
i
;
register_console
(
&
sunzilog_console
);
register_console
(
&
sunzilog_console
);
return
0
;
return
0
;
}
}
...
@@ -1480,6 +1491,7 @@ static void __init sunzilog_prepare(void)
...
@@ -1480,6 +1491,7 @@ static void __init sunzilog_prepare(void)
up
[(
chip
*
2
)
+
0
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
0
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
0
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
0
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
0
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
0
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
0
].
port
.
type
=
PORT_SUNZILOG
;
up
[(
chip
*
2
)
+
0
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
0
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
0
].
port
.
line
=
(
chip
*
2
)
+
0
;
up
[(
chip
*
2
)
+
0
].
port
.
line
=
(
chip
*
2
)
+
0
;
up
[(
chip
*
2
)
+
0
].
flags
|=
SUNZILOG_FLAG_IS_CHANNEL_A
;
up
[(
chip
*
2
)
+
0
].
flags
|=
SUNZILOG_FLAG_IS_CHANNEL_A
;
...
@@ -1490,6 +1502,7 @@ static void __init sunzilog_prepare(void)
...
@@ -1490,6 +1502,7 @@ static void __init sunzilog_prepare(void)
up
[(
chip
*
2
)
+
1
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
1
].
port
.
uartclk
=
ZS_CLOCK
;
up
[(
chip
*
2
)
+
1
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
1
].
port
.
fifosize
=
1
;
up
[(
chip
*
2
)
+
1
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
1
].
port
.
ops
=
&
sunzilog_pops
;
up
[(
chip
*
2
)
+
1
].
port
.
type
=
PORT_SUNZILOG
;
up
[(
chip
*
2
)
+
1
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
1
].
port
.
flags
=
0
;
up
[(
chip
*
2
)
+
1
].
port
.
line
=
(
chip
*
2
)
+
1
;
up
[(
chip
*
2
)
+
1
].
port
.
line
=
(
chip
*
2
)
+
1
;
up
[(
chip
*
2
)
+
1
].
flags
|=
0
;
up
[(
chip
*
2
)
+
1
].
flags
|=
0
;
...
@@ -1607,12 +1620,10 @@ static int __init sunzilog_ports_init(void)
...
@@ -1607,12 +1620,10 @@ static int __init sunzilog_ports_init(void)
* in the system.
* in the system.
*/
*/
sunzilog_reg
.
nr
=
NUM_CHANNELS
;
sunzilog_reg
.
nr
=
NUM_CHANNELS
;
#ifdef CONFIG_SERIAL_CONSOLE
sunzilog_reg
.
cons
=
&
sunzilog_console
;
sunzilog_reg
.
cons
=
&
sunzilog_console
;
#else
sunzilog_reg
.
cons
=
NULL
;
sunzilog_reg
.
minor
=
sunserial_current_minor
;
#endif
sunserial_current_minor
+=
NUM_CHANNELS
;
ret
=
uart_register_driver
(
&
sunzilog_reg
);
ret
=
uart_register_driver
(
&
sunzilog_reg
);
if
(
ret
==
0
)
{
if
(
ret
==
0
)
{
...
...
include/asm-sparc64/ns87303.h
View file @
130ca59d
...
@@ -78,9 +78,13 @@
...
@@ -78,9 +78,13 @@
#ifdef __KERNEL__
#ifdef __KERNEL__
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/io.h>
extern
spinlock_t
ns87303_lock
;
static
__inline__
int
ns87303_modify
(
unsigned
long
port
,
unsigned
int
index
,
static
__inline__
int
ns87303_modify
(
unsigned
long
port
,
unsigned
int
index
,
unsigned
char
clr
,
unsigned
char
set
)
unsigned
char
clr
,
unsigned
char
set
)
{
{
...
@@ -96,14 +100,16 @@ static __inline__ int ns87303_modify(unsigned long port, unsigned int index,
...
@@ -96,14 +100,16 @@ static __inline__ int ns87303_modify(unsigned long port, unsigned int index,
if
(
index
>
0x0d
)
if
(
index
>
0x0d
)
return
-
EINVAL
;
return
-
EINVAL
;
save_flags
(
flags
);
cli
();
spin_lock_irqsave
(
&
ns87303_lock
,
flags
);
outb
(
index
,
port
);
outb
(
index
,
port
);
value
=
inb
(
port
+
1
);
value
=
inb
(
port
+
1
);
value
&=
~
(
reserved
[
index
]
|
clr
);
value
&=
~
(
reserved
[
index
]
|
clr
);
value
|=
set
;
value
|=
set
;
outb
(
value
,
port
+
1
);
outb
(
value
,
port
+
1
);
outb
(
value
,
port
+
1
);
outb
(
value
,
port
+
1
);
restore_flags
(
flags
);
spin_unlock_irqrestore
(
&
ns87303_lock
,
flags
);
return
0
;
return
0
;
}
}
...
...
include/linux/serial_core.h
View file @
130ca59d
...
@@ -51,6 +51,10 @@
...
@@ -51,6 +51,10 @@
#define PORT_UART00 35
#define PORT_UART00 35
#define PORT_21285 37
#define PORT_21285 37
/* Sparc type numbers. */
#define PORT_SUNZILOG 38
#define PORT_SUNSAB 39
#ifdef __KERNEL__
#ifdef __KERNEL__
#include <linux/config.h>
#include <linux/config.h>
...
...
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