Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
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
Show 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 @@
...
@@ -29,8 +29,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
*/
#define PROMLIB_INTERNAL
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
...
@@ -39,10 +37,10 @@
...
@@ -39,10 +37,10 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <asm/oplib.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/openpromio.h>
#include <asm/openpromio.h>
...
@@ -51,15 +49,20 @@
...
@@ -51,15 +49,20 @@
#include <asm/pbm.h>
#include <asm/pbm.h>
#endif
#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. */
/* Private data kept by the driver for each descriptor. */
typedef
struct
openprom_private_data
typedef
struct
openprom_private_data
{
{
int
current_node
;
/* Current node for SunOS ioctls. */
struct
device_node
*
current_node
;
/* Current node for SunOS ioctls. */
int
lastnode
;
/* Last valid node used by BSD ioctls. */
struct
device_node
*
lastnode
;
/* Last valid node used by BSD ioctls. */
}
DATA
;
}
DATA
;
/* ID of the PROM node containing all of the EEPROM options. */
/* 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.
* 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)
...
@@ -87,9 +90,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p)
if
(
bufsize
>
OPROMMAXPARAM
)
if
(
bufsize
>
OPROMMAXPARAM
)
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
;
return
-
ENOMEM
;
memset
(
*
opp_p
,
0
,
sizeof
(
int
)
+
bufsize
+
1
);
if
(
copy_from_user
(
&
(
*
opp_p
)
->
oprom_array
,
if
(
copy_from_user
(
&
(
*
opp_p
)
->
oprom_array
,
&
info
->
oprom_array
,
bufsize
))
{
&
info
->
oprom_array
,
bufsize
))
{
...
@@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
...
@@ -107,10 +109,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
if
(
!
info
||
!
opp_p
)
if
(
!
info
||
!
opp_p
)
return
-
EFAULT
;
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
;
return
-
ENOMEM
;
memset
(
*
opp_p
,
0
,
sizeof
(
int
)
+
OPROMMAXPARAM
+
1
);
(
*
opp_p
)
->
oprom_size
=
0
;
(
*
opp_p
)
->
oprom_size
=
0
;
n
=
bufsize
=
0
;
n
=
bufsize
=
0
;
...
@@ -140,143 +141,207 @@ static int copyout(void __user *info, struct openpromio *opp, int len)
...
@@ -140,143 +141,207 @@ static int copyout(void __user *info, struct openpromio *opp, int len)
return
0
;
return
0
;
}
}
/*
static
int
opromgetprop
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
* 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
)
{
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
void
*
pval
;
char
buffer
[
OPROMMAXPARAM
+
1
],
*
buf
;
int
len
;
struct
openpromio
*
opp
;
int
bufsize
,
len
,
error
=
0
;
static
int
cnt
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
if
(
cmd
==
OPROMSETOPT
)
pval
=
of_get_property
(
dp
,
op
->
oprom_array
,
&
len
);
bufsize
=
getstrings
(
argp
,
&
opp
);
if
(
!
pval
||
len
<=
0
||
len
>
bufsize
)
else
return
copyout
(
argp
,
op
,
sizeof
(
int
));
bufsize
=
copyin
(
argp
,
&
opp
);
if
(
bufsize
<
0
)
memcpy
(
op
->
oprom_array
,
pval
,
len
);
return
bufsize
;
op
->
oprom_array
[
len
]
=
'\0'
;
op
->
oprom_size
=
len
;
switch
(
cmd
)
{
return
copyout
(
argp
,
op
,
sizeof
(
int
)
+
bufsize
);
case
OPROMGETOPT
:
}
case
OPROMGETPROP
:
len
=
prom_getproplen
(
node
,
opp
->
oprom_array
);
if
(
len
<=
0
||
len
>
bufsize
)
{
static
int
opromnxtprop
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
));
{
break
;
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
);
len
=
prom_getproperty
(
node
,
opp
->
oprom_array
,
buffer
,
bufsize
);
if
(
!
prop
||
!
prop
->
next
||
(
len
=
strlen
(
prop
->
next
->
name
))
+
1
>
bufsize
)
return
copyout
(
argp
,
op
,
sizeof
(
int
));
memcpy
(
opp
->
oprom_array
,
buffer
,
len
);
prop
=
prop
->
next
;
opp
->
oprom_array
[
len
]
=
'\0'
;
}
opp
->
oprom_size
=
len
;
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
)
+
bufsize
);
memcpy
(
op
->
oprom_array
,
prop
->
name
,
len
);
break
;
op
->
oprom_array
[
len
]
=
'\0'
;
op
->
oprom_size
=
++
len
;
case
OPROMNXTOPT
:
return
copyout
(
argp
,
op
,
sizeof
(
int
)
+
bufsize
);
case
OPROMNXTPROP
:
}
buf
=
prom_nextprop
(
node
,
opp
->
oprom_array
,
buffer
);
len
=
strlen
(
buf
);
static
int
opromsetopt
(
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
)
if
(
len
==
0
||
len
+
1
>
bufsize
)
{
{
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
));
char
*
buf
=
op
->
oprom_array
+
strlen
(
op
->
oprom_array
)
+
1
;
break
;
int
len
=
op
->
oprom_array
+
bufsize
-
buf
;
}
memcpy
(
opp
->
oprom_array
,
buf
,
len
);
return
of_set_property
(
options_node
,
op
->
oprom_array
,
buf
,
len
);
opp
->
oprom_array
[
len
]
=
'\0'
;
}
opp
->
oprom_size
=
++
len
;
error
=
copyout
(
argp
,
opp
,
sizeof
(
int
)
+
bufsize
);
static
int
opromnext
(
void
__user
*
argp
,
unsigned
int
cmd
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
,
DATA
*
data
)
break
;
{
phandle
ph
;
case
OPROMSETOPT
:
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
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
,
if
(
bufsize
<
sizeof
(
phandle
))
buf
,
len
)
;
return
-
EINVAL
;
if
(
error
<
0
)
ph
=
*
((
int
*
)
op
->
oprom_array
);
error
=
-
EINVAL
;
if
(
ph
)
{
break
;
dp
=
of_find_node_by_phandle
(
ph
);
if
(
!
dp
)
return
-
EINVAL
;
switch
(
cmd
)
{
case
OPROMNEXT
:
case
OPROMNEXT
:
dp
=
dp
->
sibling
;
break
;
case
OPROMCHILD
:
case
OPROMCHILD
:
case
OPROMSETCUR
:
dp
=
dp
->
child
;
if
(
bufsize
<
sizeof
(
int
))
{
error
=
-
EINVAL
;
break
;
break
;
}
node
=
*
((
int
*
)
opp
->
oprom_array
);
case
OPROMSETCUR
:
default:
break
;
};
}
else
{
/* Sibling of node zero is the root node. */
if
(
cmd
!=
OPROMNEXT
)
return
-
EINVAL
;
switch
(
cmd
)
{
dp
=
of_find_node_by_path
(
"/"
);
case
OPROMNEXT
:
node
=
__prom_getsibling
(
node
);
break
;
case
OPROMCHILD
:
node
=
__prom_getchild
(
node
);
break
;
case
OPROMSETCUR
:
break
;
}
}
data
->
current_node
=
node
;
ph
=
0
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
if
(
dp
)
opp
->
oprom_size
=
sizeof
(
int
)
;
ph
=
dp
->
node
;
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
data
->
current_node
=
dp
;
break
;
*
((
int
*
)
op
->
oprom_array
)
=
ph
;
op
->
oprom_size
=
sizeof
(
phandle
);
case
OPROMPCI2NODE
:
return
copyout
(
argp
,
op
,
bufsize
+
sizeof
(
int
));
error
=
-
EINVAL
;
}
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
))
{
if
(
bufsize
>=
2
*
sizeof
(
int
))
{
#ifdef CONFIG_PCI
#ifdef CONFIG_PCI
struct
pci_dev
*
pdev
;
struct
pci_dev
*
pdev
;
struct
pcidev_cookie
*
pcp
;
struct
pcidev_cookie
*
pcp
;
pdev
=
pci_find_slot
(((
int
*
)
op
p
->
oprom_array
)[
0
],
pdev
=
pci_find_slot
(((
int
*
)
o
p
->
oprom_array
)[
0
],
((
int
*
)
op
p
->
oprom_array
)[
1
]);
((
int
*
)
o
p
->
oprom_array
)[
1
]);
pcp
=
pdev
->
sysdata
;
pcp
=
pdev
->
sysdata
;
if
(
pcp
!=
NULL
)
{
if
(
pcp
!=
NULL
)
{
node
=
pcp
->
prom_node
->
node
;
dp
=
pcp
->
prom_
node
;
data
->
current_node
=
node
;
data
->
current_node
=
dp
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
*
((
int
*
)
op
->
oprom_array
)
=
dp
->
node
;
op
p
->
oprom_size
=
sizeof
(
int
);
o
p
->
oprom_size
=
sizeof
(
int
);
error
=
copyout
(
argp
,
op
p
,
bufsize
+
sizeof
(
int
));
err
=
copyout
(
argp
,
o
p
,
bufsize
+
sizeof
(
int
));
}
}
#endif
#endif
}
}
break
;
case
OPROMPATH2NODE
:
return
err
;
node
=
prom_finddevice
(
opp
->
oprom_array
);
}
data
->
current_node
=
node
;
*
((
int
*
)
opp
->
oprom_array
)
=
node
;
static
int
oprompath2node
(
void
__user
*
argp
,
struct
device_node
*
dp
,
struct
openpromio
*
op
,
int
bufsize
,
DATA
*
data
)
opp
->
oprom_size
=
sizeof
(
int
);
{
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
,
struct
device_node
*
dp
)
{
DATA
*
data
=
file
->
private_data
;
struct
openpromio
*
opp
;
int
bufsize
,
error
=
0
;
static
int
cnt
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
if
(
cmd
==
OPROMSETOPT
)
bufsize
=
getstrings
(
argp
,
&
opp
);
else
bufsize
=
copyin
(
argp
,
&
opp
);
if
(
bufsize
<
0
)
return
bufsize
;
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
switch
(
cmd
)
{
case
OPROMGETOPT
:
case
OPROMGETPROP
:
error
=
opromgetprop
(
argp
,
dp
,
opp
,
bufsize
);
break
;
break
;
case
OPROMGETBOOTARGS
:
case
OPROMNXTOPT
:
buf
=
saved_command_line
;
case
OPROMNXTPROP
:
error
=
opromnxtprop
(
argp
,
dp
,
opp
,
bufsize
);
break
;
len
=
strlen
(
buf
);
case
OPROMSETOPT
:
case
OPROMSETOPT2
:
error
=
opromsetopt
(
dp
,
opp
,
bufsize
);
break
;
if
(
len
>
bufsize
)
{
case
OPROMNEXT
:
error
=
-
EINVAL
;
case
OPROMCHILD
:
case
OPROMSETCUR
:
error
=
opromnext
(
argp
,
cmd
,
dp
,
opp
,
bufsize
,
data
);
break
;
case
OPROMPCI2NODE
:
error
=
oprompci2node
(
argp
,
dp
,
opp
,
bufsize
,
data
);
break
;
break
;
}
strcpy
(
opp
->
oprom_array
,
buf
);
case
OPROMPATH2NODE
:
opp
->
oprom_size
=
len
;
error
=
oprompath2node
(
argp
,
dp
,
opp
,
bufsize
,
data
);
break
;
error
=
copyout
(
argp
,
opp
,
bufsize
+
sizeof
(
int
));
case
OPROMGETBOOTARGS
:
error
=
opromgetbootargs
(
argp
,
opp
,
bufsize
);
break
;
break
;
case
OPROMU2P
:
case
OPROMU2P
:
...
@@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
...
@@ -297,25 +362,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
return
error
;
return
error
;
}
}
static
struct
device_node
*
get_node
(
phandle
n
,
DATA
*
data
)
/* Return nonzero if a specific node is in the PROM device tree. */
static
int
intree
(
int
root
,
int
node
)
{
{
for
(;
root
!=
0
;
root
=
prom_getsibling
(
root
))
struct
device_node
*
dp
=
of_find_node_by_phandle
(
n
);
if
(
root
==
node
||
intree
(
prom_getchild
(
root
),
node
))
return
1
;
return
0
;
}
/* Return nonzero if a specific node is "valid". */
if
(
dp
)
static
int
goodnode
(
int
n
,
DATA
*
data
)
data
->
lastnode
=
dp
;
{
if
(
n
==
data
->
lastnode
||
n
==
prom_root_node
||
n
==
options_node
)
return
dp
;
return
1
;
if
(
n
==
0
||
n
==
-
1
||
!
intree
(
prom_root_node
,
n
))
return
0
;
data
->
lastnode
=
n
;
return
1
;
}
}
/* Copy in a whole string from userspace into kernelspace. */
/* 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)
...
@@ -330,7 +384,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
if
(
!
tmp
)
if
(
!
tmp
)
return
-
ENOMEM
;
return
-
ENOMEM
;
if
(
copy_from_user
(
tmp
,
user
,
len
))
{
if
(
copy_from_user
(
tmp
,
user
,
len
))
{
kfree
(
tmp
);
kfree
(
tmp
);
return
-
EFAULT
;
return
-
EFAULT
;
}
}
...
@@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
...
@@ -345,162 +399,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
/*
/*
* NetBSD /dev/openprom ioctl calls.
* NetBSD /dev/openprom ioctl calls.
*/
*/
static
int
openprom_bsd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
static
int
opiocget
(
void
__user
*
argp
,
DATA
*
data
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
void
__user
*
argp
=
(
void
__user
*
)
arg
;
struct
opiocdesc
op
;
struct
opiocdesc
op
;
int
error
,
node
,
len
;
struct
device_node
*
dp
;
char
*
str
,
*
tmp
;
char
*
str
;
char
buffer
[
64
]
;
void
*
pval
;
static
int
cnt
;
int
err
,
len
;
switch
(
cmd
)
{
case
OPIOCGET
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
!
goodnode
(
op
.
op_nodeid
,
data
))
dp
=
get_node
(
op
.
op_nodeid
,
data
);
return
-
EINVAL
;
error
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
err
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
error
)
if
(
err
)
return
error
;
return
err
;
len
=
prom_getproplen
(
op
.
op_nodeid
,
str
);
if
(
len
>
op
.
op_buflen
)
{
kfree
(
str
);
return
-
ENOMEM
;
}
pval
=
of_get_property
(
dp
,
str
,
&
len
);
err
=
0
;
if
(
!
pval
||
len
>
op
.
op_buflen
)
{
err
=
-
EINVAL
;
}
else
{
op
.
op_buflen
=
len
;
op
.
op_buflen
=
len
;
if
(
copy_to_user
(
argp
,
&
op
,
sizeof
(
op
))
||
if
(
len
<=
0
)
{
copy_to_user
(
op
.
op_buf
,
pval
,
len
))
kfree
(
str
);
err
=
-
EFAULT
;
/* Verified by the above copy_from_user */
if
(
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
)))
return
-
EFAULT
;
return
0
;
}
}
tmp
=
kmalloc
(
len
+
1
,
GFP_KERNEL
);
if
(
!
tmp
)
{
kfree
(
str
);
kfree
(
str
);
return
-
ENOMEM
;
}
cnt
=
prom_getproperty
(
op
.
op_nodeid
,
str
,
tmp
,
len
);
if
(
cnt
<=
0
)
{
error
=
-
EINVAL
;
}
else
{
tmp
[
len
]
=
'\0'
;
if
(
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
))
!=
0
||
copy_to_user
(
op
.
op_buf
,
tmp
,
len
)
!=
0
)
error
=
-
EFAULT
;
}
kfree
(
tmp
)
;
return
err
;
kfree
(
str
);
}
return
error
;
static
int
opiocnextprop
(
void
__user
*
argp
,
DATA
*
data
)
{
struct
opiocdesc
op
;
struct
device_node
*
dp
;
struct
property
*
prop
;
char
*
str
;
int
err
,
len
;
case
OPIOCNEXTPROP
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
!
goodnode
(
op
.
op_nodeid
,
data
))
dp
=
get_node
(
op
.
op_nodeid
,
data
);
if
(
!
dp
)
return
-
EINVAL
;
return
-
EINVAL
;
erro
r
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
er
r
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
erro
r
)
if
(
er
r
)
return
erro
r
;
return
er
r
;
tmp
=
prom_nextprop
(
op
.
op_nodeid
,
str
,
buffer
);
if
(
str
[
0
]
==
'\0'
)
{
prop
=
dp
->
properties
;
}
else
{
prop
=
of_find_property
(
dp
,
str
,
NULL
);
if
(
prop
)
prop
=
prop
->
next
;
}
kfree
(
str
);
if
(
!
prop
)
len
=
0
;
else
len
=
prop
->
length
;
if
(
tmp
)
{
len
=
strlen
(
tmp
);
if
(
len
>
op
.
op_buflen
)
if
(
len
>
op
.
op_buflen
)
len
=
op
.
op_buflen
;
len
=
op
.
op_buflen
;
else
op
.
op_buflen
=
len
;
}
else
{
len
=
op
.
op_buflen
=
0
;
}
if
(
!
access_ok
(
VERIFY_WRITE
,
argp
,
sizeof
(
op
)))
{
if
(
copy_to_user
(
argp
,
&
op
,
sizeof
(
op
)))
kfree
(
str
);
return
-
EFAULT
;
return
-
EFAULT
;
}
if
(
!
access_ok
(
VERIFY_WRITE
,
op
.
op_buf
,
len
))
{
if
(
len
&&
kfree
(
str
);
copy_to_user
(
op
.
op_buf
,
prop
->
value
,
len
))
return
-
EFAULT
;
return
-
EFAULT
;
}
error
=
__copy_to_user
(
argp
,
&
op
,
sizeof
(
op
));
return
0
;
if
(
!
error
)
error
=
__copy_to_user
(
op
.
op_buf
,
tmp
,
len
);
}
kfree
(
str
);
return
error
;
static
int
opiocset
(
void
__user
*
argp
,
DATA
*
data
)
{
struct
opiocdesc
op
;
struct
device_node
*
dp
;
char
*
str
,
*
tmp
;
int
err
;
case
OPIOCSET
:
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
if
(
copy_from_user
(
&
op
,
argp
,
sizeof
(
op
)))
return
-
EFAULT
;
return
-
EFAULT
;
if
(
!
goodnode
(
op
.
op_nodeid
,
data
))
dp
=
get_node
(
op
.
op_nodeid
,
data
);
if
(
!
dp
)
return
-
EINVAL
;
return
-
EINVAL
;
erro
r
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
er
r
=
copyin_string
(
op
.
op_name
,
op
.
op_namelen
,
&
str
);
if
(
erro
r
)
if
(
er
r
)
return
erro
r
;
return
er
r
;
erro
r
=
copyin_string
(
op
.
op_buf
,
op
.
op_buflen
,
&
tmp
);
er
r
=
copyin_string
(
op
.
op_buf
,
op
.
op_buflen
,
&
tmp
);
if
(
erro
r
)
{
if
(
er
r
)
{
kfree
(
str
);
kfree
(
str
);
return
erro
r
;
return
er
r
;
}
}
len
=
prom_setprop
(
op
.
op_nodeid
,
str
,
tmp
,
op
.
op_buflen
+
1
);
err
=
of_set_property
(
dp
,
str
,
tmp
,
op
.
op_buflen
);
if
(
len
!=
op
.
op_buflen
)
return
-
EINVAL
;
kfree
(
str
);
kfree
(
str
);
kfree
(
tmp
);
kfree
(
tmp
);
return
0
;
return
err
;
}
case
OPIOCGETOPTNODE
:
static
int
opiocgetnext
(
unsigned
int
cmd
,
void
__user
*
argp
)
if
(
copy_to_user
(
argp
,
&
options_node
,
sizeof
(
int
)))
{
return
-
EFAULT
;
struct
device_node
*
dp
;
return
0
;
phandle
nd
;
case
OPIOCGETNEXT
:
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
case
OPIOCGETCHILD
:
if
(
copy_from_user
(
&
node
,
argp
,
sizeof
(
int
)))
if
(
copy_from_user
(
&
nd
,
argp
,
sizeof
(
phandle
)))
return
-
EFAULT
;
return
-
EFAULT
;
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
)
if
(
cmd
==
OPIOCGETNEXT
)
node
=
__prom_getsibling
(
node
)
;
dp
=
dp
->
sibling
;
else
else
node
=
__prom_getchild
(
node
);
dp
=
dp
->
child
;
}
}
if
(
dp
)
nd
=
dp
->
node
;
if
(
copy_to_user
(
argp
,
&
nd
,
sizeof
(
phandle
)))
return
-
EFAULT
;
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
;
switch
(
cmd
)
{
case
OPIOCGET
:
err
=
opiocget
(
argp
,
data
);
break
;
if
(
__copy_to_user
(
argp
,
&
node
,
sizeof
(
int
)))
case
OPIOCNEXTPROP
:
err
=
opiocnextprop
(
argp
,
data
);
break
;
case
OPIOCSET
:
err
=
opiocset
(
argp
,
data
);
break
;
case
OPIOCGETOPTNODE
:
BUILD_BUG_ON
(
sizeof
(
phandle
)
!=
sizeof
(
int
));
if
(
copy_to_user
(
argp
,
&
options_node
->
node
,
sizeof
(
phandle
)))
return
-
EFAULT
;
return
-
EFAULT
;
return
0
;
return
0
;
case
OPIOCGETNEXT
:
case
OPIOCGETCHILD
:
err
=
opiocgetnext
(
cmd
,
argp
);
break
;
default:
default:
if
(
cnt
++
<
10
)
printk
(
KERN_INFO
"openprom_bsd_ioctl: cmd 0x%X
\n
"
,
cmd
);
return
-
EINVAL
;
return
-
EINVAL
;
}
};
return
err
;
}
}
...
@@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
...
@@ -511,7 +590,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
DATA
*
data
=
(
DATA
*
)
file
->
private_data
;
static
int
cnt
;
switch
(
cmd
)
{
switch
(
cmd
)
{
case
OPROMGETOPT
:
case
OPROMGETOPT
:
...
@@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
...
@@ -563,10 +641,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
return
openprom_bsd_ioctl
(
inode
,
file
,
cmd
,
arg
);
return
openprom_bsd_ioctl
(
inode
,
file
,
cmd
,
arg
);
default:
default:
if
(
cnt
++
<
10
)
printk
(
"openprom_ioctl: cmd 0x%X, arg 0x%lX
\n
"
,
cmd
,
arg
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
;
}
}
static
long
openprom_compat_ioctl
(
struct
file
*
file
,
unsigned
int
cmd
,
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,
...
@@ -594,9 +670,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
case
OPROMSETCUR
:
case
OPROMSETCUR
:
case
OPROMPCI2NODE
:
case
OPROMPCI2NODE
:
case
OPROMPATH2NODE
:
case
OPROMPATH2NODE
:
lock_kernel
();
rval
=
openprom_ioctl
(
file
->
f_dentry
->
d_inode
,
file
,
cmd
,
arg
);
rval
=
openprom_ioctl
(
file
->
f_dentry
->
d_inode
,
file
,
cmd
,
arg
);
lock_kernel
();
break
;
break
;
}
}
...
@@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file)
...
@@ -607,13 +681,13 @@ static int openprom_open(struct inode * inode, struct file * file)
{
{
DATA
*
data
;
DATA
*
data
;
data
=
(
DATA
*
)
kmalloc
(
sizeof
(
DATA
),
GFP_KERNEL
);
data
=
kmalloc
(
sizeof
(
DATA
),
GFP_KERNEL
);
if
(
!
data
)
if
(
!
data
)
return
-
ENOMEM
;
return
-
ENOMEM
;
data
->
current_node
=
prom_root_node
;
data
->
current_node
=
of_find_node_by_path
(
"/"
)
;
data
->
lastnode
=
prom_roo
t_node
;
data
->
lastnode
=
data
->
curren
t_node
;
file
->
private_data
=
(
void
*
)
data
;
file
->
private_data
=
(
void
*
)
data
;
return
0
;
return
0
;
}
}
...
@@ -634,24 +708,30 @@ static struct file_operations openprom_fops = {
...
@@ -634,24 +708,30 @@ static struct file_operations openprom_fops = {
};
};
static
struct
miscdevice
openprom_dev
=
{
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
)
static
int
__init
openprom_init
(
void
)
{
{
int
error
;
struct
device_node
*
dp
;
int
err
;
error
=
misc_register
(
&
openprom_dev
);
err
=
misc_register
(
&
openprom_dev
);
if
(
error
)
{
if
(
err
)
printk
(
KERN_ERR
"openprom: unable to get misc minor
\n
"
);
return
err
;
return
error
;
}
options_node
=
prom_getchild
(
prom_root_node
);
dp
=
of_find_node_by_path
(
"/"
);
options_node
=
prom_searchsiblings
(
options_node
,
"options"
);
dp
=
dp
->
child
;
while
(
dp
)
{
if
(
!
strcmp
(
dp
->
name
,
"options"
))
break
;
dp
=
dp
->
sibling
;
}
options_node
=
dp
;
if
(
options_node
==
0
||
options_node
==
-
1
)
{
if
(
!
options_node
)
{
printk
(
KERN_ERR
"openprom: unable to find options node
\n
"
);
misc_deregister
(
&
openprom_dev
);
misc_deregister
(
&
openprom_dev
);
return
-
EIO
;
return
-
EIO
;
}
}
...
@@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void)
...
@@ -666,4 +746,3 @@ static void __exit openprom_cleanup(void)
module_init
(
openprom_init
);
module_init
(
openprom_init
);
module_exit
(
openprom_cleanup
);
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