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
01a99f33
Commit
01a99f33
authored
Mar 26, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://bk.arm.linux.org.uk/linux-2.5-pcmcia
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
fff263fe
0f5c57f5
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
259 additions
and
251 deletions
+259
-251
drivers/pcmcia/ds.c
drivers/pcmcia/ds.c
+249
-176
include/pcmcia/driver_ops.h
include/pcmcia/driver_ops.h
+2
-73
include/pcmcia/ds.h
include/pcmcia/ds.h
+8
-2
No files found.
drivers/pcmcia/ds.c
View file @
01a99f33
...
...
@@ -48,6 +48,7 @@
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/pci.h>
#include <linux/list.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
...
...
@@ -55,6 +56,7 @@
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <pcmcia/ss.h>
/*====================================================================*/
...
...
@@ -97,15 +99,18 @@ typedef struct user_info_t {
}
user_info_t
;
/* Socket state information */
typedef
struct
socket_info_t
{
client_handle_t
handle
;
int
state
;
user_info_t
*
user
;
int
req_pending
,
req_result
;
wait_queue_head_t
queue
,
request
;
struct
timer_list
removal
;
socket_bind_t
*
bind
;
}
socket_info_t
;
struct
pcmcia_bus_socket
{
client_handle_t
handle
;
int
state
;
user_info_t
*
user
;
int
req_pending
,
req_result
;
wait_queue_head_t
queue
,
request
;
struct
timer_list
removal
;
socket_bind_t
*
bind
;
struct
device
*
socket_dev
;
struct
list_head
socket_list
;
unsigned
int
socket_no
;
/* deprecated */
};
#define SOCKET_PRESENT 0x01
#define SOCKET_BUSY 0x02
...
...
@@ -116,13 +121,13 @@ typedef struct socket_info_t {
/* Device driver ID passed to Card Services */
static
dev_info_t
dev_info
=
"Driver Services"
;
static
int
sockets
=
0
,
major_dev
=
-
1
;
static
socket_info_t
*
socket_table
=
NULL
;
static
int
major_dev
=
-
1
;
extern
struct
proc_dir_entry
*
proc_pccard
;
/* list of all sockets registered with the pcmcia bus driver */
static
DECLARE_RWSEM
(
bus_socket_list_rwsem
);
static
LIST_HEAD
(
bus_socket_list
);
/* We use this to distinguish in-kernel from modular drivers */
static
int
init_status
=
1
;
extern
struct
proc_dir_entry
*
proc_pccard
;
/*====================================================================*/
...
...
@@ -135,6 +140,7 @@ static void cs_error(client_handle_t handle, int func, int ret)
/*======================================================================*/
static
struct
pcmcia_driver
*
get_pcmcia_driver
(
dev_info_t
*
dev_info
);
static
struct
pcmcia_bus_socket
*
get_socket_info_by_nr
(
unsigned
int
nr
);
/**
* pcmcia_register_driver - register a PCMCIA driver with the bus core
...
...
@@ -147,7 +153,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
return
-
EINVAL
;
driver
->
use_count
=
0
;
driver
->
status
=
init_status
;
driver
->
drv
.
bus
=
&
pcmcia_bus_type
;
return
driver_register
(
&
driver
->
drv
);
...
...
@@ -160,17 +165,19 @@ EXPORT_SYMBOL(pcmcia_register_driver);
void
pcmcia_unregister_driver
(
struct
pcmcia_driver
*
driver
)
{
socket_bind_t
*
b
;
int
i
;
struct
pcmcia_bus_socket
*
bus_sock
;
if
(
driver
->
use_count
>
0
)
{
/* Blank out any left-over device instances */
driver
->
attach
=
NULL
;
driver
->
detach
=
NULL
;
for
(
i
=
0
;
i
<
sockets
;
i
++
)
for
(
b
=
socket_table
[
i
].
bind
;
b
;
b
=
b
->
next
)
down_read
(
&
bus_socket_list_rwsem
);
list_for_each_entry
(
bus_sock
,
&
bus_socket_list
,
socket_list
)
{
for
(
b
=
bus_sock
->
bind
;
b
;
b
=
b
->
next
)
if
(
b
->
driver
==
driver
)
b
->
instance
=
NULL
;
}
}
up_read
(
&
bus_socket_list_rwsem
);
}
driver_unregister
(
&
driver
->
drv
);
}
EXPORT_SYMBOL
(
pcmcia_unregister_driver
);
...
...
@@ -182,7 +189,7 @@ int register_pccard_driver(dev_info_t *dev_info,
{
struct
pcmcia_driver
*
driver
;
socket_bind_t
*
b
;
int
i
;
struct
pcmcia_bus_socket
*
bus_sock
;
DEBUG
(
0
,
"ds: register_pccard_driver('%s')
\n
"
,
(
char
*
)
dev_info
);
driver
=
get_pcmcia_driver
(
dev_info
);
...
...
@@ -199,15 +206,17 @@ int register_pccard_driver(dev_info_t *dev_info,
if
(
driver
->
use_count
==
0
)
return
0
;
/* Instantiate any already-bound devices */
for
(
i
=
0
;
i
<
sockets
;
i
++
)
for
(
b
=
socket_table
[
i
].
bind
;
b
;
b
=
b
->
next
)
{
down_read
(
&
bus_socket_list_rwsem
);
list_for_each_entry
(
bus_sock
,
&
bus_socket_list
,
socket_list
)
{
for
(
b
=
bus_sock
->
bind
;
b
;
b
=
b
->
next
)
{
if
(
b
->
driver
!=
driver
)
continue
;
b
->
instance
=
driver
->
attach
();
if
(
b
->
instance
==
NULL
)
printk
(
KERN_NOTICE
"ds: unable to create instance "
"of '%s'!
\n
"
,
driver
->
drv
.
name
);
}
}
up_read
(
&
bus_socket_list_rwsem
);
return
0
;
}
/* register_pccard_driver */
...
...
@@ -238,8 +247,7 @@ static int proc_read_drivers_callback(struct device_driver *driver, void *d)
struct
pcmcia_driver
*
p_dev
=
container_of
(
driver
,
struct
pcmcia_driver
,
drv
);
*
p
+=
sprintf
(
*
p
,
"%-24.24s %d %d
\n
"
,
driver
->
name
,
p_dev
->
status
,
p_dev
->
use_count
);
*
p
+=
sprintf
(
*
p
,
"%-24.24s 1 %d
\n
"
,
driver
->
name
,
p_dev
->
use_count
);
d
=
(
void
*
)
p
;
return
0
;
...
...
@@ -282,7 +290,7 @@ static void queue_event(user_info_t *user, event_t event)
user
->
event
[
user
->
event_head
]
=
event
;
}
static
void
handle_event
(
s
ocket_info_
t
*
s
,
event_t
event
)
static
void
handle_event
(
s
truct
pcmcia_bus_socke
t
*
s
,
event_t
event
)
{
user_info_t
*
user
;
for
(
user
=
s
->
user
;
user
;
user
=
user
->
next
)
...
...
@@ -290,7 +298,7 @@ static void handle_event(socket_info_t *s, event_t event)
wake_up_interruptible
(
&
s
->
queue
);
}
static
int
handle_request
(
s
ocket_info_
t
*
s
,
event_t
event
)
static
int
handle_request
(
s
truct
pcmcia_bus_socke
t
*
s
,
event_t
event
)
{
if
(
s
->
req_pending
!=
0
)
return
CS_IN_USE
;
...
...
@@ -309,7 +317,7 @@ static int handle_request(socket_info_t *s, event_t event)
static
void
handle_removal
(
u_long
sn
)
{
s
ocket_info_t
*
s
=
&
socket_table
[
sn
]
;
s
truct
pcmcia_bus_socket
*
s
=
get_socket_info_by_nr
(
sn
)
;
handle_event
(
s
,
CS_EVENT_CARD_REMOVAL
);
s
->
state
&=
~
SOCKET_REMOVAL_PENDING
;
}
...
...
@@ -323,13 +331,11 @@ static void handle_removal(u_long sn)
static
int
ds_event
(
event_t
event
,
int
priority
,
event_callback_args_t
*
args
)
{
socket_info_t
*
s
;
int
i
;
struct
pcmcia_bus_socket
*
s
;
DEBUG
(
1
,
"ds: ds_event(0x%06x, %d, 0x%p)
\n
"
,
event
,
priority
,
args
->
client_handle
);
s
=
args
->
client_data
;
i
=
s
-
socket_table
;
switch
(
event
)
{
...
...
@@ -366,21 +372,21 @@ static int ds_event(event_t event, int priority,
======================================================================*/
static
int
bind_mtd
(
int
i
,
mtd_info_t
*
mtd_info
)
static
int
bind_mtd
(
struct
pcmcia_bus_socket
*
bus_sock
,
mtd_info_t
*
mtd_info
)
{
mtd_bind_t
bind_req
;
int
ret
;
bind_req
.
dev_info
=
&
mtd_info
->
dev_info
;
bind_req
.
Attributes
=
mtd_info
->
Attributes
;
bind_req
.
Socket
=
i
;
bind_req
.
Socket
=
bus_sock
->
socket_no
;
bind_req
.
CardOffset
=
mtd_info
->
CardOffset
;
ret
=
pcmcia_bind_mtd
(
&
bind_req
);
if
(
ret
!=
CS_SUCCESS
)
{
cs_error
(
NULL
,
BindMTD
,
ret
);
printk
(
KERN_NOTICE
"ds: unable to bind MTD '%s' to socket %d"
" offset 0x%x
\n
"
,
(
char
*
)
bind_req
.
dev_info
,
i
,
bind_req
.
CardOffset
);
(
char
*
)
bind_req
.
dev_info
,
bus_sock
->
socket_no
,
bind_req
.
CardOffset
);
return
-
ENODEV
;
}
return
0
;
...
...
@@ -395,14 +401,16 @@ static int bind_mtd(int i, mtd_info_t *mtd_info)
======================================================================*/
static
int
bind_request
(
int
i
,
bind_info_t
*
bind_info
)
static
int
bind_request
(
struct
pcmcia_bus_socket
*
s
,
bind_info_t
*
bind_info
)
{
struct
pcmcia_driver
*
driver
;
socket_bind_t
*
b
;
bind_req_t
bind_req
;
socket_info_t
*
s
=
&
socket_table
[
i
];
int
ret
;
if
(
!
s
)
return
-
EINVAL
;
DEBUG
(
2
,
"bind_request(%d, '%s')
\n
"
,
i
,
(
char
*
)
bind_info
->
dev_info
);
driver
=
get_pcmcia_driver
(
&
bind_info
->
dev_info
);
...
...
@@ -423,14 +431,14 @@ static int bind_request(int i, bind_info_t *bind_info)
return
-
EBUSY
;
}
bind_req
.
Socket
=
i
;
bind_req
.
Socket
=
s
->
socket_no
;
bind_req
.
Function
=
bind_info
->
function
;
bind_req
.
dev_info
=
(
dev_info_t
*
)
driver
->
drv
.
name
;
ret
=
pcmcia_bind_device
(
&
bind_req
);
if
(
ret
!=
CS_SUCCESS
)
{
cs_error
(
NULL
,
BindDevice
,
ret
);
printk
(
KERN_NOTICE
"ds: unable to bind '%s' to socket %d
\n
"
,
(
char
*
)
dev_info
,
i
);
(
char
*
)
dev_info
,
s
->
socket_no
);
return
-
ENODEV
;
}
...
...
@@ -462,9 +470,8 @@ static int bind_request(int i, bind_info_t *bind_info)
/*====================================================================*/
static
int
get_device_info
(
int
i
,
bind_info_t
*
bind_info
,
int
first
)
static
int
get_device_info
(
struct
pcmcia_bus_socket
*
s
,
bind_info_t
*
bind_info
,
int
first
)
{
socket_info_t
*
s
=
&
socket_table
[
i
];
socket_bind_t
*
b
;
dev_node_t
*
node
;
...
...
@@ -532,9 +539,8 @@ static int get_device_info(int i, bind_info_t *bind_info, int first)
/*====================================================================*/
static
int
unbind_request
(
int
i
,
bind_info_t
*
bind_info
)
static
int
unbind_request
(
struct
pcmcia_bus_socket
*
s
,
bind_info_t
*
bind_info
)
{
socket_info_t
*
s
=
&
socket_table
[
i
];
socket_bind_t
**
b
,
*
c
;
DEBUG
(
2
,
"unbind_request(%d, '%s')
\n
"
,
i
,
...
...
@@ -568,13 +574,15 @@ static int unbind_request(int i, bind_info_t *bind_info)
static
int
ds_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
socket_t
i
=
minor
(
inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
user_info_t
*
user
;
DEBUG
(
0
,
"ds_open(socket %d)
\n
"
,
i
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
-
ENODEV
;
s
=
&
socket_table
[
i
];
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
-
ENODEV
;
if
((
file
->
f_flags
&
O_ACCMODE
)
!=
O_RDONLY
)
{
if
(
s
->
state
&
SOCKET_BUSY
)
return
-
EBUSY
;
...
...
@@ -600,13 +608,15 @@ static int ds_open(struct inode *inode, struct file *file)
static
int
ds_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
socket_t
i
=
minor
(
inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
user_info_t
*
user
,
**
link
;
DEBUG
(
0
,
"ds_release(socket %d)
\n
"
,
i
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
0
;
s
=
&
socket_table
[
i
];
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
0
;
user
=
file
->
private_data
;
if
(
CHECK_USER
(
user
))
goto
out
;
...
...
@@ -632,16 +642,18 @@ static ssize_t ds_read(struct file *file, char *buf,
size_t
count
,
loff_t
*
ppos
)
{
socket_t
i
=
minor
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
user_info_t
*
user
;
DEBUG
(
2
,
"ds_read(socket %d)
\n
"
,
i
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
-
ENODEV
;
if
(
count
<
4
)
return
-
EINVAL
;
s
=
&
socket_table
[
i
];
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
-
ENODEV
;
user
=
file
->
private_data
;
if
(
CHECK_USER
(
user
))
return
-
EIO
;
...
...
@@ -661,18 +673,20 @@ static ssize_t ds_write(struct file *file, const char *buf,
size_t
count
,
loff_t
*
ppos
)
{
socket_t
i
=
minor
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
user_info_t
*
user
;
DEBUG
(
2
,
"ds_write(socket %d)
\n
"
,
i
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
-
ENODEV
;
if
(
count
!=
4
)
return
-
EINVAL
;
if
((
file
->
f_flags
&
O_ACCMODE
)
==
O_RDONLY
)
return
-
EBADF
;
s
=
&
socket_table
[
i
];
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
-
ENODEV
;
user
=
file
->
private_data
;
if
(
CHECK_USER
(
user
))
return
-
EIO
;
...
...
@@ -694,14 +708,15 @@ static ssize_t ds_write(struct file *file, const char *buf,
static
u_int
ds_poll
(
struct
file
*
file
,
poll_table
*
wait
)
{
socket_t
i
=
minor
(
file
->
f_dentry
->
d_inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
user_info_t
*
user
;
DEBUG
(
2
,
"ds_poll(socket %d)
\n
"
,
i
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
POLLERR
;
s
=
&
socket_table
[
i
];
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
POLLERR
;
user
=
file
->
private_data
;
if
(
CHECK_USER
(
user
))
return
POLLERR
;
...
...
@@ -717,16 +732,16 @@ static int ds_ioctl(struct inode * inode, struct file * file,
u_int
cmd
,
u_long
arg
)
{
socket_t
i
=
minor
(
inode
->
i_rdev
);
s
ocket_info_
t
*
s
;
s
truct
pcmcia_bus_socke
t
*
s
;
u_int
size
;
int
ret
,
err
;
ds_ioctl_arg_t
buf
;
DEBUG
(
2
,
"ds_ioctl(socket %d, %#x, %#lx)
\n
"
,
i
,
cmd
,
arg
);
if
((
i
>=
sockets
)
||
(
sockets
==
0
))
return
-
ENODEV
;
s
=
&
socket_table
[
i
]
;
s
=
get_socket_info_by_nr
(
i
);
if
(
!
s
)
return
-
ENODEV
;
size
=
(
cmd
&
IOCSIZE_MASK
)
>>
IOCSIZE_SHIFT
;
if
(
size
>
sizeof
(
ds_ioctl_arg_t
))
return
-
EINVAL
;
...
...
@@ -827,20 +842,20 @@ static int ds_ioctl(struct inode * inode, struct file * file,
break
;
case
DS_BIND_REQUEST
:
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
err
=
bind_request
(
i
,
&
buf
.
bind_info
);
err
=
bind_request
(
s
,
&
buf
.
bind_info
);
break
;
case
DS_GET_DEVICE_INFO
:
err
=
get_device_info
(
i
,
&
buf
.
bind_info
,
1
);
err
=
get_device_info
(
s
,
&
buf
.
bind_info
,
1
);
break
;
case
DS_GET_NEXT_DEVICE
:
err
=
get_device_info
(
i
,
&
buf
.
bind_info
,
0
);
err
=
get_device_info
(
s
,
&
buf
.
bind_info
,
0
);
break
;
case
DS_UNBIND_REQUEST
:
err
=
unbind_request
(
i
,
&
buf
.
bind_info
);
err
=
unbind_request
(
s
,
&
buf
.
bind_info
);
break
;
case
DS_BIND_MTD
:
if
(
!
capable
(
CAP_SYS_ADMIN
))
return
-
EPERM
;
err
=
bind_mtd
(
i
,
&
buf
.
mtd_info
);
err
=
bind_mtd
(
s
,
&
buf
.
mtd_info
);
break
;
default:
err
=
-
EINVAL
;
...
...
@@ -889,141 +904,199 @@ EXPORT_SYMBOL(unregister_pccard_driver);
/*====================================================================*/
struct
bus_type
pcmcia_bus_type
=
{
.
name
=
"pcmcia"
,
};
EXPORT_SYMBOL
(
pcmcia_bus_type
);
static
int
__init
init_pcmcia_bus
(
void
)
static
int
__devinit
pcmcia_bus_add_socket
(
struct
device
*
dev
,
unsigned
int
socket_nr
)
{
bus_register
(
&
pcmcia_bus_type
);
return
0
;
}
client_reg_t
client_reg
;
bind_req_t
bind
;
struct
pcmcia_bus_socket
*
s
,
*
tmp_s
;
int
ret
;
int
i
;
static
int
__init
init_pcmcia_ds
(
void
)
{
client_reg_t
client_reg
;
servinfo_t
serv
;
bind_req_t
bind
;
socket_info_t
*
s
;
int
i
,
ret
;
s
=
kmalloc
(
sizeof
(
struct
pcmcia_bus_socket
),
GFP_KERNEL
);
if
(
!
s
)
return
-
ENOMEM
;
memset
(
s
,
0
,
sizeof
(
struct
pcmcia_bus_socket
));
DEBUG
(
0
,
"%s
\n
"
,
version
);
/*
* Ugly. But we want to wait for the socket threads to have started up.
* We really should let the drivers themselves drive some of this..
*/
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
HZ
/
4
);
/*
* Ugly. But we want to wait for the socket threads to have started up.
* We really should let the drivers themselves drive some of this..
*/
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
HZ
/
4
);
pcmcia_get_card_services_info
(
&
serv
);
if
(
serv
.
Revision
!=
CS_RELEASE_CODE
)
{
printk
(
KERN_NOTICE
"ds: Card Services release does not match!
\n
"
);
return
-
1
;
}
if
(
serv
.
Count
==
0
)
{
printk
(
KERN_NOTICE
"ds: no socket drivers loaded!
\n
"
);
return
-
1
;
}
sockets
=
serv
.
Count
;
socket_table
=
kmalloc
(
sockets
*
sizeof
(
socket_info_t
),
GFP_KERNEL
);
if
(
!
socket_table
)
return
-
1
;
for
(
i
=
0
,
s
=
socket_table
;
i
<
sockets
;
i
++
,
s
++
)
{
s
->
state
=
0
;
s
->
user
=
NULL
;
s
->
req_pending
=
0
;
init_waitqueue_head
(
&
s
->
queue
);
init_waitqueue_head
(
&
s
->
request
);
s
->
handle
=
NULL
;
init_timer
(
&
s
->
removal
);
s
->
removal
.
data
=
i
;
/* find the lowest, unused socket no. Please note that this is a
* temporary workaround until "struct pcmcia_socket" is introduced
* into cs.c which will include this number, and which will be
* accessible to ds.c directly */
i
=
0
;
next_try:
list_for_each_entry
(
tmp_s
,
&
bus_socket_list
,
socket_list
)
{
if
(
tmp_s
->
socket_no
==
i
)
{
i
++
;
goto
next_try
;
}
}
s
->
socket_no
=
i
;
/* initialize data */
s
->
socket_dev
=
dev
;
s
->
removal
.
data
=
s
->
socket_no
;
s
->
removal
.
function
=
&
handle_removal
;
s
->
bind
=
NULL
;
}
init_timer
(
&
s
->
removal
);
/* Set up hotline to Card Services */
client_reg
.
dev_info
=
bind
.
dev_info
=
&
dev_info
;
client_reg
.
Attributes
=
INFO_MASTER_CLIENT
;
client_reg
.
EventMask
=
CS_EVENT_CARD_INSERTION
|
CS_EVENT_CARD_REMOVAL
|
CS_EVENT_RESET_PHYSICAL
|
CS_EVENT_CARD_RESET
|
CS_EVENT_EJECTION_REQUEST
|
CS_EVENT_INSERTION_REQUEST
|
CS_EVENT_PM_SUSPEND
|
CS_EVENT_PM_RESUME
;
client_reg
.
event_handler
=
&
ds_event
;
client_reg
.
Version
=
0x0210
;
for
(
i
=
0
;
i
<
sockets
;
i
++
)
{
bind
.
Socket
=
i
;
/* Set up hotline to Card Services */
client_reg
.
dev_info
=
bind
.
dev_info
=
&
dev_info
;
bind
.
Socket
=
s
->
socket_no
;
bind
.
Function
=
BIND_FN_ALL
;
ret
=
pcmcia_bind_device
(
&
bind
);
if
(
ret
!=
CS_SUCCESS
)
{
cs_error
(
NULL
,
BindDevice
,
ret
);
break
;
cs_error
(
NULL
,
BindDevice
,
ret
);
kfree
(
s
);
return
-
EINVAL
;
}
client_reg
.
event_callback_args
.
client_data
=
&
socket_table
[
i
];
ret
=
pcmcia_register_client
(
&
socket_table
[
i
].
handle
,
&
client_reg
);
client_reg
.
Attributes
=
INFO_MASTER_CLIENT
;
client_reg
.
EventMask
=
CS_EVENT_CARD_INSERTION
|
CS_EVENT_CARD_REMOVAL
|
CS_EVENT_RESET_PHYSICAL
|
CS_EVENT_CARD_RESET
|
CS_EVENT_EJECTION_REQUEST
|
CS_EVENT_INSERTION_REQUEST
|
CS_EVENT_PM_SUSPEND
|
CS_EVENT_PM_RESUME
;
client_reg
.
event_handler
=
&
ds_event
;
client_reg
.
Version
=
0x0210
;
client_reg
.
event_callback_args
.
client_data
=
s
;
ret
=
pcmcia_register_client
(
&
s
->
handle
,
&
client_reg
);
if
(
ret
!=
CS_SUCCESS
)
{
cs_error
(
NULL
,
RegisterClient
,
ret
);
break
;
cs_error
(
NULL
,
RegisterClient
,
ret
);
kfree
(
s
);
return
-
EINVAL
;
}
}
/* Set up character device for user mode clients */
i
=
register_chrdev
(
0
,
"pcmcia"
,
&
ds_fops
);
if
(
i
==
-
EBUSY
)
printk
(
KERN_NOTICE
"unable to find a free device # for "
"Driver Services
\n
"
);
else
major_dev
=
i
;
#ifdef CONFIG_PROC_FS
if
(
proc_pccard
)
create_proc_read_entry
(
"drivers"
,
0
,
proc_pccard
,
proc_read_drivers
,
NULL
);
init_status
=
0
;
#endif
return
0
;
list_add
(
&
s
->
socket_list
,
&
bus_socket_list
);
return
0
;
}
static
void
__exit
exit_pcmcia_ds
(
void
)
static
int
__devinit
pcmcia_bus_add_socket_dev
(
struct
device
*
dev
)
{
struct
pcmcia_socket_class_data
*
cls_d
=
dev
->
class_data
;
unsigned
int
i
;
unsigned
int
ret
=
0
;
if
(
!
cls_d
)
return
-
ENODEV
;
down_write
(
&
bus_socket_list_rwsem
);
for
(
i
=
0
;
i
<
cls_d
->
nsock
;
i
++
)
ret
+=
pcmcia_bus_add_socket
(
dev
,
i
);
up_write
(
&
bus_socket_list_rwsem
);
return
ret
;
}
static
int
__devexit
pcmcia_bus_remove_socket_dev
(
struct
device
*
dev
)
{
int
i
;
struct
pcmcia_socket_class_data
*
cls_d
=
dev
->
class_data
;
struct
list_head
*
list_loop
;
struct
list_head
*
tmp_storage
;
if
(
!
cls_d
)
return
-
ENODEV
;
down_write
(
&
bus_socket_list_rwsem
);
list_for_each_safe
(
list_loop
,
tmp_storage
,
&
bus_socket_list
)
{
struct
pcmcia_bus_socket
*
bus_sock
=
container_of
(
list_loop
,
struct
pcmcia_bus_socket
,
socket_list
);
if
(
bus_sock
->
socket_dev
==
dev
)
{
pcmcia_deregister_client
(
bus_sock
->
handle
);
list_del
(
&
bus_sock
->
socket_list
);
kfree
(
bus_sock
);
}
}
up_write
(
&
bus_socket_list_rwsem
);
return
0
;
}
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
static
struct
device_interface
pcmcia_bus_interface
=
{
.
name
=
"pcmcia-bus"
,
.
devclass
=
&
pcmcia_socket_class
,
.
add_device
=
&
pcmcia_bus_add_socket_dev
,
.
remove_device
=
__devexit_p
(
&
pcmcia_bus_remove_socket_dev
),
.
kset
=
{
.
subsys
=
&
pcmcia_socket_class
.
subsys
,
},
.
devnum
=
0
,
};
struct
bus_type
pcmcia_bus_type
=
{
.
name
=
"pcmcia"
,
};
EXPORT_SYMBOL
(
pcmcia_bus_type
);
static
int
__init
init_pcmcia_bus
(
void
)
{
int
i
;
bus_register
(
&
pcmcia_bus_type
);
interface_register
(
&
pcmcia_bus_interface
);
/* Set up character device for user mode clients */
i
=
register_chrdev
(
0
,
"pcmcia"
,
&
ds_fops
);
if
(
i
==
-
EBUSY
)
printk
(
KERN_NOTICE
"unable to find a free device # for "
"Driver Services
\n
"
);
else
major_dev
=
i
;
#ifdef CONFIG_PROC_FS
if
(
proc_pccard
)
remove_proc_entry
(
"drivers"
,
proc_pccard
);
if
(
proc_pccard
)
create_proc_read_entry
(
"drivers"
,
0
,
proc_pccard
,
proc_read_drivers
,
NULL
);
#endif
if
(
major_dev
!=
-
1
)
unregister_chrdev
(
major_dev
,
"pcmcia"
);
for
(
i
=
0
;
i
<
sockets
;
i
++
)
pcmcia_deregister_client
(
socket_table
[
i
].
handle
);
sockets
=
0
;
kfree
(
socket_table
);
bus_unregister
(
&
pcmcia_bus_type
);
return
0
;
}
fs_initcall
(
init_pcmcia_bus
);
/* one level after subsys_initcall so that
* pcmcia_socket_class is already registered */
#ifdef MODULE
/* init_pcmcia_bus must be done early, init_pcmcia_ds late. If we load this
* as a module, we can only specify one initcall, though...
*/
static
int
__init
init_pcmcia_module
(
void
)
{
init_pcmcia_bus
();
return
init_pcmcia_ds
();
}
module_init
(
init_pcmcia_module
);
static
void
__exit
exit_pcmcia_bus
(
void
)
{
interface_unregister
(
&
pcmcia_bus_interface
);
#
else
/* !MODULE */
subsys_initcall
(
init_pcmcia_bus
);
late_initcall
(
init_pcmcia_ds
);
#
ifdef CONFIG_PROC_FS
if
(
proc_pccard
)
remove_proc_entry
(
"drivers"
,
proc_pccard
);
#endif
if
(
major_dev
!=
-
1
)
unregister_chrdev
(
major_dev
,
"pcmcia"
);
bus_unregister
(
&
pcmcia_bus_type
);
}
module_exit
(
exit_pcmcia_bus
);
module_exit
(
exit_pcmcia_ds
);
/* helpers for backwards-compatible functions */
static
struct
pcmcia_bus_socket
*
get_socket_info_by_nr
(
unsigned
int
nr
)
{
struct
pcmcia_bus_socket
*
s
;
down_read
(
&
bus_socket_list_rwsem
);
list_for_each_entry
(
s
,
&
bus_socket_list
,
socket_list
)
if
(
s
->
socket_no
==
nr
)
{
up_read
(
&
bus_socket_list_rwsem
);
return
s
;
}
up_read
(
&
bus_socket_list_rwsem
);
return
NULL
;
}
/* backwards-compatible accessing of driver --- by name! */
struct
cmp_data
{
...
...
include/pcmcia/driver_ops.h
View file @
01a99f33
/*
* driver_ops.h 1.15 2000/06/12 21:55:40
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and
* limitations under the License.
*
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in which
* case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the MPL or the GPL.
*/
#ifndef _LINUX_DRIVER_OPS_H
#define _LINUX_DRIVER_OPS_H
#ifndef DEV_NAME_LEN
#define DEV_NAME_LEN 32
#endif
#ifdef __KERNEL__
typedef
struct
dev_node_t
{
char
dev_name
[
DEV_NAME_LEN
];
u_short
major
,
minor
;
struct
dev_node_t
*
next
;
}
dev_node_t
;
typedef
struct
dev_locator_t
{
enum
{
LOC_ISA
,
LOC_PCI
}
bus
;
union
{
struct
{
u_short
io_base_1
,
io_base_2
;
u_long
mem_base
;
u_char
irq
,
dma
;
}
isa
;
struct
{
u_char
bus
;
u_char
devfn
;
}
pci
;
}
b
;
}
dev_locator_t
;
typedef
struct
driver_operations
{
char
*
name
;
dev_node_t
*
(
*
attach
)
(
dev_locator_t
*
loc
);
void
(
*
suspend
)
(
dev_node_t
*
dev
);
void
(
*
resume
)
(
dev_node_t
*
dev
);
void
(
*
detach
)
(
dev_node_t
*
dev
);
}
driver_operations
;
int
register_driver
(
struct
driver_operations
*
ops
);
void
unregister_driver
(
struct
driver_operations
*
ops
);
#endif
/* __KERNEL__ */
#endif
/* _LINUX_DRIVER_OPS_H */
/* now empty */
#warning please remove the reference to this file
include/pcmcia/ds.h
View file @
01a99f33
...
...
@@ -30,9 +30,9 @@
#ifndef _LINUX_DS_H
#define _LINUX_DS_H
#include <pcmcia/driver_ops.h>
#include <pcmcia/bulkmem.h>
#include <linux/device.h>
#include <pcmcia/cs_types.h>
typedef
struct
tuple_parse_t
{
tuple_t
tuple
;
...
...
@@ -108,6 +108,12 @@ typedef union ds_ioctl_arg_t {
#ifdef __KERNEL__
typedef
struct
dev_node_t
{
char
dev_name
[
DEV_NAME_LEN
];
u_short
major
,
minor
;
struct
dev_node_t
*
next
;
}
dev_node_t
;
typedef
struct
dev_link_t
{
dev_node_t
*
dev
;
u_int
state
,
open
;
...
...
@@ -144,7 +150,7 @@ int unregister_pccard_driver(dev_info_t *dev_info);
extern
struct
bus_type
pcmcia_bus_type
;
struct
pcmcia_driver
{
int
use_count
,
status
;
int
use_count
;
dev_link_t
*
(
*
attach
)(
void
);
void
(
*
detach
)(
dev_link_t
*
);
struct
module
*
owner
;
...
...
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