Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
08aa4ea8
Commit
08aa4ea8
authored
May 13, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk/linux-2.5-pcmcia
into penguin.transmeta.com:/home/torvalds/v2.5/linux
parents
29b25594
77e62b64
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
418 additions
and
312 deletions
+418
-312
drivers/pcmcia/cs.c
drivers/pcmcia/cs.c
+410
-311
drivers/pcmcia/cs_internal.h
drivers/pcmcia/cs_internal.h
+8
-1
No files found.
drivers/pcmcia/cs.c
View file @
08aa4ea8
...
...
@@ -302,11 +302,8 @@ static int proc_read_clients(char *buf, char **start, off_t pos,
======================================================================*/
static
int
setup_socket
(
socket_info_t
*
);
static
void
shutdown_socket
(
socket_info_t
*
);
static
void
reset_socket
(
socket_info_t
*
);
static
void
unreset_socket
(
socket_info_t
*
);
static
void
parse_events
(
void
*
info
,
u_int
events
);
static
int
pccardd
(
void
*
__skt
);
void
pcmcia_unregister_socket
(
struct
class_device
*
dev
);
#define to_class_data(dev) dev->class_data
...
...
@@ -317,7 +314,7 @@ int pcmcia_register_socket(struct class_device *class_dev)
{
struct
pcmcia_socket_class_data
*
cls_d
=
class_get_devdata
(
class_dev
);
socket_info_t
*
s_info
;
unsigned
int
i
,
j
;
unsigned
int
i
,
j
,
ret
;
if
(
!
cls_d
)
return
-
EINVAL
;
...
...
@@ -330,6 +327,7 @@ int pcmcia_register_socket(struct class_device *class_dev)
memset
(
s_info
,
0
,
cls_d
->
nsock
*
sizeof
(
socket_info_t
));
cls_d
->
s_info
=
s_info
;
ret
=
0
;
/* socket initialization */
for
(
i
=
0
;
i
<
cls_d
->
nsock
;
i
++
)
{
...
...
@@ -344,7 +342,7 @@ int pcmcia_register_socket(struct class_device *class_dev)
s
->
erase_busy
.
next
=
s
->
erase_busy
.
prev
=
&
s
->
erase_busy
;
INIT_LIST_HEAD
(
&
s
->
cis_cache
);
spin_lock_init
(
&
s
->
lock
);
/* TBD: remove usage of socket_table, use class_for_each_dev instead */
for
(
j
=
0
;
j
<
sockets
;
j
++
)
if
(
socket_table
[
j
]
==
NULL
)
break
;
...
...
@@ -353,6 +351,20 @@ int pcmcia_register_socket(struct class_device *class_dev)
init_socket
(
s
);
s
->
ss_entry
->
inquire_socket
(
s
->
sock
,
&
s
->
cap
);
init_completion
(
&
s
->
thread_done
);
init_waitqueue_head
(
&
s
->
thread_wait
);
init_MUTEX
(
&
s
->
skt_sem
);
spin_lock_init
(
&
s
->
thread_lock
);
ret
=
kernel_thread
(
pccardd
,
s
,
CLONE_KERNEL
);
if
(
ret
<
0
)
{
pcmcia_unregister_socket
(
class_dev
);
break
;
}
wait_for_completion
(
&
s
->
thread_done
);
BUG_ON
(
!
s
->
thread
);
#ifdef CONFIG_PROC_FS
if
(
proc_pccard
)
{
char
name
[
3
];
...
...
@@ -368,7 +380,7 @@ int pcmcia_register_socket(struct class_device *class_dev)
}
#endif
}
return
0
;
return
ret
;
}
/* pcmcia_register_socket */
...
...
@@ -407,8 +419,12 @@ void pcmcia_unregister_socket(struct class_device *class_dev)
remove_proc_entry
(
name
,
proc_pccard
);
}
#endif
shutdown_socket
(
s
);
if
(
s
->
thread
)
{
init_completion
(
&
s
->
thread_done
);
s
->
thread
=
NULL
;
wake_up
(
&
s
->
thread_wait
);
wait_for_completion
(
&
s
->
thread_done
);
}
release_cis_mem
(
s
);
while
(
s
->
clients
)
{
client
=
s
->
clients
;
...
...
@@ -450,15 +466,6 @@ static void free_regions(memory_handle_t *list)
static
int
send_event
(
socket_info_t
*
s
,
event_t
event
,
int
priority
);
/*
* Sleep for n_cs centiseconds (1 cs = 1/100th of a second)
*/
static
void
cs_sleep
(
unsigned
int
n_cs
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
(
n_cs
*
HZ
+
99
)
/
100
);
}
static
void
shutdown_socket
(
socket_info_t
*
s
)
{
client_t
**
c
;
...
...
@@ -505,132 +512,6 @@ static void shutdown_socket(socket_info_t *s)
free_regions
(
&
s
->
c_region
);
}
/* shutdown_socket */
/*
* Return zero if we think the card isn't actually present
*/
static
int
setup_socket
(
socket_info_t
*
s
)
{
int
val
,
ret
;
int
setup_timeout
=
100
;
/* Wait for "not pending" */
for
(;;)
{
get_socket_status
(
s
,
&
val
);
if
(
!
(
val
&
SS_PENDING
))
break
;
if
(
--
setup_timeout
)
{
cs_sleep
(
10
);
continue
;
}
printk
(
KERN_NOTICE
"cs: socket %p voltage interrogation"
" timed out
\n
"
,
s
);
ret
=
0
;
goto
out
;
}
if
(
val
&
SS_DETECT
)
{
DEBUG
(
1
,
"cs: setup_socket(%p): applying power
\n
"
,
s
);
s
->
state
|=
SOCKET_PRESENT
;
s
->
socket
.
flags
&=
SS_DEBOUNCED
;
if
(
val
&
SS_3VCARD
)
s
->
socket
.
Vcc
=
s
->
socket
.
Vpp
=
33
;
else
if
(
!
(
val
&
SS_XVCARD
))
s
->
socket
.
Vcc
=
s
->
socket
.
Vpp
=
50
;
else
{
printk
(
KERN_NOTICE
"cs: socket %p: unsupported "
"voltage key
\n
"
,
s
);
s
->
socket
.
Vcc
=
0
;
}
if
(
val
&
SS_CARDBUS
)
{
s
->
state
|=
SOCKET_CARDBUS
;
#ifndef CONFIG_CARDBUS
printk
(
KERN_NOTICE
"cs: unsupported card type detected!
\n
"
);
#endif
}
set_socket
(
s
,
&
s
->
socket
);
cs_sleep
(
vcc_settle
);
reset_socket
(
s
);
ret
=
1
;
}
else
{
DEBUG
(
0
,
"cs: setup_socket(%p): no card!
\n
"
,
s
);
ret
=
0
;
}
out:
return
ret
;
}
/* setup_socket */
/*======================================================================
Reset_socket() and unreset_socket() handle hard resets. Resets
have several causes: card insertion, a call to reset_socket, or
recovery from a suspend/resume cycle. Unreset_socket() sends
a CS event that matches the cause of the reset.
======================================================================*/
static
void
reset_socket
(
socket_info_t
*
s
)
{
DEBUG
(
1
,
"cs: resetting socket %p
\n
"
,
s
);
s
->
socket
.
flags
|=
SS_OUTPUT_ENA
|
SS_RESET
;
set_socket
(
s
,
&
s
->
socket
);
udelay
((
long
)
reset_time
);
s
->
socket
.
flags
&=
~
SS_RESET
;
set_socket
(
s
,
&
s
->
socket
);
cs_sleep
(
unreset_delay
);
unreset_socket
(
s
);
}
/* reset_socket */
#define EVENT_MASK \
(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
static
void
unreset_socket
(
socket_info_t
*
s
)
{
int
setup_timeout
=
unreset_limit
;
int
val
;
/* Wait for "ready" */
for
(;;)
{
get_socket_status
(
s
,
&
val
);
if
(
val
&
SS_READY
)
break
;
DEBUG
(
2
,
"cs: socket %d not ready yet
\n
"
,
s
->
sock
);
if
(
--
setup_timeout
)
{
cs_sleep
(
unreset_check
);
continue
;
}
printk
(
KERN_NOTICE
"cs: socket %p timed out during"
" reset. Try increasing setup_delay.
\n
"
,
s
);
s
->
state
&=
~
EVENT_MASK
;
return
;
}
DEBUG
(
1
,
"cs: reset done on socket %p
\n
"
,
s
);
if
(
s
->
state
&
SOCKET_SUSPEND
)
{
s
->
state
&=
~
EVENT_MASK
;
if
(
verify_cis_cache
(
s
)
!=
0
)
parse_events
(
s
,
SS_DETECT
);
else
send_event
(
s
,
CS_EVENT_PM_RESUME
,
CS_EVENT_PRI_LOW
);
}
else
if
(
s
->
state
&
SOCKET_SETUP_PENDING
)
{
#ifdef CONFIG_CARDBUS
if
(
s
->
state
&
SOCKET_CARDBUS
)
{
cb_alloc
(
s
);
s
->
state
|=
SOCKET_CARDBUS_CONFIG
;
}
#endif
send_event
(
s
,
CS_EVENT_CARD_INSERTION
,
CS_EVENT_PRI_LOW
);
s
->
state
&=
~
SOCKET_SETUP_PENDING
;
}
else
{
send_event
(
s
,
CS_EVENT_CARD_RESET
,
CS_EVENT_PRI_LOW
);
if
(
s
->
reset_handle
)
{
s
->
reset_handle
->
event_callback_args
.
info
=
NULL
;
EVENT
(
s
->
reset_handle
,
CS_EVENT_RESET_COMPLETE
,
CS_EVENT_PRI_LOW
);
}
s
->
state
&=
~
EVENT_MASK
;
}
}
/* unreset_socket */
/*======================================================================
The central event handler. Send_event() sends an event to all
...
...
@@ -661,61 +542,266 @@ static int send_event(socket_info_t *s, event_t event, int priority)
return
ret
;
}
/* send_event */
static
void
do_shutdown
(
socket_info_t
*
s
)
static
void
pcmcia_error
(
socket_info_t
*
skt
,
const
char
*
fmt
,
...
)
{
client_t
*
client
;
if
(
s
->
state
&
SOCKET_SHUTDOWN_PENDING
)
return
;
s
->
state
|=
SOCKET_SHUTDOWN_PENDING
;
send_event
(
s
,
CS_EVENT_CARD_REMOVAL
,
CS_EVENT_PRI_HIGH
);
for
(
client
=
s
->
clients
;
client
;
client
=
client
->
next
)
if
(
!
(
client
->
Attributes
&
INFO_MASTER_CLIENT
))
client
->
state
|=
CLIENT_STALE
;
if
(
s
->
state
&
(
SOCKET_SETUP_PENDING
|
SOCKET_RESET_PENDING
))
{
DEBUG
(
0
,
"cs: flushing pending setup
\n
"
);
s
->
state
&=
~
EVENT_MASK
;
}
cs_sleep
(
shutdown_delay
);
s
->
state
&=
~
SOCKET_PRESENT
;
shutdown_socket
(
s
);
static
char
buf
[
128
];
va_list
ap
;
int
len
;
va_start
(
ap
,
fmt
);
len
=
vsnprintf
(
buf
,
sizeof
(
buf
),
fmt
,
ap
);
va_end
(
ap
);
buf
[
len
]
=
'\0'
;
printk
(
KERN_ERR
"PCMCIA: socket %p: %s"
,
skt
,
buf
);
}
static
void
parse_events
(
void
*
info
,
u_int
events
)
#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
static
void
socket_remove_drivers
(
socket_info_t
*
skt
)
{
socket_info_t
*
s
=
info
;
if
(
events
&
SS_DETECT
)
{
int
status
;
get_socket_status
(
s
,
&
status
);
if
((
s
->
state
&
SOCKET_PRESENT
)
&&
(
!
(
s
->
state
&
SOCKET_SUSPEND
)
||
!
(
status
&
SS_DETECT
)))
do_shutdown
(
s
);
if
(
status
&
SS_DETECT
)
{
if
(
s
->
state
&
SOCKET_SETUP_PENDING
)
{
DEBUG
(
1
,
"cs: delaying pending setup
\n
"
);
return
;
}
s
->
state
|=
SOCKET_SETUP_PENDING
;
if
(
s
->
state
&
SOCKET_SUSPEND
)
cs_sleep
(
resume_delay
);
else
cs_sleep
(
setup_delay
);
s
->
socket
.
flags
|=
SS_DEBOUNCED
;
if
(
setup_socket
(
s
)
==
0
)
s
->
state
&=
~
SOCKET_SETUP_PENDING
;
s
->
socket
.
flags
&=
~
SS_DEBOUNCED
;
client_t
*
client
;
send_event
(
skt
,
CS_EVENT_CARD_REMOVAL
,
CS_EVENT_PRI_HIGH
);
for
(
client
=
skt
->
clients
;
client
;
client
=
client
->
next
)
if
(
!
(
client
->
Attributes
&
INFO_MASTER_CLIENT
))
client
->
state
|=
CLIENT_STALE
;
}
static
void
socket_shutdown
(
socket_info_t
*
skt
)
{
socket_remove_drivers
(
skt
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
shutdown_delay
));
skt
->
state
&=
~
SOCKET_PRESENT
;
shutdown_socket
(
skt
);
}
static
int
socket_reset
(
socket_info_t
*
skt
)
{
int
status
,
i
;
skt
->
socket
.
flags
|=
SS_OUTPUT_ENA
|
SS_RESET
;
set_socket
(
skt
,
&
skt
->
socket
);
udelay
((
long
)
reset_time
);
skt
->
socket
.
flags
&=
~
SS_RESET
;
set_socket
(
skt
,
&
skt
->
socket
);
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
unreset_delay
));
for
(
i
=
0
;
i
<
unreset_limit
;
i
++
)
{
get_socket_status
(
skt
,
&
status
);
if
(
!
(
status
&
SS_DETECT
))
return
CS_NO_CARD
;
if
(
status
&
SS_READY
)
return
CS_SUCCESS
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
unreset_check
));
}
}
if
(
events
&
SS_BATDEAD
)
send_event
(
s
,
CS_EVENT_BATTERY_DEAD
,
CS_EVENT_PRI_LOW
);
if
(
events
&
SS_BATWARN
)
send_event
(
s
,
CS_EVENT_BATTERY_LOW
,
CS_EVENT_PRI_LOW
);
if
(
events
&
SS_READY
)
{
if
(
!
(
s
->
state
&
SOCKET_RESET_PENDING
))
send_event
(
s
,
CS_EVENT_READY_CHANGE
,
CS_EVENT_PRI_LOW
);
else
DEBUG
(
1
,
"cs: ready change during reset
\n
"
);
}
pcmcia_error
(
skt
,
"time out after reset.
\n
"
);
return
CS_GENERAL_FAILURE
;
}
static
int
socket_setup
(
socket_info_t
*
skt
,
int
initial_delay
)
{
int
status
,
i
;
get_socket_status
(
skt
,
&
status
);
if
(
!
(
status
&
SS_DETECT
))
return
CS_NO_CARD
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
initial_delay
));
for
(
i
=
0
;
i
<
100
;
i
++
)
{
get_socket_status
(
skt
,
&
status
);
if
(
!
(
status
&
SS_DETECT
))
return
CS_NO_CARD
;
if
(
!
(
status
&
SS_PENDING
))
break
;
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
10
));
}
if
(
status
&
SS_PENDING
)
{
pcmcia_error
(
skt
,
"voltage interrogation timed out.
\n
"
);
return
CS_GENERAL_FAILURE
;
}
if
(
status
&
SS_CARDBUS
)
{
skt
->
state
|=
SOCKET_CARDBUS
;
#ifndef CONFIG_CARDBUS
pcmcia_error
(
skt
,
"cardbus cards are not supported.
\n
"
);
return
CS_BAD_TYPE
;
#endif
}
/*
* Decode the card voltage requirements, and apply power to the card.
*/
if
(
status
&
SS_3VCARD
)
skt
->
socket
.
Vcc
=
skt
->
socket
.
Vpp
=
33
;
else
if
(
!
(
status
&
SS_XVCARD
))
skt
->
socket
.
Vcc
=
skt
->
socket
.
Vpp
=
50
;
else
{
pcmcia_error
(
skt
,
"unsupported voltage key.
\n
"
);
return
CS_BAD_TYPE
;
}
skt
->
state
|=
SOCKET_PRESENT
;
skt
->
socket
.
flags
=
SS_DEBOUNCED
;
set_socket
(
skt
,
&
skt
->
socket
);
/*
* Wait "vcc_settle" for the supply to stabilise.
*/
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
cs_to_timeout
(
vcc_settle
));
return
socket_reset
(
skt
);
}
/*
* Handle card insertion. Setup the socket, reset the card,
* and then tell the rest of PCMCIA that a card is present.
*/
static
int
socket_insert
(
socket_info_t
*
skt
)
{
int
ret
;
ret
=
socket_setup
(
skt
,
setup_delay
);
if
(
ret
==
CS_SUCCESS
)
{
#ifdef CONFIG_CARDBUS
if
(
skt
->
state
&
SOCKET_CARDBUS
)
{
cb_alloc
(
skt
);
skt
->
state
|=
SOCKET_CARDBUS_CONFIG
;
}
#endif
send_event
(
skt
,
CS_EVENT_CARD_INSERTION
,
CS_EVENT_PRI_LOW
);
skt
->
socket
.
flags
&=
~
SS_DEBOUNCED
;
}
else
socket_shutdown
(
skt
);
return
ret
;
}
static
int
socket_suspend
(
socket_info_t
*
skt
)
{
if
(
skt
->
state
&
SOCKET_SUSPEND
)
return
CS_IN_USE
;
send_event
(
skt
,
CS_EVENT_PM_SUSPEND
,
CS_EVENT_PRI_LOW
);
suspend_socket
(
skt
);
skt
->
state
|=
SOCKET_SUSPEND
;
return
CS_SUCCESS
;
}
/*
* Resume a socket. If a card is present, verify its CIS against
* our cached copy. If they are different, the card has been
* replaced, and we need to tell the drivers.
*/
static
int
socket_resume
(
socket_info_t
*
skt
)
{
int
ret
;
if
(
!
(
skt
->
state
&
SOCKET_SUSPEND
))
return
CS_IN_USE
;
init_socket
(
skt
);
ret
=
socket_setup
(
skt
,
resume_delay
);
if
(
ret
==
CS_SUCCESS
)
{
/*
* FIXME: need a better check here for cardbus cards.
*/
if
(
verify_cis_cache
(
skt
)
!=
0
)
{
socket_remove_drivers
(
skt
);
destroy_cis_cache
(
skt
);
send_event
(
skt
,
CS_EVENT_CARD_INSERTION
,
CS_EVENT_PRI_LOW
);
}
else
{
send_event
(
skt
,
CS_EVENT_PM_RESUME
,
CS_EVENT_PRI_LOW
);
}
skt
->
socket
.
flags
&=
~
SS_DEBOUNCED
;
}
else
socket_shutdown
(
skt
);
skt
->
state
&=
~
SOCKET_SUSPEND
;
return
CS_SUCCESS
;
}
static
int
pccardd
(
void
*
__skt
)
{
socket_info_t
*
skt
=
__skt
;
DECLARE_WAITQUEUE
(
wait
,
current
);
daemonize
(
"pccardd"
);
skt
->
thread
=
current
;
complete
(
&
skt
->
thread_done
);
add_wait_queue
(
&
skt
->
thread_wait
,
&
wait
);
for
(;;)
{
unsigned
long
flags
;
unsigned
int
events
;
set_current_state
(
TASK_INTERRUPTIBLE
);
spin_lock_irqsave
(
&
skt
->
thread_lock
,
flags
);
events
=
skt
->
thread_events
;
skt
->
thread_events
=
0
;
spin_unlock_irqrestore
(
&
skt
->
thread_lock
,
flags
);
if
(
events
)
{
down
(
&
skt
->
skt_sem
);
if
(
events
&
SS_DETECT
&&
!
(
skt
->
state
&
SOCKET_SUSPEND
))
{
int
status
;
get_socket_status
(
skt
,
&
status
);
if
((
skt
->
state
&
SOCKET_PRESENT
)
&&
!
(
status
&
SS_DETECT
))
socket_shutdown
(
skt
);
if
(
status
&
SS_DETECT
)
socket_insert
(
skt
);
}
if
(
events
&
SS_BATDEAD
)
send_event
(
skt
,
CS_EVENT_BATTERY_DEAD
,
CS_EVENT_PRI_LOW
);
if
(
events
&
SS_BATWARN
)
send_event
(
skt
,
CS_EVENT_BATTERY_LOW
,
CS_EVENT_PRI_LOW
);
if
(
events
&
SS_READY
)
send_event
(
skt
,
CS_EVENT_READY_CHANGE
,
CS_EVENT_PRI_LOW
);
up
(
&
skt
->
skt_sem
);
continue
;
}
schedule
();
if
(
!
skt
->
thread
)
break
;
}
remove_wait_queue
(
&
skt
->
thread_wait
,
&
wait
);
socket_shutdown
(
skt
);
complete_and_exit
(
&
skt
->
thread_done
,
0
);
}
static
void
parse_events
(
void
*
info
,
u_int
events
)
{
socket_info_t
*
s
=
info
;
spin_lock
(
&
s
->
thread_lock
);
s
->
thread_events
|=
events
;
spin_unlock
(
&
s
->
thread_lock
);
wake_up
(
&
s
->
thread_wait
);
}
/* parse_events */
/*======================================================================
...
...
@@ -727,27 +813,18 @@ static void parse_events(void *info, u_int events)
======================================================================*/
void
pcmcia_suspend_socket
(
socket_info_t
*
s
)
void
pcmcia_suspend_socket
(
socket_info_t
*
s
kt
)
{
if
((
s
->
state
&
SOCKET_PRESENT
)
&&
!
(
s
->
state
&
SOCKET_SUSPEND
))
{
send_event
(
s
,
CS_EVENT_PM_SUSPEND
,
CS_EVENT_PRI_LOW
);
suspend_socket
(
s
);
s
->
state
|=
SOCKET_SUSPEND
;
}
down
(
&
skt
->
skt_sem
);
socket_suspend
(
skt
);
up
(
&
skt
->
skt_sem
);
}
void
pcmcia_resume_socket
(
socket_info_t
*
s
)
void
pcmcia_resume_socket
(
socket_info_t
*
s
kt
)
{
int
stat
;
/* Do this just to reinitialize the socket */
init_socket
(
s
);
get_socket_status
(
s
,
&
stat
);
/* If there was or is a card here, we need to do something
about it... but parse_events will sort it all out. */
if
((
s
->
state
&
SOCKET_PRESENT
)
||
(
stat
&
SS_DETECT
))
parse_events
(
s
,
SS_DETECT
);
down
(
&
skt
->
skt_sem
);
socket_resume
(
skt
);
up
(
&
skt
->
skt_sem
);
}
...
...
@@ -1461,15 +1538,8 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
s
=
socket_table
[
ns
];
if
(
++
s
->
real_clients
==
1
)
{
int
status
;
register_callback
(
s
,
&
parse_events
,
s
);
get_socket_status
(
s
,
&
status
);
if
((
status
&
SS_DETECT
)
&&
!
(
s
->
state
&
SOCKET_SETUP_PENDING
))
{
s
->
state
|=
SOCKET_SETUP_PENDING
;
if
(
setup_socket
(
s
)
==
0
)
s
->
state
&=
~
SOCKET_SETUP_PENDING
;
}
parse_events
(
s
,
SS_DETECT
);
}
*
handle
=
client
;
...
...
@@ -2022,30 +2092,44 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
int
pcmcia_reset_card
(
client_handle_t
handle
,
client_req_t
*
req
)
{
int
i
,
re
t
;
socket_info_t
*
s
;
socket_info_t
*
sk
t
;
int
ret
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
i
=
handle
->
Socket
;
s
=
socket_table
[
i
];
if
(
!
(
s
->
state
&
SOCKET_PRESENT
))
return
CS_NO_CARD
;
if
(
s
->
state
&
SOCKET_RESET_PENDING
)
return
CS_IN_USE
;
s
->
state
|=
SOCKET_RESET_PENDING
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
DEBUG
(
1
,
"cs: resetting socket %d
\n
"
,
handle
->
Socket
);
skt
=
SOCKET
(
handle
);
down
(
&
skt
->
skt_sem
);
do
{
if
(
!
(
skt
->
state
&
SOCKET_PRESENT
))
{
ret
=
CS_NO_CARD
;
break
;
}
if
(
skt
->
state
&
SOCKET_SUSPEND
)
{
ret
=
CS_IN_USE
;
break
;
}
if
(
skt
->
state
&
SOCKET_CARDBUS
)
{
ret
=
CS_UNSUPPORTED_FUNCTION
;
break
;
}
ret
=
send_event
(
s
,
CS_EVENT_RESET_REQUEST
,
CS_EVENT_PRI_LOW
);
if
(
ret
!=
0
)
{
s
->
state
&=
~
SOCKET_RESET_PENDING
;
handle
->
event_callback_args
.
info
=
(
void
*
)(
u_long
)
ret
;
EVENT
(
handle
,
CS_EVENT_RESET_COMPLETE
,
CS_EVENT_PRI_LOW
);
}
else
{
DEBUG
(
1
,
"cs: resetting socket %d
\n
"
,
i
);
send_event
(
s
,
CS_EVENT_RESET_PHYSICAL
,
CS_EVENT_PRI_LOW
);
s
->
reset_handle
=
handle
;
reset_socket
(
s
);
}
return
CS_SUCCESS
;
ret
=
send_event
(
skt
,
CS_EVENT_RESET_REQUEST
,
CS_EVENT_PRI_LOW
);
if
(
ret
==
0
)
{
send_event
(
skt
,
CS_EVENT_RESET_PHYSICAL
,
CS_EVENT_PRI_LOW
);
if
(
socket_reset
(
skt
)
==
CS_SUCCESS
)
send_event
(
skt
,
CS_EVENT_CARD_RESET
,
CS_EVENT_PRI_LOW
);
}
handle
->
event_callback_args
.
info
=
(
void
*
)(
u_long
)
ret
;
EVENT
(
handle
,
CS_EVENT_RESET_COMPLETE
,
CS_EVENT_PRI_LOW
);
ret
=
CS_SUCCESS
;
}
while
(
0
);
up
(
&
skt
->
skt_sem
);
return
ret
;
}
/* reset_card */
/*======================================================================
...
...
@@ -2057,42 +2141,56 @@ int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
int
pcmcia_suspend_card
(
client_handle_t
handle
,
client_req_t
*
req
)
{
int
i
;
socket_info_t
*
s
;
socket_info_t
*
skt
;
int
ret
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
i
=
handle
->
Socket
;
s
=
socket_table
[
i
];
if
(
!
(
s
->
state
&
SOCKET_PRESENT
))
return
CS_NO_CARD
;
if
(
s
->
state
&
SOCKET_SUSPEND
)
return
CS_IN_USE
;
DEBUG
(
1
,
"cs: suspending socket %d
\n
"
,
i
);
send_event
(
s
,
CS_EVENT_PM_SUSPEND
,
CS_EVENT_PRI_LOW
);
suspend_socket
(
s
);
s
->
state
|=
SOCKET_SUSPEND
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
DEBUG
(
1
,
"cs: suspending socket %d
\n
"
,
handle
->
Socket
);
skt
=
SOCKET
(
handle
);
down
(
&
skt
->
skt_sem
);
do
{
if
(
!
(
skt
->
state
&
SOCKET_PRESENT
))
{
ret
=
CS_NO_CARD
;
break
;
}
if
(
skt
->
state
&
SOCKET_CARDBUS
)
{
ret
=
CS_UNSUPPORTED_FUNCTION
;
break
;
}
ret
=
socket_suspend
(
skt
);
}
while
(
0
);
up
(
&
skt
->
skt_sem
);
return
CS_SUCCESS
;
return
ret
;
}
/* suspend_card */
int
pcmcia_resume_card
(
client_handle_t
handle
,
client_req_t
*
req
)
{
int
i
;
socket_info_t
*
s
;
socket_info_t
*
skt
;
int
ret
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
i
=
handle
->
Socket
;
s
=
socket_table
[
i
];
if
(
!
(
s
->
state
&
SOCKET_PRESENT
))
return
CS_NO_CARD
;
if
(
!
(
s
->
state
&
SOCKET_SUSPEND
))
return
CS_IN_USE
;
DEBUG
(
1
,
"cs: waking up socket %d
\n
"
,
i
);
setup_socket
(
s
);
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
DEBUG
(
1
,
"cs: waking up socket %d
\n
"
,
handle
->
Socket
);
skt
=
SOCKET
(
handle
);
down
(
&
skt
->
skt_sem
);
do
{
if
(
!
(
skt
->
state
&
SOCKET_PRESENT
))
{
ret
=
CS_NO_CARD
;
break
;
}
if
(
skt
->
state
&
SOCKET_CARDBUS
)
{
ret
=
CS_UNSUPPORTED_FUNCTION
;
break
;
}
ret
=
socket_resume
(
skt
);
}
while
(
0
);
up
(
&
skt
->
skt_sem
);
return
CS_SUCCESS
;
return
ret
;
}
/* resume_card */
/*======================================================================
...
...
@@ -2103,57 +2201,58 @@ int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
int
pcmcia_eject_card
(
client_handle_t
handle
,
client_req_t
*
req
)
{
int
i
,
ret
;
socket_info_t
*
s
;
u_long
flags
;
socket_info_t
*
skt
;
int
ret
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
i
=
handle
->
Socket
;
s
=
socket_table
[
i
];
if
(
!
(
s
->
state
&
SOCKET_PRESENT
))
return
CS_NO_CARD
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
DEBUG
(
1
,
"cs: user eject request on socket %d
\n
"
,
handle
->
Socket
);
skt
=
SOCKET
(
handle
);
down
(
&
skt
->
skt_sem
);
do
{
if
(
!
(
skt
->
state
&
SOCKET_PRESENT
))
{
ret
=
CS_NO_CARD
;
break
;
}
DEBUG
(
1
,
"cs: user eject request on socket %d
\n
"
,
i
);
ret
=
send_event
(
skt
,
CS_EVENT_EJECTION_REQUEST
,
CS_EVENT_PRI_LOW
);
if
(
ret
!=
0
)
break
;
ret
=
send_event
(
s
,
CS_EVENT_EJECTION_REQUEST
,
CS_EVENT_PRI_LOW
);
if
(
ret
!=
0
)
return
ret
;
socket_shutdown
(
skt
);
ret
=
CS_SUCCESS
;
}
while
(
0
);
up
(
&
skt
->
skt_sem
);
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
do_shutdown
(
s
);
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
return
CS_SUCCESS
;
return
ret
;
}
/* eject_card */
int
pcmcia_insert_card
(
client_handle_t
handle
,
client_req_t
*
req
)
{
int
i
,
status
;
socket_info_t
*
s
;
u_long
flags
;
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
i
=
handle
->
Socket
;
s
=
socket_table
[
i
];
if
(
s
->
state
&
SOCKET_PRESENT
)
return
CS_IN_USE
;
DEBUG
(
1
,
"cs: user insert request on socket %d
\n
"
,
i
);
socket_info_t
*
skt
;
int
ret
;
spin_lock_irqsave
(
&
s
->
lock
,
flags
);
if
(
!
(
s
->
state
&
SOCKET_SETUP_PENDING
))
{
s
->
state
|=
SOCKET_SETUP_PENDING
;
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
get_socket_status
(
s
,
&
status
);
if
((
status
&
SS_DETECT
)
==
0
||
(
setup_socket
(
s
)
==
0
))
{
s
->
state
&=
~
SOCKET_SETUP_PENDING
;
return
CS_NO_CARD
;
}
}
else
spin_unlock_irqrestore
(
&
s
->
lock
,
flags
);
if
(
CHECK_HANDLE
(
handle
))
return
CS_BAD_HANDLE
;
DEBUG
(
1
,
"cs: user insert request on socket %d
\n
"
,
handle
->
Socket
);
skt
=
SOCKET
(
handle
);
down
(
&
skt
->
skt_sem
);
do
{
if
(
skt
->
state
&
SOCKET_PRESENT
)
{
ret
=
CS_IN_USE
;
break
;
}
if
(
socket_insert
(
skt
)
==
CS_NO_CARD
)
{
ret
=
CS_NO_CARD
;
break
;
}
ret
=
CS_SUCCESS
;
}
while
(
0
);
up
(
&
skt
->
skt_sem
);
return
CS_SUCCESS
;
return
ret
;
}
/* insert_card */
/*======================================================================
...
...
drivers/pcmcia/cs_internal.h
View file @
08aa4ea8
...
...
@@ -133,7 +133,6 @@ typedef struct socket_info_t {
u_short
lock_count
;
client_handle_t
clients
;
u_int
real_clients
;
client_handle_t
reset_handle
;
pccard_mem_map
cis_mem
;
u_char
*
cis_virt
;
config_t
*
config
;
...
...
@@ -155,6 +154,14 @@ typedef struct socket_info_t {
#ifdef CONFIG_PROC_FS
struct
proc_dir_entry
*
proc
;
#endif
struct
semaphore
skt_sem
;
/* protects socket h/w state */
struct
task_struct
*
thread
;
struct
completion
thread_done
;
wait_queue_head_t
thread_wait
;
spinlock_t
thread_lock
;
/* protects thread_events */
unsigned
int
thread_events
;
}
socket_info_t
;
/* Flags in config state */
...
...
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