Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci-2.6.23
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci-2.6.23
Commits
8e48aec7
Commit
8e48aec7
authored
Jun 25, 2006
by
David S. Miller
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[OPENPROM]: Rewrite driver to use in-kernel device tree.
Signed-off-by:
David S. Miller
<
davem@davemloft.net
>
parent
3d824a46
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
336 additions
and
257 deletions
+336
-257
drivers/sbus/char/openprom.c
drivers/sbus/char/openprom.c
+336
-257
No files found.
drivers/sbus/char/openprom.c
View file @
8e48aec7
...
...
@@ -29,8 +29,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define PROMLIB_INTERNAL
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
...
...
@@ -39,10 +37,10 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/openpromio.h>
...
...
@@ -51,15 +49,20 @@
#include <asm/pbm.h>
#endif
MODULE_AUTHOR
(
"Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)"
);
MODULE_DESCRIPTION
(
"OPENPROM Configuration Driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
"1.0"
);
/* Private data kept by the driver for each descriptor. */
typedef
struct
openprom_private_data
{
int
current_node
;
/* Current node for SunOS ioctls. */
int
lastnode
;
/* Last valid node used by BSD ioctls. */
struct
device_node
*
current_node
;
/* Current node for SunOS ioctls. */
struct
device_node
*
lastnode
;
/* Last valid node used by BSD ioctls. */
}
DATA
;
/* ID of the PROM node containing all of the EEPROM options. */
static
int
options_node
=
0
;
static
struct
device_node
*
options_node
;
/*
* Copy an openpromio structure into kernel space from user space.
...
...
@@ -87,9 +90,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p)
if
(
bufsize
>
OPROMMAXPARAM
)
bufsize
=
OPROMMAXPARAM
;
if
(
!
(
*
opp_p
=
k
m
alloc
(
sizeof
(
int
)
+
bufsize
+
1
,
GFP_KERNEL
)))
if
(
!
(
*
opp_p
=
k
z
alloc
(
sizeof
(
int
)
+
bufsize
+
1
,
GFP_KERNEL
)))
return
-
ENOMEM
;
memset
(
*
opp_p
,
0
,
sizeof
(
int
)
+
bufsize
+
1
);
if
(
copy_from_user
(
&
(
*
opp_p
)
->
oprom_array
,
&
info
->
oprom_array
,
bufsize
))
{
...
...
@@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
if
(
!
info
||
!
opp_p
)
return
-
EFAULT
;
if
(
!
(
*
opp_p
=
k
m
alloc
(
sizeof
(
int
)
+
OPROMMAXPARAM
+
1
,
GFP_KERNEL
)))
if
(
!
(
*
opp_p
=
k
z
alloc
(
sizeof
(
int
)
+
OPROMMAXPARAM
+
1
,
GFP_KERNEL
)))
return
-
ENOMEM
;
memset
(
*
opp_p
,
0
,
sizeof
(
int
)
+
OPROMMAXPARAM
+
1
);
(
*
opp_p
)
->
oprom_size
=
0
;
n
=
bufsize
=
0
;
...
...
@@ -140,16 +141,164 @@ static int copyout(void __user *info, struct openpromio *opp, int len)
return
0
;
}
static
int
opromgetprop
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
{
void
*
pval
;
int
len
;
pval
=
of_get_property
(
dp
,
op
->
oprom_array
,
&
len
);
if
(
!
pval
||
len
<=
0
||
len
>
bufsize
)
return
copyout
(
argp
,
op
,
sizeof
(
int
));
memcpy
(
op
->
oprom_array
,
pval
,
len
);
op
->
oprom_array
[
len
]
=
'\0'
;
op
->
oprom_size
=
len
;
return
copyout
(
argp
,
op
,
sizeof
(
int
)
+
bufsize
);
}
static
int
opromnxtprop
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
{
struct
property
*
prop
;
int
len
;
if
(
op
->
oprom_array
[
0
]
==
'\0'
)
{
prop
=
dp
->
properties
;
if
(
!
prop
)
return
copyout
(
argp
,
op
,
sizeof
(
int
));
len
=
strlen
(
prop
->
name
);
}
else
{
prop
=
of_find_property
(
dp
,
op
->
oprom_array
,
NULL
);
if
(
!
prop
||
!
prop
->
next
||
(
len
=
strlen
(
prop
->
next
->
name
))
+
1
>
bufsize
)
return
copyout
(
argp
,
op
,
sizeof
(
int
));
prop
=
prop
->
next
;
}
memcpy
(
op
->
oprom_array
,
prop
->
name
,
len
);
op
->
oprom_array
[
len
]
=
'\0'
;
op
->
oprom_size
=
++
len
;
return
copyout
(
argp
,
op
,
sizeof
(
int
)
+
bufsize
);
}
static
int
opromsetopt
(
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
{
char
*
buf
=
op
->
oprom_array
+
strlen
(
op
->
oprom_array
)
+
1
;
int
len
=
op
->
oprom_array
+
bufsize
-
buf
;
return
of_set_property
(
options_node
,
op
->
oprom_array
,
buf
,
len
);
}
static
int
opromnext
(
void
__user
*
argp
,
unsigned
int
cmd
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
,
DATA
*
data
)
{
phandle
ph
;
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
if
(
bufsize
<
sizeof
(
phandle
))
return
-
EINVAL
;
ph
=
*
((
int
*
)
op
->
oprom_array
);
if
(
ph
)
{
dp
=
of_find_node_by_phandle
(
ph
);
if
(
!
dp
)
return
-
EINVAL
;
switch
(
cmd
)
{
case
OPROMNEXT
:
dp
=
dp
->
sibling
;
break
;
case
OPROMCHILD
:
dp
=
dp
->
child
;
break
;
case
OPROMSETCUR
:
default:
break
;
};
}
else
{
/* Sibling of node zero is the root node. */
if
(
cmd
!=
OPROMNEXT
)
return
-
EINVAL
;
dp
=
of_find_node_by_path
(
"/"
);
}
ph
=
0
;
if
(
dp
)
ph
=
dp
->
node
;
data
->
current_node
=
dp
;
*
((
int
*
)
op
->
oprom_array
)
=
ph
;
op
->
oprom_size
=
sizeof
(
phandle
);
return
copyout
(
argp
,
op
,
bufsize
+
sizeof
(
int
));
}
static
int
oprompci2node
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
,
DATA
*
data
)
{
int
err
=
-
EINVAL
;
if
(
bufsize
>=
2
*
sizeof
(
int
))
{
#ifdef CONFIG_PCI
struct
pci_dev
*
pdev
;
struct
pcidev_cookie
*
pcp
;
pdev
=
pci_find_slot
(((
int
*
)
op
->
oprom_array
)[
0
],
((
int
*
)
op
->
oprom_array
)[
1
]);
pcp
=
pdev
->
sysdata
;
if
(
pcp
!=
NULL
)
{
dp
=
pcp
->
prom_node
;
data
->
current_node
=
dp
;
*
((
int
*
)
op
->
oprom_array
)
=
dp
->
node
;
op
->
oprom_size
=
sizeof
(
int
);
err
=
copyout
(
argp
,
op
,
bufsize
+
sizeof
(
int
));
}
#endif
}
return
err
;
}
static
int
oprompath2node
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
,
DATA
*
data
)
{
dp
=
of_find_node_by_path
(
op
->
oprom_array
);
data
->
current_node
=
dp
;
*
((
int
*
)
op
->
oprom_array
)
=
dp
->
node
;
op
->
oprom_size
=
sizeof
(
int
);
return
copyout
(
argp
,
op
,
bufsize
+
sizeof
(
int
));
}
static
int
opromgetbootargs
(
void
__user
*
argp
,
struct
openpromio
*
op
,
int
bufsize
)
{
char
*
buf
=
saved_command_line
;
int
len
=
strlen
(
buf
);
if
(
len
>
bufsize
)
return
-
EINVAL
;
strcpy
(
op
->
oprom_array
,
buf
);
op
->
oprom_size
=
len
;
return
copyout
(
argp
,
op
,
bufsize
+
sizeof
(
int
));
}
/*
* SunOS and Solaris /dev/openprom ioctl calls.
*/
static
int
openprom_sunos_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
,
int
node
)
unsigned
int
cmd
,
unsigned
long
arg
,
struct
device_node
*
dp
)
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
char
buffer
[
OPROMMAXPARAM
+
1
],
*
buf
;
DATA
*
data
=
file
->
private_data
;
struct
openpromio
*
opp
;
int
bufsize
,
len
,
error
=
0
;
int
bufsize
,
error
=
0
;
static
int
cnt
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
...
...
@@ -164,119 +313,35 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
switch
(
cmd
)
{
case
OPROMGETOPT
:
case
OPROMGETPROP
:
len
=
prom_getproplen
(
node
,
opp
->
oprom_array
);
if
(
len
<=
0
||
len
>
bufsize
)
{
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
));
break
;
}
len
=
prom_getproperty
(
node
,
opp
->
oprom_array
,
buffer
,
bufsize
);
memcpy
(
opp
->
oprom_array
,
buffer
,
len
);
opp
->
oprom_array
[
len
]
=
'\0'
;
opp
->
oprom_size
=
len
;
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
)
+
bufsize
);
error
=
opromgetprop
(
argp
,
dp
,
opp
,
bufsize
);
break
;
case
OPROMNXTOPT
:
case
OPROMNXTPROP
:
buf
=
prom_nextprop
(
node
,
opp
->
oprom_array
,
buffer
);
len
=
strlen
(
buf
);
if
(
len
==
0
||
len
+
1
>
bufsize
)
{
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
));
break
;
}
memcpy
(
opp
->
oprom_array
,
buf
,
len
);
opp
->
oprom_array
[
len
]
=
'\0'
;
opp
->
oprom_size
=
++
len
;
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
)
+
bufsize
);
error
=
opromnxtprop
(
argp
,
dp
,
opp
,
bufsize
);
break
;
case
OPROMSETOPT
:
case
OPROMSETOPT2
:
buf
=
opp
->
oprom_array
+
strlen
(
opp
->
oprom_array
)
+
1
;
len
=
opp
->
oprom_array
+
bufsize
-
buf
;
error
=
prom_setprop
(
options_node
,
opp
->
oprom_array
,
buf
,
len
);
if
(
error
<
0
)
error
=
-
EINVAL
;
error
=
opromsetopt
(
dp
,
opp
,
bufsize
);
break
;
case
OPROMNEXT
:
case
OPROMCHILD
:
case
OPROMSETCUR
:
if
(
bufsize
<
sizeof
(
int
))
{
error
=
-
EINVAL
;
break
;
}
node
=
*
((
int
*
)
opp
->
oprom_array
);
switch
(
cmd
)
{
case
OPROMNEXT
:
node
=
__prom_getsibling
(
node
);
break
;
case
OPROMCHILD
:
node
=
__prom_getchild
(
node
);
break
;
case
OPROMSETCUR
:
break
;
}
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
opp
->
oprom_size
=
sizeof
(
int
);
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
error
=
opromnext
(
argp
,
cmd
,
dp
,
opp
,
bufsize
,
data
);
break
;
case
OPROMPCI2NODE
:
error
=
-
EINVAL
;
if
(
bufsize
>=
2
*
sizeof
(
int
))
{
#ifdef CONFIG_PCI
struct
pci_dev
*
pdev
;
struct
pcidev_cookie
*
pcp
;
pdev
=
pci_find_slot
(((
int
*
)
opp
->
oprom_array
)[
0
],
((
int
*
)
opp
->
oprom_array
)[
1
]);
pcp
=
pdev
->
sysdata
;
if
(
pcp
!=
NULL
)
{
node
=
pcp
->
prom_node
->
node
;
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
opp
->
oprom_size
=
sizeof
(
int
);
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
}
#endif
}
error
=
oprompci2node
(
argp
,
dp
,
opp
,
bufsize
,
data
);
break
;
case
OPROMPATH2NODE
:
node
=
prom_finddevice
(
opp
->
oprom_array
);
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
opp
->
oprom_size
=
sizeof
(
int
);
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
error
=
oprompath2node
(
argp
,
dp
,
opp
,
bufsize
,
data
);
break
;
case
OPROMGETBOOTARGS
:
buf
=
saved_command_line
;
len
=
strlen
(
buf
);
if
(
len
>
bufsize
)
{
error
=
-
EINVAL
;
break
;
}
strcpy
(
opp
->
oprom_array
,
buf
);
opp
->
oprom_size
=
len
;
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
error
=
opromgetbootargs
(
argp
,
opp
,
bufsize
);
break
;
case
OPROMU2P
:
...
...
@@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
return
error
;
}
/* Return nonzero if a specific node is in the PROM device tree. */
static
int
intree
(
int
root
,
int
node
)
static
struct
device_node
*
get_node
(
phandle
n
,
DATA
*
data
)
{
for
(;
root
!=
0
;
root
=
prom_getsibling
(
root
))
if
(
root
==
node
||
intree
(
prom_getchild
(
root
),
node
))
return
1
;
return
0
;
}
struct
device_node
*
dp
=
of_find_node_by_phandle
(
n
);
/* Return nonzero if a specific node is "valid". */
static
int
goodnode
(
int
n
,
DATA
*
data
)
{
if
(
n
==
data
->
lastnode
||
n
==
prom_root_node
||
n
==
options_node
)
return
1
;
if
(
n
==
0
||
n
==
-
1
||
!
intree
(
prom_root_node
,
n
))
return
0
;
data
->
lastnode
=
n
;
return
1
;
if
(
dp
)
data
->
lastnode
=
dp
;
return
dp
;
}
/* Copy in a whole string from userspace into kernelspace. */
...
...
@@ -330,7 +384,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
if
(
!
tmp
)
return
-
ENOMEM
;
if
(
copy_from_user
(
tmp
,
user
,
len
))
{
if
(
copy_from_user
(
tmp
,
user
,
len
))
{
kfree
(
tmp
);
return
-
EFAULT
;
}
...
...
@@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
/*
* NetBSD /dev/openprom ioctl calls.
*/
static
int
openprom_bsd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
int
opiocget
(
void
__user
*
argp
,
DATA
*
data
)
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
struct
opiocdesc
op
;
int
error
,
node
,
len
;
char
*
str
,
*
tmp
;
char
buffer
[
64
];
static
int
cnt
;
switch
(
cmd
)
{
case
OPIOCGET
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
if
(
!
goodnode
(
op
.
op_nodeid
,
data
))
return
-
EINVAL
;
struct
device_node
*
dp
;
char
*
str
;
void
*
pval
;
int
err
,
len
;
error
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
error
)
return
error
;
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
len
=
prom_getproplen
(
op
.
op_nodeid
,
str
);
dp
=
get_node
(
op
.
op_nodeid
,
data
);
if
(
len
>
op
.
op_buflen
)
{
kfree
(
str
);
return
-
ENOMEM
;
}
err
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
err
)
return
err
;
pval
=
of_get_property
(
dp
,
str
,
&
len
);
err
=
0
;
if
(
!
pval
||
len
>
op
.
op_buflen
)
{
err
=
-
EINVAL
;
}
else
{
op
.
op_buflen
=
len
;
if
(
copy_to_user
(
argp
,
&
op
,
sizeof
(
op
))
||
copy_to_user
(
op
.
op_buf
,
pval
,
len
))
err
=
-
EFAULT
;
}
kfree
(
str
);
if
(
len
<=
0
)
{
kfree
(
str
);
/* Verified by the above copy_from_user */
if
(
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
)))
return
-
EFAULT
;
return
0
;
}
return
err
;
}
tmp
=
kmalloc
(
len
+
1
,
GFP_KERNEL
);
if
(
!
tmp
)
{
kfree
(
str
);
return
-
ENOMEM
;
}
static
int
opiocnextprop
(
void
__user
*
argp
,
DATA
*
data
)
{
struct
opiocdesc
op
;
struct
device_node
*
dp
;
struct
property
*
prop
;
char
*
str
;
int
err
,
len
;
cnt
=
prom_getproperty
(
op
.
op_nodeid
,
str
,
tmp
,
len
);
if
(
cnt
<=
0
)
{
error
=
-
EINVAL
;
}
else
{
tmp
[
len
]
=
'\0'
;
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
if
(
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
))
!=
0
||
copy_to_user
(
op
.
op_buf
,
tmp
,
len
)
!=
0
)
error
=
-
EFAULT
;
}
dp
=
get_node
(
op
.
op_nodeid
,
data
);
if
(
!
dp
)
return
-
EINVAL
;
kfree
(
tmp
);
kfree
(
str
);
err
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
err
)
return
err
;
return
error
;
if
(
str
[
0
]
==
'\0'
)
{
prop
=
dp
->
properties
;
}
else
{
prop
=
of_find_property
(
dp
,
str
,
NULL
);
if
(
prop
)
prop
=
prop
->
next
;
}
kfree
(
str
);
case
OPIOCNEXTPROP
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
if
(
!
prop
)
len
=
0
;
else
len
=
prop
->
length
;
if
(
!
goodnode
(
op
.
op_nodeid
,
data
)
)
return
-
EINVAL
;
if
(
len
>
op
.
op_buflen
)
len
=
op
.
op_buflen
;
error
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
error
)
return
error
;
if
(
copy_to_user
(
argp
,
&
op
,
sizeof
(
op
)))
return
-
EFAULT
;
tmp
=
prom_nextprop
(
op
.
op_nodeid
,
str
,
buffer
);
if
(
len
&&
copy_to_user
(
op
.
op_buf
,
prop
->
value
,
len
))
return
-
EFAULT
;
if
(
tmp
)
{
len
=
strlen
(
tmp
);
if
(
len
>
op
.
op_buflen
)
len
=
op
.
op_buflen
;
else
op
.
op_buflen
=
len
;
}
else
{
len
=
op
.
op_buflen
=
0
;
}
return
0
;
}
if
(
!
access_ok
(
VERIFY_WRITE
,
argp
,
sizeof
(
op
)))
{
kfree
(
str
);
return
-
EFAULT
;
}
static
int
opiocset
(
void
__user
*
argp
,
DATA
*
data
)
{
struct
opiocdesc
op
;
struct
device_node
*
dp
;
char
*
str
,
*
tmp
;
int
err
;
if
(
!
access_ok
(
VERIFY_WRITE
,
op
.
op_buf
,
len
))
{
kfree
(
str
);
return
-
EFAULT
;
}
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
dp
=
get_node
(
op
.
op_nodeid
,
data
);
if
(
!
dp
)
return
-
EINVAL
;
error
=
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
));
if
(
!
error
)
error
=
__copy_to_user
(
op
.
op_buf
,
tmp
,
len
);
err
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
err
)
return
err
;
err
=
copyin_string
(
op
.
op_buf
,
op
.
op_buflen
,
&
tmp
);
if
(
err
)
{
kfree
(
str
);
return
err
;
}
return
error
;
err
=
of_set_property
(
dp
,
str
,
tmp
,
op
.
op_buflen
)
;
case
OPIOCSET
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
kfree
(
str
);
kfree
(
tmp
);
if
(
!
goodnode
(
op
.
op_nodeid
,
data
))
return
-
EINVAL
;
return
err
;
}
error
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
error
)
return
error
;
static
int
opiocgetnext
(
unsigned
int
cmd
,
void
__user
*
argp
)
{
struct
device_node
*
dp
;
phandle
nd
;
error
=
copyin_string
(
op
.
op_buf
,
op
.
op_buflen
,
&
tmp
);
if
(
error
)
{
kfree
(
str
);
return
error
;
}
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
len
=
prom_setprop
(
op
.
op_nodeid
,
str
,
tmp
,
op
.
op_buflen
+
1
);
if
(
copy_from_user
(
&
nd
,
argp
,
sizeof
(
phandle
)))
return
-
EFAULT
;
if
(
len
!=
op
.
op_buflen
)
if
(
nd
==
0
)
{
if
(
cmd
!=
OPIOCGETNEXT
)
return
-
EINVAL
;
dp
=
of_find_node_by_path
(
"/"
);
}
else
{
dp
=
of_find_node_by_phandle
(
nd
);
nd
=
0
;
if
(
dp
)
{
if
(
cmd
==
OPIOCGETNEXT
)
dp
=
dp
->
sibling
;
else
dp
=
dp
->
child
;
}
}
if
(
dp
)
nd
=
dp
->
node
;
if
(
copy_to_user
(
argp
,
&
nd
,
sizeof
(
phandle
)))
return
-
EFAULT
;
kfree
(
str
)
;
kfree
(
tmp
);
return
0
;
}
return
0
;
static
int
openprom_bsd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
int
err
;
case
OPIOCGETOPTNODE
:
if
(
copy_to_user
(
argp
,
&
options_node
,
sizeof
(
int
)))
return
-
EFAULT
;
return
0
;
switch
(
cmd
)
{
case
OPIOCGET
:
err
=
opiocget
(
argp
,
data
)
;
break
;
case
OPIOCGETNEXT
:
case
OPIOCGETCHILD
:
if
(
copy_from_user
(
&
node
,
argp
,
sizeof
(
int
)))
return
-
EFAULT
;
case
OPIOCNEXTPROP
:
err
=
opiocnextprop
(
argp
,
data
);
break
;
if
(
cmd
==
OPIOCGETNEXT
)
node
=
__prom_getsibling
(
node
);
else
node
=
__prom_getchild
(
node
);
case
OPIOCSET
:
err
=
opiocset
(
argp
,
data
);
break
;
case
OPIOCGETOPTNODE
:
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
if
(
__copy_to_user
(
argp
,
&
node
,
sizeof
(
int
)))
if
(
copy_to_user
(
argp
,
&
options_node
->
node
,
sizeof
(
phandle
)))
return
-
EFAULT
;
return
0
;
case
OPIOCGETNEXT
:
case
OPIOCGETCHILD
:
err
=
opiocgetnext
(
cmd
,
argp
);
break
;
default:
if
(
cnt
++
<
10
)
printk
(
KERN_INFO
"openprom_bsd_ioctl: cmd 0x%X
\n
"
,
cmd
);
return
-
EINVAL
;
}
};
return
err
;
}
...
...
@@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
unsigned
int
cmd
,
unsigned
long
arg
)
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
static
int
cnt
;
switch
(
cmd
)
{
case
OPROMGETOPT
:
...
...
@@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
return
openprom_bsd_ioctl
(
inode
,
file
,
cmd
,
arg
);
default:
if
(
cnt
++
<
10
)
printk
(
"openprom_ioctl: cmd 0x%X, arg 0x%lX
\n
"
,
cmd
,
arg
);
return
-
EINVAL
;
}
}
;
}
static
long
openprom_compat_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
...
...
@@ -594,9 +670,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
case
OPROMSETCUR
:
case
OPROMPCI2NODE
:
case
OPROMPATH2NODE
:
lock_kernel
();
rval
=
openprom_ioctl
(
file
->
f_dentry
->
d_inode
,
file
,
cmd
,
arg
);
lock_kernel
();
break
;
}
...
...
@@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file)
{
DATA
*
data
;
data
=
(
DATA
*
)
kmalloc
(
sizeof
(
DATA
),
GFP_KERNEL
);
data
=
kmalloc
(
sizeof
(
DATA
),
GFP_KERNEL
);
if
(
!
data
)
return
-
ENOMEM
;
data
->
current_node
=
prom_root_node
;
data
->
lastnode
=
prom_roo
t_node
;
file
->
private_data
=
(
void
*
)
data
;
data
->
current_node
=
of_find_node_by_path
(
"/"
)
;
data
->
lastnode
=
data
->
curren
t_node
;
file
->
private_data
=
(
void
*
)
data
;
return
0
;
}
...
...
@@ -634,24 +708,30 @@ static struct file_operations openprom_fops = {
};
static
struct
miscdevice
openprom_dev
=
{
SUN_OPENPROM_MINOR
,
"openprom"
,
&
openprom_fops
.
minor
=
SUN_OPENPROM_MINOR
,
.
name
=
"openprom"
,
.
fops
=
&
openprom_fops
,
};
static
int
__init
openprom_init
(
void
)
{
int
error
;
struct
device_node
*
dp
;
int
err
;
error
=
misc_register
(
&
openprom_dev
);
if
(
error
)
{
printk
(
KERN_ERR
"openprom: unable to get misc minor
\n
"
);
return
error
;
}
err
=
misc_register
(
&
openprom_dev
);
if
(
err
)
return
err
;
options_node
=
prom_getchild
(
prom_root_node
);
options_node
=
prom_searchsiblings
(
options_node
,
"options"
);
dp
=
of_find_node_by_path
(
"/"
);
dp
=
dp
->
child
;
while
(
dp
)
{
if
(
!
strcmp
(
dp
->
name
,
"options"
))
break
;
dp
=
dp
->
sibling
;
}
options_node
=
dp
;
if
(
options_node
==
0
||
options_node
==
-
1
)
{
printk
(
KERN_ERR
"openprom: unable to find options node
\n
"
);
if
(
!
options_node
)
{
misc_deregister
(
&
openprom_dev
);
return
-
EIO
;
}
...
...
@@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void)
module_init
(
openprom_init
);
module_exit
(
openprom_cleanup
);
MODULE_LICENSE
(
"GPL"
);
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