Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Kirill Smelkov
linux
Commits
a96e1f22
Commit
a96e1f22
authored
17 years ago
by
Linus Torvalds
Browse files
Options
Download
Email Patches
Plain Diff
Import 2.0.1
parent
81e05330
Changes
207
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1611 additions
and
1489 deletions
+1611
-1489
drivers/isdn/pcbit/callbacks.c
drivers/isdn/pcbit/callbacks.c
+2
-1
drivers/isdn/pcbit/capi.c
drivers/isdn/pcbit/capi.c
+26
-10
drivers/isdn/pcbit/capi.h
drivers/isdn/pcbit/capi.h
+2
-1
drivers/isdn/pcbit/drv.c
drivers/isdn/pcbit/drv.c
+15
-12
drivers/isdn/pcbit/edss1.c
drivers/isdn/pcbit/edss1.c
+5
-5
drivers/isdn/pcbit/layer2.c
drivers/isdn/pcbit/layer2.c
+67
-118
drivers/isdn/teles/callc.c
drivers/isdn/teles/callc.c
+15
-4
drivers/isdn/teles/card.c
drivers/isdn/teles/card.c
+61
-49
drivers/net/de4x5.c
drivers/net/de4x5.c
+138
-122
drivers/net/net_init.c
drivers/net/net_init.c
+11
-0
drivers/net/slhc.c
drivers/net/slhc.c
+6
-8
drivers/net/wic.c
drivers/net/wic.c
+1
-1
drivers/scsi/Config.in
drivers/scsi/Config.in
+1
-3
drivers/scsi/README.st
drivers/scsi/README.st
+12
-8
drivers/scsi/hosts.h
drivers/scsi/hosts.h
+1
-1
drivers/scsi/qlogicisp.c
drivers/scsi/qlogicisp.c
+1174
-1100
drivers/scsi/qlogicisp.h
drivers/scsi/qlogicisp.h
+37
-22
drivers/scsi/scsi.c
drivers/scsi/scsi.c
+28
-15
drivers/scsi/scsi.h
drivers/scsi/scsi.h
+1
-1
drivers/scsi/sg.c
drivers/scsi/sg.c
+8
-8
No files found.
drivers/isdn/pcbit/callbacks.c
View file @
a96e1f22
...
...
@@ -59,7 +59,8 @@ void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
* - kfree when msg has been sent
*/
if
((
len
=
capi_conn_req
(
cbdata
->
data
.
setup
.
CalledPN
,
&
skb
))
<
0
)
if
((
len
=
capi_conn_req
(
cbdata
->
data
.
setup
.
CalledPN
,
&
skb
,
chan
->
proto
))
<
0
)
{
printk
(
"capi_conn_req failed
\n
"
);
return
;
...
...
This diff is collapsed.
Click to expand it.
drivers/isdn/pcbit/capi.c
View file @
a96e1f22
...
...
@@ -58,7 +58,7 @@
*
*/
int
capi_conn_req
(
const
char
*
calledPN
,
struct
sk_buff
**
skb
)
int
capi_conn_req
(
const
char
*
calledPN
,
struct
sk_buff
**
skb
,
int
proto
)
{
ushort
len
;
...
...
@@ -80,6 +80,9 @@ int capi_conn_req(const char * calledPN, struct sk_buff **skb)
len
=
18
+
strlen
(
calledPN
);
if
(
proto
==
ISDN_PROTO_L2_TRANS
)
len
++
;
if
((
*
skb
=
dev_alloc_skb
(
len
))
==
NULL
)
{
printk
(
KERN_WARNING
"capi_conn_req: alloc_skb failed
\n
"
);
...
...
@@ -89,11 +92,21 @@ int capi_conn_req(const char * calledPN, struct sk_buff **skb)
/* InfoElmMask */
*
((
ushort
*
)
skb_put
(
*
skb
,
2
))
=
AppInfoMask
;
/* Bearer Capability - Mandatory*/
*
(
skb_put
(
*
skb
,
1
))
=
2
;
/* BC0.Length */
*
(
skb_put
(
*
skb
,
1
))
=
0x88
;
/* BC0.Octect3 - Digital Information */
*
(
skb_put
(
*
skb
,
1
))
=
0x90
;
/* BC0.Octect4 - */
if
(
proto
==
ISDN_PROTO_L2_TRANS
)
{
/* Bearer Capability - Mandatory*/
*
(
skb_put
(
*
skb
,
1
))
=
3
;
/* BC0.Length */
*
(
skb_put
(
*
skb
,
1
))
=
0x80
;
/* Speech */
*
(
skb_put
(
*
skb
,
1
))
=
0x10
;
/* Circuit Mode */
*
(
skb_put
(
*
skb
,
1
))
=
0x23
;
/* A-law */
}
else
{
/* Bearer Capability - Mandatory*/
*
(
skb_put
(
*
skb
,
1
))
=
2
;
/* BC0.Length */
*
(
skb_put
(
*
skb
,
1
))
=
0x88
;
/* Digital Information */
*
(
skb_put
(
*
skb
,
1
))
=
0x90
;
/* BC0.Octect4 */
}
/* Bearer Capability - Optional*/
*
(
skb_put
(
*
skb
,
1
))
=
0
;
/* BC1.Length = 0 */
...
...
@@ -220,16 +233,19 @@ int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
*
(
skb_put
(
*
skb
,
1
))
=
0x05
;
/* LAPB */
break
;
case
ISDN_PROTO_L2_HDLC
:
#ifdef DEBUG
printk
(
KERN_DEBUG
"HDLC
\n
"
);
/* HDLC */
#endif
*
(
skb_put
(
*
skb
,
1
))
=
0x02
;
break
;
case
ISDN_PROTO_L2_TRANS
:
/*
* Voice (a-law)
*/
*
(
skb_put
(
*
skb
,
1
))
=
0x06
;
break
;
default:
#ifdef DEBUG
printk
(
KERN_DEBUG
"Transparent
\n
"
);
#endif
*
(
skb_put
(
*
skb
,
1
))
=
0x03
;
*
(
skb_put
(
*
skb
,
1
))
=
0x03
;
break
;
}
...
...
This diff is collapsed.
Click to expand it.
drivers/isdn/pcbit/capi.h
View file @
a96e1f22
...
...
@@ -22,7 +22,8 @@
#define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER
/* Connection Setup */
extern
int
capi_conn_req
(
const
char
*
calledPN
,
struct
sk_buff
**
buf
);
extern
int
capi_conn_req
(
const
char
*
calledPN
,
struct
sk_buff
**
buf
,
int
proto
);
extern
int
capi_decode_conn_conf
(
struct
pcbit_chan
*
chan
,
struct
sk_buff
*
skb
,
int
*
complete
);
...
...
This diff is collapsed.
Click to expand it.
drivers/isdn/pcbit/drv.c
View file @
a96e1f22
...
...
@@ -11,6 +11,14 @@
* PCBIT-D interface with isdn4linux
*/
/*
* Fixes:
*
* Nuno Grilo <l38486@alfa.ist.utl.pt>
* fixed msn_list NULL pointer dereference.
*
*/
#define __NO_VERSION__
#include <linux/module.h>
...
...
@@ -109,7 +117,7 @@ int pcbit_init_dev(int board, int mem_base, int irq)
dev
->
b2
->
id
=
1
;
dev
->
qdelivery
.
next
=
0
;
dev
->
qdelivery
.
next
=
NULL
;
dev
->
qdelivery
.
sync
=
0
;
dev
->
qdelivery
.
routine
=
pcbit_deliver
;
dev
->
qdelivery
.
data
=
dev
;
...
...
@@ -152,8 +160,8 @@ int pcbit_init_dev(int board, int mem_base, int irq)
dev_if
->
channels
=
2
;
dev_if
->
features
=
ISDN_FEATURE_P_EURO
|
ISDN_FEATURE_L3_TRANS
|
ISDN_FEATURE_L2_HDLC
;
dev_if
->
features
=
(
ISDN_FEATURE_P_EURO
|
ISDN_FEATURE_L3_TRANS
|
ISDN_FEATURE_L2_HDLC
|
ISDN_FEATURE_L2_TRANS
)
;
dev_if
->
writebuf_skb
=
pcbit_xmit
;
dev_if
->
writebuf
=
NULL
;
...
...
@@ -1051,7 +1059,8 @@ static void pcbit_clear_msn(struct pcbit_dev *dev)
static
void
pcbit_set_msn
(
struct
pcbit_dev
*
dev
,
char
*
list
)
{
struct
msn_entry
*
ptr
,
*
back
;
struct
msn_entry
*
ptr
;
struct
msn_entry
*
back
=
NULL
;
char
*
cp
,
*
sp
;
int
len
;
...
...
@@ -1070,7 +1079,8 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
return
;
}
for
(
back
=
dev
->
msn_list
;
back
->
next
;
back
=
back
->
next
);
if
(
dev
->
msn_list
)
for
(
back
=
dev
->
msn_list
;
back
->
next
;
back
=
back
->
next
);
sp
=
list
;
...
...
@@ -1128,10 +1138,3 @@ static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
return
0
;
}
This diff is collapsed.
Click to expand it.
drivers/isdn/pcbit/edss1.c
View file @
a96e1f22
...
...
@@ -288,15 +288,10 @@ void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
save_flags
(
flags
);
cli
();
if
(
chan
->
fsm_timer
.
function
)
{
del_timer
(
&
chan
->
fsm_timer
);
chan
->
fsm_timer
.
function
=
NULL
;
}
for
(
action
=
fsm_table
;
action
->
init
!=
0xff
;
action
++
)
if
(
action
->
init
==
chan
->
fsm_state
&&
action
->
event
==
event
)
break
;
if
(
action
->
init
==
0xff
)
{
...
...
@@ -305,6 +300,11 @@ void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
return
;
}
if
(
chan
->
fsm_timer
.
function
)
{
del_timer
(
&
chan
->
fsm_timer
);
chan
->
fsm_timer
.
function
=
NULL
;
}
chan
->
fsm_state
=
action
->
final
;
pcbit_state_change
(
dev
,
chan
,
action
->
init
,
event
,
action
->
final
);
...
...
This diff is collapsed.
Click to expand it.
drivers/isdn/pcbit/layer2.c
View file @
a96e1f22
...
...
@@ -58,16 +58,7 @@
/*
* task queue struct
*/
struct
tq_struct
*
tq_delivery
=
NULL
;
static
void
do_pcbit_bh
(
task_queue
*
list
)
{
run_task_queue
(
list
);
}
struct
tq_struct
run_delivery
=
{
0
,
0
,
(
void
*
)(
void
*
)
do_pcbit_bh
,
&
tq_delivery
,
};
/*
...
...
@@ -87,7 +78,6 @@ void pcbit_deliver(void * data);
static
void
pcbit_transmit
(
struct
pcbit_dev
*
dev
);
static
void
pcbit_recv_ack
(
struct
pcbit_dev
*
dev
,
unsigned
char
ack
);
static
void
pcbit_frame_read
(
struct
pcbit_dev
*
dev
,
unsigned
char
read_seq
);
static
void
pcbit_l2_error
(
struct
pcbit_dev
*
dev
);
static
void
pcbit_l2_active_conf
(
struct
pcbit_dev
*
dev
,
u_char
info
);
...
...
@@ -95,11 +85,10 @@ static void pcbit_l2_err_recover(unsigned long data);
static
void
pcbit_firmware_bug
(
struct
pcbit_dev
*
dev
);
static
void
pcbit_sched_delivery
(
struct
pcbit_dev
*
dev
)
static
__inline__
void
pcbit_sched_delivery
(
struct
pcbit_dev
*
dev
)
{
queue_task_irq_off
(
&
dev
->
qdelivery
,
&
tq_delivery
);
queue_task_irq_off
(
&
run_delivery
,
&
tq_immediate
);
mark_bh
(
IMMEDIATE_BH
);
queue_task
(
&
dev
->
qdelivery
,
&
tq_immediate
);
mark_bh
(
IMMEDIATE_BH
);
}
...
...
@@ -195,11 +184,10 @@ static void pcbit_transmit(struct pcbit_dev * dev)
unacked
=
(
dev
->
send_seq
+
(
8
-
dev
->
unack_seq
)
)
&
0x07
;
if
(
dev
->
free
>
16
&&
dev
->
write_queue
&&
unacked
<
7
)
{
save_flags
(
flags
);
cli
();
save_flags
(
flags
);
cli
();
if
(
dev
->
free
>
16
&&
dev
->
write_queue
&&
unacked
<
7
)
{
if
(
!
dev
->
w_busy
)
dev
->
w_busy
=
1
;
...
...
@@ -209,11 +197,12 @@ static void pcbit_transmit(struct pcbit_dev * dev)
return
;
}
restore_flags
(
flags
);
frame
=
dev
->
write_queue
;
free
=
dev
->
free
;
restore_flags
(
flags
);
if
(
frame
->
copied
==
0
)
{
/* Type 0 frame */
...
...
@@ -311,12 +300,15 @@ static void pcbit_transmit(struct pcbit_dev * dev)
dev
->
w_busy
=
0
;
restore_flags
(
flags
);
}
#ifdef DEBUG
else
{
restore_flags
(
flags
);
#ifdef DEBUG
printk
(
KERN_DEBUG
"unacked %d free %d write_queue %s
\n
"
,
unacked
,
dev
->
free
,
dev
->
write_queue
?
"not empty"
:
"empty"
);
"empty"
);
#endif
}
}
...
...
@@ -334,29 +326,31 @@ void pcbit_deliver(void * data)
save_flags
(
flags
);
cli
();
/* get frame from queue */
if
(
!
(
frame
=
dev
->
read_queue
))
{
while
((
frame
=
dev
->
read_queue
))
{
dev
->
read_queue
=
frame
->
next
;
restore_flags
(
flags
);
return
;
}
dev
->
read_queue
=
frame
->
next
;
restore_flags
(
flags
);
msg
.
cpu
=
0
;
msg
.
proc
=
0
;
msg
.
cmd
=
frame
->
skb
->
data
[
2
];
msg
.
scmd
=
frame
->
skb
->
data
[
3
];
msg
.
cpu
=
0
;
msg
.
proc
=
0
;
msg
.
cmd
=
frame
->
skb
->
data
[
2
];
msg
.
scmd
=
frame
->
skb
->
data
[
3
]
;
frame
->
refnum
=
*
((
ushort
*
)
frame
->
skb
->
data
+
4
)
;
frame
->
msg
=
*
((
ulong
*
)
&
msg
)
;
skb_pull
(
frame
->
skb
,
6
)
;
frame
->
refnum
=
*
((
ushort
*
)
frame
->
skb
->
data
+
4
);
frame
->
msg
=
*
((
ulong
*
)
&
msg
);
skb_pull
(
frame
->
skb
,
6
);
pcbit_l3_receive
(
dev
,
frame
->
msg
,
frame
->
skb
,
frame
->
hdr_len
,
frame
->
refnum
);
pcbit_l3_receive
(
dev
,
frame
->
msg
,
frame
->
skb
,
frame
->
hdr_len
,
frame
->
refnum
);
kfree
(
frame
);
kfree
(
frame
);
save_flags
(
flags
);
cli
();
}
restore_flags
(
flags
);
}
/*
...
...
@@ -517,8 +511,7 @@ static void pcbit_receive(struct pcbit_dev * dev)
}
else
dev
->
read_queue
=
frame
;
pcbit_sched_delivery
(
dev
);
restore_flags
(
flags
);
}
...
...
@@ -572,7 +565,6 @@ void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs)
{
struct
pcbit_dev
*
dev
;
u_char
info
,
ack_seq
,
read_seq
;
u_char
ack_int
=
1
;
dev
=
(
struct
pcbit_dev
*
)
devptr
;
...
...
@@ -618,33 +610,27 @@ void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs)
read_seq
=
(
info
&
0x07U
);
dev
->
interrupt
=
0
;
sti
();
/*
* Bottom Half
* Runs with ints enabled
*/
if
(
read_seq
!=
dev
->
rcv_seq
)
{
pcbit_frame_read
(
dev
,
read_seq
);
ack_int
=
0
;
while
(
read_seq
!=
dev
->
rcv_seq
)
{
pcbit_receive
(
dev
);
dev
->
rcv_seq
=
(
dev
->
rcv_seq
+
1
)
%
8
;
}
pcbit_sched_delivery
(
dev
);
}
if
(
ack_seq
!=
dev
->
unack_seq
)
{
pcbit_recv_ack
(
dev
,
ack_seq
);
ack_int
=
0
;
}
if
(
ack_int
)
{
info
=
0
;
info
|=
dev
->
rcv_seq
<<
3
;
info
|=
dev
->
send_seq
;
info
=
dev
->
rcv_seq
<<
3
;
info
|=
dev
->
send_seq
;
writeb
(
info
,
dev
->
sh_mem
+
BANK4
);
}
writeb
(
info
,
dev
->
sh_mem
+
BANK4
);
}
...
...
@@ -685,17 +671,19 @@ static void pcbit_l2_err_recover(unsigned long data)
del_timer
(
&
dev
->
error_recover_timer
);
if
(
dev
->
w_busy
||
dev
->
r_busy
)
{
init_timer
(
&
dev
->
error_recover_timer
);
dev
->
error_recover_timer
.
expires
=
jiffies
+
ERRTIME
;
add_timer
(
&
dev
->
error_recover_timer
);
return
;
}
{
init_timer
(
&
dev
->
error_recover_timer
);
dev
->
error_recover_timer
.
expires
=
jiffies
+
ERRTIME
;
add_timer
(
&
dev
->
error_recover_timer
);
return
;
}
dev
->
w_busy
=
dev
->
r_busy
=
1
;
if
(
dev
->
read_frame
)
{
if
(
dev
->
read_frame
->
skb
)
{
if
(
dev
->
read_frame
)
{
if
(
dev
->
read_frame
->
skb
)
{
dev
->
read_frame
->
skb
->
free
=
1
;
kfree_skb
(
dev
->
read_frame
->
skb
,
FREE_READ
);
}
...
...
@@ -704,7 +692,8 @@ static void pcbit_l2_err_recover(unsigned long data)
}
if
(
dev
->
write_queue
)
{
if
(
dev
->
write_queue
)
{
frame
=
dev
->
write_queue
;
#ifdef FREE_ON_ERROR
dev
->
write_queue
=
dev
->
write_queue
->
next
;
...
...
@@ -775,14 +764,20 @@ static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
{
if
(
dev
->
send_seq
>
dev
->
unack_seq
)
if
(
ack
<=
dev
->
unack_seq
||
ack
>
dev
->
send_seq
)
if
(
ack
<=
dev
->
unack_seq
||
ack
>
dev
->
send_seq
)
{
printk
(
"layer 2 ack unacceptable - dev %d"
,
dev
->
id
);
printk
(
KERN_DEBUG
"layer 2 ack unacceptable - dev %d"
,
dev
->
id
);
pcbit_l2_error
(
dev
);
}
else
if
(
ack
>
dev
->
send_seq
&&
ack
<=
dev
->
unack_seq
)
{
printk
(
"layer 2 ack unacceptable - dev %d"
,
dev
->
id
);
if
(
ack
>
dev
->
send_seq
&&
ack
<=
dev
->
unack_seq
)
{
printk
(
KERN_DEBUG
"layer 2 ack unacceptable - dev %d"
,
dev
->
id
);
pcbit_l2_error
(
dev
);
}
...
...
@@ -805,55 +800,9 @@ static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
if
(
dev
->
send_seq
==
lsend_seq
)
break
;
count
++
;
}
if
(
!
count
)
{
u_char
info
;
info
=
0
;
info
|=
dev
->
rcv_seq
<<
3
;
info
|=
dev
->
send_seq
;
writeb
(
info
,
dev
->
sh_mem
+
BANK4
);
}
count
++
;
}
}
else
printk
(
KERN_DEBUG
"recv_ack: unacked = 0
\n
"
);
}
static
void
pcbit_frame_read
(
struct
pcbit_dev
*
dev
,
unsigned
char
read_seq
)
{
unsigned
long
flags
;
int
busy
;
u_char
info
;
save_flags
(
flags
);
cli
();
if
(
!
(
busy
=
dev
->
r_busy
))
dev
->
r_busy
=
1
;
restore_flags
(
flags
);
if
(
busy
)
return
;
while
(
read_seq
!=
dev
->
rcv_seq
)
{
pcbit_receive
(
dev
);
dev
->
rcv_seq
=
(
dev
->
rcv_seq
+
1
)
%
8
;
}
dev
->
r_busy
=
0
;
info
=
0
;
info
|=
dev
->
rcv_seq
<<
3
;
info
|=
dev
->
send_seq
;
writeb
(
info
,
dev
->
sh_mem
+
BANK4
);
}
This diff is collapsed.
Click to expand it.
drivers/isdn/teles/callc.c
View file @
a96e1f22
/* $Id: callc.c,v 1.1
1
1996/06/
07 12:32:20
fritz Exp $
/* $Id: callc.c,v 1.1
3
1996/06/
24 17:15:55
fritz Exp $
*
* $Log: callc.c,v $
* Revision 1.13 1996/06/24 17:15:55 fritz
* corrected return code of teles_writebuf()
*
* Revision 1.12 1996/06/12 16:15:33 fritz
* Extended user-configurable debugging flags.
*
* Revision 1.11 1996/06/07 12:32:20 fritz
* More changes to support suspend/resume.
*
...
...
@@ -1297,8 +1303,10 @@ distr_debug(void)
chanlist
[
i
].
ds
.
l2
.
l2m
.
debug
=
debugflags
&
16
;
}
for
(
i
=
0
;
i
<
nrcards
;
i
++
)
if
(
cards
[
i
].
sp
)
if
(
cards
[
i
].
sp
)
{
cards
[
i
].
sp
->
dlogflag
=
debugflags
&
4
;
cards
[
i
].
sp
->
debug
=
debugflags
&
32
;
}
}
int
...
...
@@ -1419,12 +1427,15 @@ teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
if
(
!
chanp
->
data_open
)
{
printk
(
KERN_DEBUG
"teles_writebuf: channel not open
\n
"
);
return
-
E
NOMEM
;
return
-
E
IO
;
}
err
=
BufPoolGet
(
&
ibh
,
st
->
l1
.
sbufpool
,
GFP_ATOMIC
,
st
,
21
);
if
(
err
)
return
-
ENOMEM
;
/* Must return 0 here, since this is not an error
* but a temporary lack of resources.
*/
return
0
;
ptr
=
DATAPTR
(
ibh
);
if
(
chanp
->
lc_b
.
l2_establish
)
...
...
This diff is collapsed.
Click to expand it.
drivers/isdn/teles/card.c
View file @
a96e1f22
/* $Id: card.c,v 1.
9
1996/06/
06 14:42:09
fritz Exp $
/* $Id: card.c,v 1.
12
1996/06/
24 17:16:52
fritz Exp $
*
* card.c low level stuff for the Teles S0 isdn card
*
...
...
@@ -7,6 +7,16 @@
* Beat Doebeli log all D channel traffic
*
* $Log: card.c,v $
* Revision 1.12 1996/06/24 17:16:52 fritz
* Added check for misconfigured membase.
*
* Revision 1.11 1996/06/14 03:30:37 fritz
* Added recovery from EXIR 40 interrupt.
* Some cleanup.
*
* Revision 1.10 1996/06/11 14:57:20 hipp
* minor changes to ensure, that SKBs are sent in the right order
*
* Revision 1.9 1996/06/06 14:42:09 fritz
* Bugfix: forgot hsp-> in last change.
*
...
...
@@ -52,7 +62,6 @@
#include <linux/interrupt.h>
#undef DCHAN_VERBOSE
#define FRITZ_EXPERIMENTAL
extern
void
tei_handler
(
struct
PStack
*
st
,
byte
pr
,
struct
BufHeader
*
ibh
);
...
...
@@ -215,16 +224,9 @@ waitforCEC_3(int iobase, byte hscx)
static
inline
void
waitforXFW_0
(
byte
*
base
,
byte
hscx
)
{
#ifdef FRITZ_EXPERIMENTAL
long
to
=
20
;
while
((
!
(
readhscx_0
(
base
,
hscx
,
HSCX_STAR
)
&
0x44
)
==
0x40
)
&&
to
)
{
#else
long
to
=
10
;
waitforCEC_0
(
base
,
hscx
);
while
((
!
(
readhscx_0
(
base
,
hscx
,
HSCX_STAR
)
&
0x40
))
&&
to
)
{
#endif
udelay
(
5
);
to
--
;
}
...
...
@@ -235,16 +237,9 @@ waitforXFW_0(byte * base, byte hscx)
static
inline
void
waitforXFW_3
(
int
iobase
,
byte
hscx
)
{
#ifdef FRITZ_EXPERIMENTAL
long
to
=
20
;
while
((
!
(
readhscx_3
(
iobase
,
hscx
,
HSCX_STAR
)
&
0x44
)
==
0x40
)
&&
to
)
{
#else
long
to
=
10
;
waitforCEC_3
(
iobase
,
hscx
);
while
((
!
(
readhscx_3
(
iobase
,
hscx
,
HSCX_STAR
)
&
0x40
))
&&
to
)
{
#endif
udelay
(
5
);
to
--
;
}
...
...
@@ -507,10 +502,10 @@ hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
}
else
{
if
(
hsp
->
releasebuf
)
BufPoolRelease
(
hsp
->
xmtibh
);
hsp
->
xmtibh
=
NULL
;
hsp
->
sendptr
=
0
;
if
(
hsp
->
st
->
l4
.
l1writewakeup
)
hsp
->
st
->
l4
.
l1writewakeup
(
hsp
->
st
);
hsp
->
xmtibh
=
NULL
;
}
if
(
!
BufQueueUnlink
(
&
hsp
->
xmtibh
,
&
hsp
->
sq
))
{
hsp
->
releasebuf
=
!
0
;
...
...
@@ -709,7 +704,7 @@ isac_new_ph(struct IsdnCardState *sp)
static
void
teles_interrupt
(
int
intno
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
byte
val
,
val2
,
r
,
exval
;
byte
val
,
r
,
exval
;
struct
IsdnCardState
*
sp
;
unsigned
int
count
;
struct
HscxState
*
hsp
;
...
...
@@ -725,11 +720,20 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if
(
val
&
0x01
)
{
hsp
=
sp
->
hs
+
1
;
exval
=
READHSCX
(
sp
->
membase
,
sp
->
iobase
,
1
,
HSCX_EXIR
);
if
((
hsp
->
mode
==
1
)
||
(
exval
==
0x40
))
hscx_fill_fifo
(
hsp
);
else
printk
(
KERN_WARNING
"HSCX B EXIR %x xmitbh %lx rcvibh %lx
\n
"
,
exval
,
(
long
)
hsp
->
xmtibh
,
(
long
)
hsp
->
rcvibh
);
if
(
exval
==
0x40
)
{
if
(
hsp
->
mode
==
1
)
hscx_fill_fifo
(
hsp
);
else
{
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp
->
sendptr
=
0
;
WRITEHSCX_CMDR
(
hsp
->
membase
,
hsp
->
iobase
,
hsp
->
hscx
,
0x01
);
printk
(
KERN_DEBUG
"HSCX B EXIR %x
\n
"
,
exval
);
}
}
else
printk
(
KERN_WARNING
"HSCX B EXIR %x
\n
"
,
exval
);
}
if
(
val
&
0xf8
)
{
if
(
sp
->
debug
)
...
...
@@ -739,33 +743,28 @@ teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if
(
val
&
0x02
)
{
hsp
=
sp
->
hs
;
exval
=
READHSCX
(
sp
->
membase
,
sp
->
iobase
,
0
,
HSCX_EXIR
);
if
((
hsp
->
mode
==
1
)
&&
(
exval
==
0x40
))
hscx_fill_fifo
(
hsp
);
else
printk
(
KERN_WARNING
"HSCX A EXIR %x
\n
"
,
exval
);
if
(
exval
==
0x40
)
{
if
(
hsp
->
mode
==
1
)
hscx_fill_fifo
(
hsp
);
else
{
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp
->
sendptr
=
0
;
WRITEHSCX_CMDR
(
hsp
->
membase
,
hsp
->
iobase
,
hsp
->
hscx
,
0x01
);
printk
(
KERN_DEBUG
"HSCX A EXIR %x
\n
"
,
exval
);
}
}
else
printk
(
KERN_WARNING
"HSCX A EXIR %x
\n
"
,
exval
);
}
/* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */
if
(
sp
->
membase
)
{
if
(
val
&
0x04
)
{
val
=
readhscx_0
(
sp
->
membase
,
0
,
HSCX_ISTA
);
if
(
sp
->
debug
)
printk
(
KERN_DEBUG
"HSCX A interrupt %x
\n
"
,
val
);
hscx_interrupt
(
sp
,
val
,
0
);
}
}
else
{
val2
=
readhscx_3
(
sp
->
iobase
,
0
,
HSCX_ISTA
);
if
(
val
&
0x04
)
{
val
=
READHSCX
(
sp
->
membase
,
sp
->
iobase
,
0
,
HSCX_ISTA
);
if
(
sp
->
debug
)
printk
(
KERN_DEBUG
"HSCX A ISTA %x
\n
"
,
val2
);
if
(
val
&
0x04
)
{
if
(
sp
->
debug
)
printk
(
KERN_DEBUG
"HSCX A interrupt %x
\n
"
,
val2
);
hscx_interrupt
(
sp
,
val2
,
0
);
}
printk
(
KERN_DEBUG
"HSCX A interrupt %x
\n
"
,
val
);
hscx_interrupt
(
sp
,
val
,
0
);
}
/* ??? Why do that ^^^^^^^^^^^^^^^^^^^^^ different on Teles 16-3 ??? */
val
=
READISAC
(
sp
->
membase
,
sp
->
iobase
,
ISAC_ISTA
);
...
...
@@ -1083,6 +1082,13 @@ checkcard(int cardnr)
byte
cfval
,
val
;
struct
IsdnCard
*
card
=
cards
+
cardnr
;
if
(
card
->
membase
)
if
((
unsigned
long
)
card
->
membase
<
0x10000
)
{
(
unsigned
long
)
card
->
membase
<<=
4
;
printk
(
KERN_INFO
"Teles membase configured DOSish, assuming 0x%lx
\n
"
,
(
unsigned
long
)
card
->
membase
);
}
if
(
!
card
->
iobase
)
{
if
(
card
->
membase
)
{
printk
(
KERN_NOTICE
...
...
@@ -1090,7 +1096,7 @@ checkcard(int cardnr)
(
long
)
card
->
membase
,
card
->
interrupt
,
(
card
->
protocol
==
ISDN_PTYPE_1TR6
)
?
"1TR6"
:
"EDSS1"
);
printk
(
KERN_INFO
"HSCX version A:
%x B:%x
\n
"
,
printk
(
KERN_INFO
"HSCX version A:%x B:%x
\n
"
,
readhscx_0
(
card
->
membase
,
0
,
HSCX_VSTR
)
&
0xf
,
readhscx_0
(
card
->
membase
,
1
,
HSCX_VSTR
)
&
0xf
);
}
...
...
@@ -1736,12 +1742,18 @@ hscx_l2l1(struct PStack *st, int pr,
struct
IsdnCardState
*
sp
=
(
struct
IsdnCardState
*
)
st
->
l1
.
hardware
;
struct
HscxState
*
hsp
=
sp
->
hs
+
st
->
l1
.
hscx
;
long
flags
;
switch
(
pr
)
{
case
(
PH_DATA
):
if
(
hsp
->
xmtibh
)
save_flags
(
flags
);
cli
();
if
(
hsp
->
xmtibh
)
{
BufQueueLink
(
&
hsp
->
sq
,
ibh
);
restore_flags
(
flags
);
}
else
{
restore_flags
(
flags
);
hsp
->
xmtibh
=
ibh
;
hsp
->
sendptr
=
0
;
hsp
->
releasebuf
=
!
0
;
...
...
This diff is collapsed.
Click to expand it.
drivers/net/de4x5.c
View file @
a96e1f22
/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux.
/* de4x5.c: A DIGITAL DE425/DE434/DE435/
DE450/
DE500 ethernet driver for Linux.
Copyright 1994, 1995 Digital Equipment Corporation.
...
...
@@ -191,15 +191,25 @@
Fix bug in dc21040 and dc21041 autosense code.
Remove buffer copies on receive for Intels.
Change sk_buff handling during media disconnects to
eliminate DUP packets.
eliminate DUP packets.
Add dynamic TX thresholding.
Change all chips to use perfect multicast filtering.
Fix alloc_device() bug <jari@markkus2.fimr.fi>
0.43 21-Jun-96 Fix unconnected media TX retry bug.
Add Accton to the list of broken cards.
Fix TX under-run bug for non DC21140 chips.
Fix boot command probe bug in alloc_device() as
reported by <koen.gadeyne@barco.com> and
<orava@nether.tky.hut.fi>.
Add cache locks to prevent a race condition as
reported by <csd@microplex.com> and
<baba@beckman.uiuc.edu>.
Upgraded alloc_device() code.
=========================================================================
*/
static
const
char
*
version
=
"de4x5.c:v0.4
2
96/
4
/2
6
davies@wanton.lkg.dec.com
\n
"
;
static
const
char
*
version
=
"de4x5.c:v0.4
3
96/
6
/2
1
davies@wanton.lkg.dec.com
\n
"
;
#include <linux/module.h>
...
...
@@ -226,6 +236,7 @@ static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n"
#include <linux/time.h>
#include <linux/types.h>
#include <linux/unistd.h>
#include <linux/ctype.h>
#include "de4x5.h"
...
...
@@ -274,10 +285,12 @@ static struct phy_table phy_info[] = {
** Define special SROM detection cases
*/
static
c_char
enet_det
[][
ETH_ALEN
]
=
{
{
0x00
,
0x00
,
0xc0
,
0x00
,
0x00
,
0x00
}
{
0x00
,
0x00
,
0xc0
,
0x00
,
0x00
,
0x00
},
{
0x00
,
0x00
,
0xe8
,
0x00
,
0x00
,
0x00
}
};
#define SMC 1
#define SMC 1
#define ACCTON 2
#ifdef DE4X5_DEBUG
...
...
@@ -511,6 +524,7 @@ struct de4x5_private {
struct
{
void
*
priv
;
/* Original kmalloc'd mem addr */
void
*
buf
;
/* Original kmalloc'd mem addr */
int
lock
;
/* Lock the cache accesses */
s32
csr0
;
/* Saved Bus Mode Register */
s32
csr6
;
/* Saved Operating Mode Reg. */
s32
csr7
;
/* Saved IRQ Mask Register */
...
...
@@ -633,12 +647,15 @@ static int get_hw_addr(struct device *dev);
static
void
eisa_probe
(
struct
device
*
dev
,
u_long
iobase
);
static
void
pci_probe
(
struct
device
*
dev
,
u_long
iobase
);
static
struct
device
*
alloc_device
(
struct
device
*
dev
,
u_long
iobase
);
static
struct
device
*
insert_device
(
struct
device
*
dev
,
u_long
iobase
,
int
(
*
init
)(
struct
device
*
));
static
char
*
build_setup_frame
(
struct
device
*
dev
,
int
mode
);
static
void
disable_ast
(
struct
device
*
dev
);
static
void
enable_ast
(
struct
device
*
dev
,
u32
time_out
);
static
long
de4x5_switch_to_srl
(
struct
device
*
dev
);
static
long
de4x5_switch_to_mii
(
struct
device
*
dev
);
static
void
timeout
(
struct
device
*
dev
,
void
(
*
fn
)(
u_long
data
),
u_long
data
,
u_long
msec
);
static
int
de4x5_dev_index
(
char
*
s
);
static
void
de4x5_dbg_open
(
struct
device
*
dev
);
static
void
de4x5_dbg_mii
(
struct
device
*
dev
,
int
k
);
static
void
de4x5_dbg_media
(
struct
device
*
dev
);
...
...
@@ -683,7 +700,7 @@ de4x5_probe(struct device *dev)
{
int
tmp
=
num_de4x5s
,
status
=
-
ENODEV
;
u_long
iobase
=
dev
->
base_addr
;
eisa_probe
(
dev
,
iobase
);
pci_probe
(
dev
,
iobase
);
...
...
@@ -691,7 +708,7 @@ de4x5_probe(struct device *dev)
printk
(
"%s: de4x5_probe() cannot find device at 0x%04lx.
\n
"
,
dev
->
name
,
iobase
);
}
/*
** Walk the device list to check that at least one device
** initialised OK
...
...
@@ -1076,6 +1093,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
return
0
;
}
set_bit
(
0
,
(
void
*
)
&
dev
->
tbusy
);
/* Stop send re-tries */
if
(
lp
->
tx_enable
==
NO
)
{
/* Cannot send for now */
return
-
1
;
}
...
...
@@ -1085,11 +1103,13 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
** interrupts are lost by delayed descriptor status updates relative to
** the irq assertion, especially with a busy PCI bus.
*/
set_bit
(
0
,
(
void
*
)
&
dev
->
tbusy
);
cli
();
de4x5_tx
(
dev
);
sti
();
/* Test if cache is already locked - requeue skb if so */
if
(
set_bit
(
0
,
(
void
*
)
&
lp
->
cache
.
lock
)
&&
!
dev
->
interrupt
)
return
-
1
;
/* Transmit descriptor ring full or stale skb */
if
(
dev
->
tbusy
||
lp
->
tx_skb
[
lp
->
tx_new
])
{
if
(
dev
->
interrupt
)
{
...
...
@@ -1130,6 +1150,8 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
}
}
lp
->
cache
.
lock
=
0
;
return
status
;
}
...
...
@@ -1195,8 +1217,11 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/* Load the TX ring with any locally stored packets */
while
(
lp
->
cache
.
skb
&&
!
dev
->
tbusy
&&
lp
->
tx_enable
)
{
de4x5_queue_pkt
(
de4x5_get_cache
(
dev
),
dev
);
if
(
!
set_bit
(
0
,
(
void
*
)
&
lp
->
cache
.
lock
))
{
while
(
lp
->
cache
.
skb
&&
!
dev
->
tbusy
&&
lp
->
tx_enable
)
{
de4x5_queue_pkt
(
de4x5_get_cache
(
dev
),
dev
);
}
lp
->
cache
.
lock
=
0
;
}
dev
->
interrupt
=
UNMASK_INTERRUPTS
;
...
...
@@ -1376,7 +1401,7 @@ de4x5_txur(struct device *dev)
int
omr
;
omr
=
inl
(
DE4X5_OMR
);
if
(
!
(
omr
&
OMR_SF
))
{
if
(
!
(
omr
&
OMR_SF
)
||
(
lp
->
chipset
==
DC21041
)
||
(
lp
->
chipset
==
DC21040
)
)
{
omr
&=
~
(
OMR_ST
|
OMR_SR
);
outl
(
omr
,
DE4X5_OMR
);
while
(
inl
(
DE4X5_STS
)
&
STS_TS
);
...
...
@@ -1564,6 +1589,7 @@ eisa_probe(struct device *dev, u_long ioaddr)
u_long
iobase
;
struct
bus_type
*
lp
=
&
bus
;
char
name
[
DE4X5_STRLEN
];
struct
device
*
tmp
;
if
(
!
ioaddr
&&
autoprobed
)
return
;
/* Been here before ! */
...
...
@@ -1589,15 +1615,14 @@ eisa_probe(struct device *dev, u_long ioaddr)
DevicePresent
(
EISA_APROM
);
/* Write the PCI Configuration Registers */
outl
(
PCI_COMMAND_IO
|
PCI_COMMAND_MASTER
,
PCI_CFCS
);
outl
(
0x0000
4
000
,
PCI_CFLT
);
outl
(
0x0000
6
000
,
PCI_CFLT
);
outl
(
iobase
,
PCI_CBIO
);
if
(
check_region
(
iobase
,
DE4X5_EISA_TOTAL_SIZE
)
==
0
)
{
if
((
dev
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
if
((
status
=
de4x5_hw_init
(
dev
,
iobase
))
==
0
)
{
if
((
tmp
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
if
((
status
=
de4x5_hw_init
(
tmp
,
iobase
))
==
0
)
{
num_de4x5s
++
;
}
num_eth
++
;
}
}
else
if
(
autoprobed
)
{
printk
(
"%s: region already allocated at 0x%04lx.
\n
"
,
dev
->
name
,
iobase
);
...
...
@@ -1632,6 +1657,7 @@ pci_probe(struct device *dev, u_long ioaddr)
u_int
class
=
DE4X5_CLASS_CODE
;
u_int
iobase
;
struct
bus_type
*
lp
=
&
bus
;
struct
device
*
tmp
;
if
((
!
ioaddr
||
!
loading_module
)
&&
autoprobed
)
return
;
...
...
@@ -1639,14 +1665,14 @@ pci_probe(struct device *dev, u_long ioaddr)
lp
->
bus
=
PCI
;
if
(
ioaddr
<
0x1000
)
{
if
(
(
ioaddr
<
0x1000
)
&&
loading_module
)
{
pbus
=
(
u_short
)(
ioaddr
>>
8
);
dnum
=
(
u_short
)(
ioaddr
&
0xff
);
}
else
{
pbus
=
0
;
dnum
=
0
;
}
for
(
index
=
0
;
(
pcibios_find_class
(
class
,
index
,
&
pb
,
&
dev_fn
)
!=
PCIBIOS_DEVICE_NOT_FOUND
);
index
++
)
{
...
...
@@ -1667,7 +1693,7 @@ pci_probe(struct device *dev, u_long ioaddr)
/* Get the board I/O address */
pcibios_read_config_dword
(
pb
,
PCI_DEVICE
,
PCI_BASE_ADDRESS_0
,
&
iobase
);
iobase
&=
CBIO_MASK
;
/* Fetch the IRQ to be used */
pcibios_read_config_byte
(
pb
,
PCI_DEVICE
,
PCI_INTERRUPT_LINE
,
&
irq
);
if
((
irq
==
0
)
||
(
irq
==
(
u_char
)
0xff
))
continue
;
...
...
@@ -1684,12 +1710,11 @@ pci_probe(struct device *dev, u_long ioaddr)
DevicePresent
(
DE4X5_APROM
);
if
(
check_region
(
iobase
,
DE4X5_PCI_TOTAL_SIZE
)
==
0
)
{
if
((
dev
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
dev
->
irq
=
irq
;
if
((
status
=
de4x5_hw_init
(
dev
,
iobase
))
==
0
)
{
if
((
tmp
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
tmp
->
irq
=
irq
;
if
((
status
=
de4x5_hw_init
(
tmp
,
iobase
))
==
0
)
{
num_de4x5s
++
;
}
num_eth
++
;
}
}
else
if
(
autoprobed
)
{
printk
(
"%s: region already allocated at 0x%04x.
\n
"
,
dev
->
name
,
...
...
@@ -1702,109 +1727,95 @@ pci_probe(struct device *dev, u_long ioaddr)
}
/*
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
** Search the entire 'eth' device list for a fixed probe. If a match isn't
** found then check for an autoprobe or unused device location. If they
** are not available then insert a new device structure at the end of
** the current list.
*/
static
struct
device
*
alloc_device
(
struct
device
*
dev
,
u_long
iobase
)
{
int
addAutoProbe
=
0
;
struct
device
*
tmp
=
NULL
,
*
ret
;
int
(
*
init
)(
struct
device
*
)
=
NULL
;
struct
device
*
adev
=
NULL
;
int
fixed
=
0
,
new_dev
=
0
;
num_eth
=
de4x5_dev_index
(
dev
->
name
);
if
(
loading_module
)
return
dev
;
/*
** Check the device structures for an end of list or unused device
*/
while
(
dev
->
next
!=
NULL
)
{
if
((
dev
->
base_addr
==
DE4X5_NDA
)
||
(
dev
->
base_addr
==
0
))
break
;
dev
=
dev
->
next
;
/* walk through eth device list */
num_eth
++
;
/* increment eth device number */
while
(
1
)
{
if
(((
dev
->
base_addr
==
DE4X5_NDA
)
||
(
dev
->
base_addr
==
0
))
&&
!
adev
)
{
adev
=
dev
;
}
else
if
((
dev
->
priv
==
NULL
)
&&
(
dev
->
base_addr
==
iobase
))
{
fixed
=
1
;
}
else
{
if
(
dev
->
next
==
NULL
)
{
new_dev
=
1
;
}
else
if
(
strncmp
(
dev
->
next
->
name
,
"eth"
,
3
)
!=
0
)
{
new_dev
=
1
;
}
}
if
((
dev
->
next
==
NULL
)
||
new_dev
||
fixed
)
break
;
dev
=
dev
->
next
;
num_eth
++
;
}
/*
** If an autoprobe is requested for another device, we must re-insert
** the request later in the list. Remember the current position first.
*/
if
((
dev
->
base_addr
==
0
)
&&
(
num_de4x5s
>
0
))
{
addAutoProbe
++
;
tmp
=
dev
->
next
;
/* point to the next device */
init
=
dev
->
init
;
/* remember the probe function */
if
(
adev
&&
!
fixed
)
{
dev
=
adev
;
num_eth
=
de4x5_dev_index
(
dev
->
name
);
new_dev
=
0
;
}
if
(((
dev
->
next
==
NULL
)
&&
((
dev
->
base_addr
!=
DE4X5_NDA
)
&&
(
dev
->
base_addr
!=
0
))
&&
!
fixed
)
||
new_dev
)
{
num_eth
++
;
/* New device */
dev
=
insert_device
(
dev
,
iobase
,
de4x5_probe
);
}
/*
** If at end of list and can't use current entry, malloc one up.
** If memory could not be allocated, print an error message.
*/
if
((
dev
->
next
==
NULL
)
&&
!
((
dev
->
base_addr
==
DE4X5_NDA
)
||
(
dev
->
base_addr
==
0
)))
{
dev
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
dev
=
dev
->
next
;
/* point to the new device */
if
(
dev
==
NULL
)
{
printk
(
"eth%d: Device not initialised, insufficient memory
\n
"
,
num_eth
);
return
dev
;
}
/*
** If at end of eth device list and can't use current entry, malloc
** one up. If memory could not be allocated, print an error message.
*/
static
struct
device
*
insert_device
(
struct
device
*
dev
,
u_long
iobase
,
int
(
*
init
)(
struct
device
*
))
{
struct
device
*
new
;
new
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
if
(
new
==
NULL
)
{
printk
(
"eth%d: Device not initialised, insufficient memory
\n
"
,
num_eth
);
return
NULL
;
}
else
{
new
->
next
=
dev
->
next
;
dev
->
next
=
new
;
dev
=
dev
->
next
;
/* point to the new device */
dev
->
name
=
(
char
*
)(
dev
+
1
);
if
(
num_eth
>
9999
)
{
sprintf
(
dev
->
name
,
"eth????"
);
/* New device name */
}
else
{
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
dev
->
name
=
(
char
*
)(
dev
+
1
);
if
(
num_eth
>
9999
)
{
sprintf
(
dev
->
name
,
"eth????"
);
/* New device name */
}
else
{
sprintf
(
dev
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
}
dev
->
base_addr
=
iobase
;
/* assign the io address */
dev
->
next
=
NULL
;
/* mark the end of list */
dev
->
init
=
&
de4x5_probe
;
/* initialisation routine */
num_de4x5s
++
;
sprintf
(
dev
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
}
dev
->
base_addr
=
iobase
;
/* assign the io address */
dev
->
init
=
init
;
/* initialisation routine */
}
ret
=
dev
;
/* return current struct, or NULL */
/*
** Now figure out what to do with the autoprobe that has to be inserted.
** Firstly, search the (possibly altered) list for an empty space.
*/
if
(
ret
!=
NULL
)
{
if
(
addAutoProbe
)
{
for
(;
(
tmp
->
next
!=
NULL
)
&&
(
tmp
->
base_addr
!=
DE4X5_NDA
);
tmp
=
tmp
->
next
);
/*
** If no more device structures and can't use the current one,
** malloc one up. If memory could not be allocated, print an error
**message.
*/
if
((
tmp
->
next
==
NULL
)
&&
!
(
tmp
->
base_addr
==
DE4X5_NDA
))
{
tmp
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
tmp
=
tmp
->
next
;
/* point to the new device */
if
(
tmp
==
NULL
)
{
printk
(
"%s: Insufficient memory to extend the device list.
\n
"
,
dev
->
name
);
}
else
{
/*
** If the memory was allocated, point to the new memory
** area and initialize it (name, I/O address, next device
** (NULL) and initialisation probe routine).
*/
tmp
->
name
=
(
char
*
)(
tmp
+
1
);
if
(
num_eth
>
9999
)
{
sprintf
(
tmp
->
name
,
"eth????"
);
}
else
{
/* New device name */
sprintf
(
tmp
->
name
,
"eth%d"
,
num_eth
);
}
tmp
->
base_addr
=
0
;
/* re-insert the io address */
tmp
->
next
=
NULL
;
/* mark the end of list */
tmp
->
init
=
init
;
/* initialisation routine */
}
}
else
{
/* structure already exists */
tmp
->
base_addr
=
0
;
/* re-insert the io address */
}
}
return
dev
;
}
static
int
de4x5_dev_index
(
char
*
s
)
{
int
i
=
0
,
j
=
0
;
for
(;
*
s
;
s
++
)
{
if
(
isdigit
(
*
s
))
{
j
=
1
;
i
=
(
i
*
10
)
+
(
*
s
-
'0'
);
}
else
if
(
j
)
break
;
}
return
ret
;
return
i
;
}
/*
...
...
@@ -2381,8 +2392,10 @@ de4x5_init_connection(struct device *dev)
de4x5_setup_intr
(
dev
);
lp
->
lostMedia
=
0
;
lp
->
tx_enable
=
YES
;
dev
->
tbusy
=
0
;
sti
();
outl
(
POLL_DEMAND
,
DE4X5_TPD
);
mark_bh
(
NET_BH
);
return
;
}
...
...
@@ -2643,8 +2656,9 @@ de4x5_alloc_rx_buff(struct device *dev, int index, int len)
ret
=
lp
->
rx_skb
[
index
];
lp
->
rx_skb
[
index
]
=
p
;
if
((
unsigned
long
)
ret
>
1
)
skb_put
(
ret
,
len
);
if
((
u_long
)
ret
>
1
)
{
skb_put
(
ret
,
len
);
}
return
ret
;
...
...
@@ -2675,7 +2689,7 @@ de4x5_free_rx_buffs(struct device *dev)
int
i
;
for
(
i
=
0
;
i
<
lp
->
rxRingSize
;
i
++
)
{
if
((
u
nsigned
long
)
lp
->
rx_skb
[
i
]
>
1
)
{
if
((
u
_
long
)
lp
->
rx_skb
[
i
]
>
1
)
{
dev_kfree_skb
(
lp
->
rx_skb
[
i
],
FREE_WRITE
);
}
lp
->
rx_ring
[
i
].
status
=
0
;
...
...
@@ -2728,7 +2742,6 @@ de4x5_save_skbs(struct device *dev)
de4x5_cache_state
(
dev
,
DE4X5_SAVE_STATE
);
de4x5_sw_reset
(
dev
);
de4x5_cache_state
(
dev
,
DE4X5_RESTORE_STATE
);
dev
->
tbusy
=
0
;
lp
->
cache
.
save_cnt
++
;
START_DE4X5
;
}
...
...
@@ -2748,7 +2761,6 @@ de4x5_restore_skbs(struct device *dev)
de4x5_cache_state
(
dev
,
DE4X5_SAVE_STATE
);
de4x5_sw_reset
(
dev
);
de4x5_cache_state
(
dev
,
DE4X5_RESTORE_STATE
);
dev
->
tbusy
=
0
;
lp
->
cache
.
save_cnt
--
;
START_DE4X5
;
}
...
...
@@ -3074,7 +3086,7 @@ get_hw_addr(struct device *dev)
}
else
if
(
!
broken
)
{
dev
->
dev_addr
[
i
]
=
(
u_char
)
lp
->
srom
.
ieee_addr
[
i
];
i
++
;
dev
->
dev_addr
[
i
]
=
(
u_char
)
lp
->
srom
.
ieee_addr
[
i
];
i
++
;
}
else
if
(
broken
==
SMC
)
{
/* Assume SMC9332 for now */
}
else
if
(
(
broken
==
SMC
)
||
(
broken
==
ACCTON
))
{
dev
->
dev_addr
[
i
]
=
*
((
u_char
*
)
&
lp
->
srom
+
i
);
i
++
;
dev
->
dev_addr
[
i
]
=
*
((
u_char
*
)
&
lp
->
srom
+
i
);
i
++
;
}
...
...
@@ -3118,7 +3130,11 @@ de4x5_bad_srom(struct bus_type *lp)
for
(
i
=
0
;
i
<
sizeof
(
enet_det
)
/
ETH_ALEN
;
i
++
)
{
if
(
!
de4x5_strncmp
((
char
*
)
&
lp
->
srom
,
(
char
*
)
&
enet_det
[
i
],
3
)
&&
!
de4x5_strncmp
((
char
*
)
&
lp
->
srom
+
0x10
,
(
char
*
)
&
enet_det
[
i
],
3
))
{
status
=
SMC
;
if
(
i
==
0
)
{
status
=
SMC
;
}
else
if
(
i
==
1
)
{
status
=
ACCTON
;
}
break
;
}
}
...
...
@@ -4123,8 +4139,8 @@ cleanup_module(void)
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/
usr/src/linux/net/inet
-Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c"
* compile-command: "gcc -D__KERNEL__ -I/
linux/include
-Wall -Wstrict-prototypes
-fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2
-O2 -m486 -c de4x5.c"
*
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/
usr/src/linux/net/inet
-Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c"
* compile-command: "gcc -D__KERNEL__ -DMODULE -I/
linux/include
-Wall -Wstrict-prototypes
-fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2
-O2 -m486 -c de4x5.c"
* End:
*/
This diff is collapsed.
Click to expand it.
drivers/net/net_init.c
View file @
a96e1f22
...
...
@@ -20,6 +20,8 @@
Use dev_close cleanly so we always shut things down tidily.
Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses.
14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function.
*/
#include <linux/config.h>
...
...
@@ -144,6 +146,14 @@ static int eth_mac_addr(struct device *dev, void *p)
return
0
;
}
static
int
eth_change_mtu
(
struct
device
*
dev
,
int
new_mtu
)
{
if
((
new_mtu
<
68
)
||
(
new_mtu
>
1500
))
return
-
EINVAL
;
dev
->
mtu
=
new_mtu
;
return
0
;
}
void
ether_setup
(
struct
device
*
dev
)
{
int
i
;
...
...
@@ -165,6 +175,7 @@ void ether_setup(struct device *dev)
}
}
dev
->
change_mtu
=
eth_change_mtu
;
dev
->
hard_header
=
eth_header
;
dev
->
rebuild_header
=
eth_rebuild_header
;
dev
->
set_mac_address
=
eth_mac_addr
;
...
...
This diff is collapsed.
Click to expand it.
drivers/net/slhc.c
View file @
a96e1f22
...
...
@@ -107,29 +107,27 @@ slhc_init(int rslots, int tslots)
memset
(
comp
,
0
,
sizeof
(
struct
slcompress
));
if
(
rslots
>
0
&&
rslots
<
256
)
{
comp
->
rstate
=
(
struct
cstate
*
)
kmalloc
(
rslots
*
sizeof
(
struct
cstate
),
GFP_KERNEL
);
size_t
rsize
=
rslots
*
sizeof
(
struct
cstate
);
comp
->
rstate
=
(
struct
cstate
*
)
kmalloc
(
rsize
,
GFP_KERNEL
);
if
(
!
comp
->
rstate
)
{
kfree
((
unsigned
char
*
)
comp
);
return
NULL
;
}
memset
(
comp
->
rstate
,
0
,
rs
lots
*
sizeof
(
struct
cstate
)
);
memset
(
comp
->
rstate
,
0
,
rs
ize
);
comp
->
rslot_limit
=
rslots
-
1
;
}
if
(
tslots
>
0
&&
tslots
<
256
)
{
comp
->
tstate
=
(
struct
cstate
*
)
kmalloc
(
tslots
*
sizeof
(
struct
cstate
),
GFP_KERNEL
);
size_t
tsize
=
tslots
*
sizeof
(
struct
cstate
);
comp
->
tstate
=
(
struct
cstate
*
)
kmalloc
(
tsize
,
GFP_KERNEL
);
if
(
!
comp
->
tstate
)
{
kfree
((
unsigned
char
*
)
comp
->
rstate
);
kfree
((
unsigned
char
*
)
comp
);
return
NULL
;
}
memset
(
comp
->
tstate
,
0
,
ts
lots
*
sizeof
(
struct
cstate
)
);
memset
(
comp
->
tstate
,
0
,
ts
ize
);
comp
->
tslot_limit
=
tslots
-
1
;
}
...
...
This diff is collapsed.
Click to expand it.
drivers/net/wic.c
View file @
a96e1f22
...
...
@@ -49,7 +49,7 @@ char *version = "NET3 WIC version 0.9 hayes@netplumbing.com";
#include <asm/bitops.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <string.h>
#include <
linux/
string.h>
#define NET_DEBUG 1
/* Use 0 for production, 1 for verification, >2 for debug */
...
...
This diff is collapsed.
Click to expand it.
drivers/scsi/Config.in
View file @
a96e1f22
...
...
@@ -48,9 +48,7 @@ dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONF
dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI
if [ "$CONFIG_PCI" = "y" ]; then
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI
fi
dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
...
...
This diff is collapsed.
Click to expand it.
drivers/scsi/README.st
View file @
a96e1f22
This
file
contains
brief
information
about
the
SCSI
tape
driver
.
Last
modified:
Wed
May
1
11
:
51
:
35
1996
by
root@
kai
.
makisara
.
fi
The
driver
is
currently
maintained
by
Kai
M
{
kisara
(
email
Kai
.
Makisara
@
metla
.
fi
)
Last
modified:
Sun
Jun
30
15
:
47
:
14
1996
by
root@
kai
.
makisara
.
fi
BASICS
...
...
@@ -85,13 +88,15 @@ the SCSI adapter. The following buffering options are selectable at
compile time and/or at run time (via ioctl):
Buffering of data across write calls in fixed block mode (define
ST_BUFFER_WRITES). This should be disabled if reliable detection of
end of medium (EOM) for fixed block mode is desired.
ST_BUFFER_WRITES).
Asynchronous writing. Writing the buffer contents to the tape is
started and the write call returns immediately. The status is checked
at the next tape operation. Should not used if reliable EOM detection
is desired.
at the next tape operation.
Buffered writes and asynchronous writes may in some rare cases cause
problems in multivolume operations if there is not enough space after
the early-warning mark to flush the driver buffer.
Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is
attempted even if the user does not want to get all of the data at
...
...
@@ -187,7 +192,8 @@ MTCOMPRESSION Sets compressing or uncompressing drive mode using the
control of compression. Some drives (like the Exabytes) use
density codes for compression control. Some drives use another
mode page but this page has not been implemented in the
driver.
driver. Some drives without compression capability will accept
any compression mode without error.
MTSETPART Moves the tape to the partition given by the argument at the
next tape operation. The block at which the tape is positioned
is the block where the tape was previously positioned in the
...
...
@@ -310,5 +316,3 @@ within file can be obtained if ST_IN_FILE_POS is defined at compile
time
or
the
MT_ST_CAN_BSR
bit
is
set
for
the
drive
with
an
ioctl
.
(
The
driver
always
backs
over
a
filemark
crossed
by
read
ahead
if
the
user
does
not
request
data
that
far
.)
Kai
M
{
kisara
This diff is collapsed.
Click to expand it.
drivers/scsi/hosts.h
View file @
a96e1f22
...
...
@@ -244,7 +244,7 @@ struct Scsi_Host
unsigned
short
extra_bytes
;
volatile
unsigned
char
host_busy
;
char
host_no
;
/* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
int
last_reset
;
unsigned
long
last_reset
;
struct
wait_queue
*
host_wait
;
Scsi_Cmnd
*
host_queue
;
Scsi_Host_Template
*
hostt
;
...
...
This diff is collapsed.
Click to expand it.
drivers/scsi/qlogicisp.c
View file @
a96e1f22
This diff is collapsed.
Click to expand it.
drivers/scsi/qlogicisp.h
View file @
a96e1f22
...
...
@@ -43,6 +43,21 @@
#ifndef _QLOGICISP_H
#define _QLOGICISP_H
/*
* With the qlogic interface, every queue slot can hold a SCSI
* command with up to 4 scatter/gather entries. If we need more
* than 4 entries, continuation entries can be used that hold
* another 7 entries each. Unlike for other drivers, this means
* that the maximum number of scatter/gather entries we can
* support at any given time is a function of the number of queue
* slots available. That is, host->can_queue and host->sg_tablesize
* are dynamic and _not_ independent. This all works fine because
* requests are queued serially and the scatter/gather limit is
* determined for each queue request anew.
*/
#define QLOGICISP_REQ_QUEUE_LEN 63
/* must be power of two - 1 */
#define QLOGICISP_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
int
isp1020_detect
(
Scsi_Host_Template
*
);
int
isp1020_release
(
struct
Scsi_Host
*
);
const
char
*
isp1020_info
(
struct
Scsi_Host
*
);
...
...
@@ -57,28 +72,28 @@ int isp1020_biosparam(Disk *, kdev_t, int[]);
extern
struct
proc_dir_entry
proc_scsi_isp1020
;
#define QLOGICISP { \
/* next */
NULL, \
/* usage_count */
NULL, \
/* proc dir */
NULL,
\
/* procfs info */
NULL,
\
/* name */
NULL, \
/* detect */
isp1020_detect, \
/* release */
isp1020_release, \
/* info */
isp1020_info, \
/* command */
NULL,
\
/* queuecommand */
isp1020_queuecommand, \
/* abort */
isp1020_abort, \
/* reset */
isp1020_reset, \
/* slave_attach */
NULL, \
/* bios_param */
isp1020_biosparam, \
/* can_queue */
8,
\
/* this_id */
-1, \
/* sg_tablesize */
4,
\
/* cmd_per_lun */
1, \
/* present */
0, \
/* unchecked_isa_dma */
0, \
/* use_clustering */
DISABLE_CLUSTERING \
#define QLOGICISP {
\
/* next */
NULL,
\
/* usage_count */
NULL,
\
/* proc dir */
NULL,
\
/* procfs info */
NULL,
\
/* name */
NULL,
\
/* detect */
isp1020_detect,
\
/* release */
isp1020_release,
\
/* info */
isp1020_info,
\
/* command */
NULL,
\
/* queuecommand */
isp1020_queuecommand,
\
/* abort */
isp1020_abort,
\
/* reset */
isp1020_reset,
\
/* slave_attach */
NULL,
\
/* bios_param */
isp1020_biosparam,
\
/* can_queue */
QLOGICISP_REQ_QUEUE_LEN,
\
/* this_id */
-1,
\
/* sg_tablesize */
QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN),
\
/* cmd_per_lun */
1,
\
/* present */
0,
\
/* unchecked_isa_dma */
0,
\
/* use_clustering */
DISABLE_CLUSTERING
\
}
#endif
/* _QLOGICISP_H */
This diff is collapsed.
Click to expand it.
drivers/scsi/scsi.c
View file @
a96e1f22
...
...
@@ -1184,27 +1184,38 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
inline
void
internal_cmnd
(
Scsi_Cmnd
*
SCpnt
)
{
int
temp
;
unsigned
long
flags
,
timeout
;
struct
Scsi_Host
*
host
;
unsigned
int
flags
;
#ifdef DEBUG_DELAY
int
clock
;
unsigned
long
clock
;
#endif
host
=
SCpnt
->
host
;
/*
* We will wait MIN_RESET_DELAY clock ticks after the last reset so
* we can avoid the drive not being ready.
*/
save_flags
(
flags
);
cli
();
/* Assign a unique nonzero serial_number. */
if
(
++
serial_number
==
0
)
serial_number
=
1
;
SCpnt
->
serial_number
=
serial_number
;
sti
();
temp
=
host
->
last_reset
+
MIN_RESET_DELAY
;
while
(
jiffies
<
temp
);
/*
* We will wait MIN_RESET_DELAY clock ticks after the last reset so
* we can avoid the drive not being ready.
*/
timeout
=
host
->
last_reset
+
MIN_RESET_DELAY
;
if
(
jiffies
<
timeout
)
{
/*
* NOTE: This may be executed from within an interrupt
* handler! This is bad, but for now, it'll do. The irq
* level of the interrupt handler has been masked out by the
* platform dependent interrupt handling code already, so the
* sti() here will not cause another call to the SCSI host's
* interrupt handler (assuming there is one irq-level per
* host).
*/
sti
();
while
(
jiffies
<
timeout
)
barrier
();
}
restore_flags
(
flags
);
update_timeout
(
SCpnt
,
SCpnt
->
timeout_per_command
);
...
...
@@ -1245,15 +1256,16 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
}
else
{
int
temp
;
#ifdef DEBUG
printk
(
"command() : routine at %p
\n
"
,
host
->
hostt
->
command
);
#endif
temp
=
host
->
hostt
->
command
(
SCpnt
);
temp
=
host
->
hostt
->
command
(
SCpnt
);
SCpnt
->
result
=
temp
;
#ifdef DEBUG_DELAY
clock
=
jiffies
+
4
*
HZ
;
while
(
jiffies
<
clock
);
while
(
jiffies
<
clock
)
barrier
()
;
printk
(
"done(host = %d, result = %04x) : routine at %p
\n
"
,
host
->
host_no
,
temp
,
host
->
hostt
->
command
);
#endif
...
...
@@ -2055,10 +2067,11 @@ int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
* Protect against races here. If the command is done, or we are
* on a different command forget it.
*/
if
(
SCpnt
->
serial_number
!=
SCpnt
->
serial_number_at_timeout
)
{
if
(
reset_flags
&
SCSI_RESET_ASYNCHRONOUS
)
if
(
SCpnt
->
serial_number
!=
SCpnt
->
serial_number_at_timeout
)
{
restore_flags
(
flags
);
return
0
;
}
}
if
(
SCpnt
->
internal_timeout
&
IN_RESET
)
{
...
...
This diff is collapsed.
Click to expand it.
drivers/scsi/scsi.h
View file @
a96e1f22
...
...
@@ -202,7 +202,7 @@ typedef struct scsi_device {
* Use these to separate status msg and our bytes
*/
#define status_byte(result) (((result) >> 1) & 0xf)
#define status_byte(result) (((result) >> 1) & 0x
1
f)
#define msg_byte(result) (((result) >> 8) & 0xff)
#define host_byte(result) (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
...
...
This diff is collapsed.
Click to expand it.
drivers/scsi/sg.c
View file @
a96e1f22
...
...
@@ -230,7 +230,7 @@ static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
* Now copy the result back to the user buffer.
*/
device
->
header
.
pack_len
=
device
->
header
.
reply_len
;
device
->
header
.
result
=
0
;
if
(
count
>=
sizeof
(
struct
sg_header
))
{
memcpy_tofs
(
buf
,
&
device
->
header
,
sizeof
(
struct
sg_header
));
...
...
@@ -242,7 +242,7 @@ static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
}
}
else
count
=
0
;
count
=
device
->
header
.
result
==
0
?
0
:
-
EIO
;
/*
* Clean up, and release the device so that we can send another
...
...
@@ -276,12 +276,7 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
* wrong.
*/
memcpy
(
device
->
header
.
sense_buffer
,
SCpnt
->
sense_buffer
,
sizeof
(
SCpnt
->
sense_buffer
));
if
(
SCpnt
->
sense_buffer
[
0
])
{
device
->
header
.
result
=
EIO
;
}
else
device
->
header
.
result
=
SCpnt
->
result
;
device
->
header
.
result
=
SCpnt
->
result
;
/*
* Now wake up the process that is waiting for the
...
...
@@ -593,6 +588,11 @@ static void sg_detach(Scsi_Device * SDp)
gpnt
->
device
=
NULL
;
SDp
->
attached
--
;
sg_template
.
nr_dev
--
;
/*
* avoid associated device /dev/sg? bying incremented
* each time module is inserted/removed , <dan@lectra.fr>
*/
sg_template
.
dev_noticed
--
;
return
;
}
return
;
...
...
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
6
7
…
11
Next
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