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
6caf5656
Commit
6caf5656
authored
May 29, 2002
by
Patrick Mochel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
USB: Move configuration parsing code from usb.c to config.c
parent
1a2f7297
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
497 additions
and
489 deletions
+497
-489
drivers/usb/core/Makefile
drivers/usb/core/Makefile
+3
-2
drivers/usb/core/config.c
drivers/usb/core/config.c
+494
-0
drivers/usb/core/usb.c
drivers/usb/core/usb.c
+0
-487
No files found.
drivers/usb/core/Makefile
View file @
6caf5656
...
...
@@ -2,9 +2,10 @@
# Makefile for USB Core files and filesystem
#
export-objs
:=
usb.o hcd.o urb.o message.o
export-objs
:=
usb.o hcd.o urb.o message.o
config.o
usbcore-objs
:=
usb.o usb-debug.o hub.o hcd.o urb.o message.o
usbcore-objs
:=
usb.o usb-debug.o hub.o hcd.o urb.o message.o
\
config.o
ifeq
($(CONFIG_USB_DEVICEFS),y)
usbcore-objs
+=
devio.o inode.o drivers.o devices.o
...
...
drivers/usb/core/config.c
0 → 100644
View file @
6caf5656
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
static
int
usb_parse_endpoint
(
struct
usb_endpoint_descriptor
*
endpoint
,
unsigned
char
*
buffer
,
int
size
)
{
struct
usb_descriptor_header
*
header
;
unsigned
char
*
begin
;
int
parsed
=
0
,
len
,
numskipped
;
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if
(
header
->
bLength
>
size
)
{
err
(
"ran out of descriptors parsing"
);
return
-
1
;
}
if
(
header
->
bDescriptorType
!=
USB_DT_ENDPOINT
)
{
warn
(
"unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X"
,
endpoint
->
bDescriptorType
,
USB_DT_ENDPOINT
);
return
parsed
;
}
if
(
header
->
bLength
==
USB_DT_ENDPOINT_AUDIO_SIZE
)
memcpy
(
endpoint
,
buffer
,
USB_DT_ENDPOINT_AUDIO_SIZE
);
else
memcpy
(
endpoint
,
buffer
,
USB_DT_ENDPOINT_SIZE
);
le16_to_cpus
(
&
endpoint
->
wMaxPacketSize
);
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
parsed
+=
header
->
bLength
;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin
=
buffer
;
numskipped
=
0
;
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
<
2
)
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
dbg
(
"skipping descriptor 0x%X"
,
header
->
bDescriptorType
);
numskipped
++
;
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
parsed
+=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific endpoint descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
!
len
)
{
endpoint
->
extra
=
NULL
;
endpoint
->
extralen
=
0
;
return
parsed
;
}
endpoint
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
endpoint
->
extra
)
{
err
(
"couldn't allocate memory for endpoint extra descriptors"
);
endpoint
->
extralen
=
0
;
return
parsed
;
}
memcpy
(
endpoint
->
extra
,
begin
,
len
);
endpoint
->
extralen
=
len
;
return
parsed
;
}
static
int
usb_parse_interface
(
struct
usb_interface
*
interface
,
unsigned
char
*
buffer
,
int
size
)
{
int
i
,
len
,
numskipped
,
retval
,
parsed
=
0
;
struct
usb_descriptor_header
*
header
;
struct
usb_interface_descriptor
*
ifp
;
unsigned
char
*
begin
;
interface
->
act_altsetting
=
0
;
interface
->
num_altsetting
=
0
;
interface
->
max_altsetting
=
USB_ALTSETTINGALLOC
;
interface
->
altsetting
=
kmalloc
(
sizeof
(
struct
usb_interface_descriptor
)
*
interface
->
max_altsetting
,
GFP_KERNEL
);
if
(
!
interface
->
altsetting
)
{
err
(
"couldn't kmalloc interface->altsetting"
);
return
-
1
;
}
while
(
size
>
0
)
{
if
(
interface
->
num_altsetting
>=
interface
->
max_altsetting
)
{
void
*
ptr
;
int
oldmas
;
oldmas
=
interface
->
max_altsetting
;
interface
->
max_altsetting
+=
USB_ALTSETTINGALLOC
;
if
(
interface
->
max_altsetting
>
USB_MAXALTSETTING
)
{
warn
(
"too many alternate settings (max %d)"
,
USB_MAXALTSETTING
);
return
-
1
;
}
ptr
=
interface
->
altsetting
;
interface
->
altsetting
=
kmalloc
(
sizeof
(
struct
usb_interface_descriptor
)
*
interface
->
max_altsetting
,
GFP_KERNEL
);
if
(
!
interface
->
altsetting
)
{
err
(
"couldn't kmalloc interface->altsetting"
);
interface
->
altsetting
=
ptr
;
return
-
1
;
}
memcpy
(
interface
->
altsetting
,
ptr
,
sizeof
(
struct
usb_interface_descriptor
)
*
oldmas
);
kfree
(
ptr
);
}
ifp
=
interface
->
altsetting
+
interface
->
num_altsetting
;
ifp
->
endpoint
=
NULL
;
ifp
->
extra
=
NULL
;
ifp
->
extralen
=
0
;
interface
->
num_altsetting
++
;
memcpy
(
ifp
,
buffer
,
USB_DT_INTERFACE_SIZE
);
/* Skip over the interface */
buffer
+=
ifp
->
bLength
;
parsed
+=
ifp
->
bLength
;
size
-=
ifp
->
bLength
;
begin
=
buffer
;
numskipped
=
0
;
/* Skip over any interface, class or vendor descriptors */
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
<
2
)
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
numskipped
++
;
buffer
+=
header
->
bLength
;
parsed
+=
header
->
bLength
;
size
-=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific interface descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
len
)
{
ifp
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
ifp
->
extra
)
{
err
(
"couldn't allocate memory for interface extra descriptors"
);
ifp
->
extralen
=
0
;
return
-
1
;
}
memcpy
(
ifp
->
extra
,
begin
,
len
);
ifp
->
extralen
=
len
;
}
/* Did we hit an unexpected descriptor? */
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
((
size
>=
sizeof
(
struct
usb_descriptor_header
))
&&
((
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
)))
return
parsed
;
if
(
ifp
->
bNumEndpoints
>
USB_MAXENDPOINTS
)
{
warn
(
"too many endpoints"
);
return
-
1
;
}
ifp
->
endpoint
=
(
struct
usb_endpoint_descriptor
*
)
kmalloc
(
ifp
->
bNumEndpoints
*
sizeof
(
struct
usb_endpoint_descriptor
),
GFP_KERNEL
);
if
(
!
ifp
->
endpoint
)
{
err
(
"out of memory"
);
return
-
1
;
}
memset
(
ifp
->
endpoint
,
0
,
ifp
->
bNumEndpoints
*
sizeof
(
struct
usb_endpoint_descriptor
));
for
(
i
=
0
;
i
<
ifp
->
bNumEndpoints
;
i
++
)
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
>
size
)
{
err
(
"ran out of descriptors parsing"
);
return
-
1
;
}
retval
=
usb_parse_endpoint
(
ifp
->
endpoint
+
i
,
buffer
,
size
);
if
(
retval
<
0
)
return
retval
;
buffer
+=
retval
;
parsed
+=
retval
;
size
-=
retval
;
}
/* We check to see if it's an alternate to this one */
ifp
=
(
struct
usb_interface_descriptor
*
)
buffer
;
if
(
size
<
USB_DT_INTERFACE_SIZE
||
ifp
->
bDescriptorType
!=
USB_DT_INTERFACE
||
!
ifp
->
bAlternateSetting
)
return
parsed
;
}
return
parsed
;
}
int
usb_parse_configuration
(
struct
usb_config_descriptor
*
config
,
char
*
buffer
)
{
int
i
,
retval
,
size
;
struct
usb_descriptor_header
*
header
;
memcpy
(
config
,
buffer
,
USB_DT_CONFIG_SIZE
);
le16_to_cpus
(
&
config
->
wTotalLength
);
size
=
config
->
wTotalLength
;
if
(
config
->
bNumInterfaces
>
USB_MAXINTERFACES
)
{
warn
(
"too many interfaces"
);
return
-
1
;
}
config
->
interface
=
(
struct
usb_interface
*
)
kmalloc
(
config
->
bNumInterfaces
*
sizeof
(
struct
usb_interface
),
GFP_KERNEL
);
dbg
(
"kmalloc IF %p, numif %i"
,
config
->
interface
,
config
->
bNumInterfaces
);
if
(
!
config
->
interface
)
{
err
(
"out of memory"
);
return
-
1
;
}
memset
(
config
->
interface
,
0
,
config
->
bNumInterfaces
*
sizeof
(
struct
usb_interface
));
buffer
+=
config
->
bLength
;
size
-=
config
->
bLength
;
config
->
extra
=
NULL
;
config
->
extralen
=
0
;
for
(
i
=
0
;
i
<
config
->
bNumInterfaces
;
i
++
)
{
int
numskipped
,
len
;
char
*
begin
;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin
=
buffer
;
numskipped
=
0
;
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
((
header
->
bLength
>
size
)
||
(
header
->
bLength
<
2
))
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
dbg
(
"skipping descriptor 0x%X"
,
header
->
bDescriptorType
);
numskipped
++
;
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific endpoint descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
len
)
{
if
(
config
->
extralen
)
{
warn
(
"extra config descriptor"
);
}
else
{
config
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
config
->
extra
)
{
err
(
"couldn't allocate memory for config extra descriptors"
);
config
->
extralen
=
0
;
return
-
1
;
}
memcpy
(
config
->
extra
,
begin
,
len
);
config
->
extralen
=
len
;
}
}
retval
=
usb_parse_interface
(
config
->
interface
+
i
,
buffer
,
size
);
if
(
retval
<
0
)
return
retval
;
buffer
+=
retval
;
size
-=
retval
;
}
return
size
;
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally on disconnect/destroy path
void
usb_destroy_configuration
(
struct
usb_device
*
dev
)
{
int
c
,
i
,
j
,
k
;
if
(
!
dev
->
config
)
return
;
if
(
dev
->
rawdescriptors
)
{
for
(
i
=
0
;
i
<
dev
->
descriptor
.
bNumConfigurations
;
i
++
)
kfree
(
dev
->
rawdescriptors
[
i
]);
kfree
(
dev
->
rawdescriptors
);
}
for
(
c
=
0
;
c
<
dev
->
descriptor
.
bNumConfigurations
;
c
++
)
{
struct
usb_config_descriptor
*
cf
=
&
dev
->
config
[
c
];
if
(
!
cf
->
interface
)
break
;
for
(
i
=
0
;
i
<
cf
->
bNumInterfaces
;
i
++
)
{
struct
usb_interface
*
ifp
=
&
cf
->
interface
[
i
];
if
(
!
ifp
->
altsetting
)
break
;
for
(
j
=
0
;
j
<
ifp
->
num_altsetting
;
j
++
)
{
struct
usb_interface_descriptor
*
as
=
&
ifp
->
altsetting
[
j
];
if
(
as
->
extra
)
{
kfree
(
as
->
extra
);
}
if
(
!
as
->
endpoint
)
break
;
for
(
k
=
0
;
k
<
as
->
bNumEndpoints
;
k
++
)
{
if
(
as
->
endpoint
[
k
].
extra
)
{
kfree
(
as
->
endpoint
[
k
].
extra
);
}
}
kfree
(
as
->
endpoint
);
}
kfree
(
ifp
->
altsetting
);
}
kfree
(
cf
->
interface
);
}
kfree
(
dev
->
config
);
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
int
usb_get_configuration
(
struct
usb_device
*
dev
)
{
int
result
;
unsigned
int
cfgno
,
length
;
unsigned
char
*
buffer
;
unsigned
char
*
bigbuffer
;
struct
usb_config_descriptor
*
desc
;
if
(
dev
->
descriptor
.
bNumConfigurations
>
USB_MAXCONFIG
)
{
warn
(
"too many configurations"
);
return
-
EINVAL
;
}
if
(
dev
->
descriptor
.
bNumConfigurations
<
1
)
{
warn
(
"not enough configurations"
);
return
-
EINVAL
;
}
dev
->
config
=
(
struct
usb_config_descriptor
*
)
kmalloc
(
dev
->
descriptor
.
bNumConfigurations
*
sizeof
(
struct
usb_config_descriptor
),
GFP_KERNEL
);
if
(
!
dev
->
config
)
{
err
(
"out of memory"
);
return
-
ENOMEM
;
}
memset
(
dev
->
config
,
0
,
dev
->
descriptor
.
bNumConfigurations
*
sizeof
(
struct
usb_config_descriptor
));
dev
->
rawdescriptors
=
(
char
**
)
kmalloc
(
sizeof
(
char
*
)
*
dev
->
descriptor
.
bNumConfigurations
,
GFP_KERNEL
);
if
(
!
dev
->
rawdescriptors
)
{
err
(
"out of memory"
);
return
-
ENOMEM
;
}
buffer
=
kmalloc
(
8
,
GFP_KERNEL
);
if
(
!
buffer
)
{
err
(
"unable to allocate memory for configuration descriptors"
);
return
-
ENOMEM
;
}
desc
=
(
struct
usb_config_descriptor
*
)
buffer
;
for
(
cfgno
=
0
;
cfgno
<
dev
->
descriptor
.
bNumConfigurations
;
cfgno
++
)
{
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
cfgno
,
buffer
,
8
);
if
(
result
<
8
)
{
if
(
result
<
0
)
err
(
"unable to get descriptor"
);
else
{
err
(
"config descriptor too short (expected %i, got %i)"
,
8
,
result
);
result
=
-
EINVAL
;
}
goto
err
;
}
/* Get the full buffer */
length
=
le16_to_cpu
(
desc
->
wTotalLength
);
bigbuffer
=
kmalloc
(
length
,
GFP_KERNEL
);
if
(
!
bigbuffer
)
{
err
(
"unable to allocate memory for configuration descriptors"
);
result
=
-
ENOMEM
;
goto
err
;
}
/* Now that we know the length, get the whole thing */
result
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
cfgno
,
bigbuffer
,
length
);
if
(
result
<
0
)
{
err
(
"couldn't get all of config descriptors"
);
kfree
(
bigbuffer
);
goto
err
;
}
if
(
result
<
length
)
{
err
(
"config descriptor too short (expected %i, got %i)"
,
length
,
result
);
result
=
-
EINVAL
;
kfree
(
bigbuffer
);
goto
err
;
}
dev
->
rawdescriptors
[
cfgno
]
=
bigbuffer
;
result
=
usb_parse_configuration
(
&
dev
->
config
[
cfgno
],
bigbuffer
);
if
(
result
>
0
)
dbg
(
"descriptor data left"
);
else
if
(
result
<
0
)
{
result
=
-
EINVAL
;
goto
err
;
}
}
kfree
(
buffer
);
return
0
;
err:
kfree
(
buffer
);
dev
->
descriptor
.
bNumConfigurations
=
cfgno
;
return
result
;
}
drivers/usb/core/usb.c
View file @
6caf5656
...
...
@@ -33,7 +33,6 @@
#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <asm/byteorder.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
...
...
@@ -1035,390 +1034,6 @@ int usb_get_current_frame_number(struct usb_device *dev)
/*-------------------------------------------------------------------*/
static
int
usb_parse_endpoint
(
struct
usb_endpoint_descriptor
*
endpoint
,
unsigned
char
*
buffer
,
int
size
)
{
struct
usb_descriptor_header
*
header
;
unsigned
char
*
begin
;
int
parsed
=
0
,
len
,
numskipped
;
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if
(
header
->
bLength
>
size
)
{
err
(
"ran out of descriptors parsing"
);
return
-
1
;
}
if
(
header
->
bDescriptorType
!=
USB_DT_ENDPOINT
)
{
warn
(
"unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X"
,
endpoint
->
bDescriptorType
,
USB_DT_ENDPOINT
);
return
parsed
;
}
if
(
header
->
bLength
==
USB_DT_ENDPOINT_AUDIO_SIZE
)
memcpy
(
endpoint
,
buffer
,
USB_DT_ENDPOINT_AUDIO_SIZE
);
else
memcpy
(
endpoint
,
buffer
,
USB_DT_ENDPOINT_SIZE
);
le16_to_cpus
(
&
endpoint
->
wMaxPacketSize
);
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
parsed
+=
header
->
bLength
;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin
=
buffer
;
numskipped
=
0
;
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
<
2
)
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
dbg
(
"skipping descriptor 0x%X"
,
header
->
bDescriptorType
);
numskipped
++
;
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
parsed
+=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific endpoint descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
!
len
)
{
endpoint
->
extra
=
NULL
;
endpoint
->
extralen
=
0
;
return
parsed
;
}
endpoint
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
endpoint
->
extra
)
{
err
(
"couldn't allocate memory for endpoint extra descriptors"
);
endpoint
->
extralen
=
0
;
return
parsed
;
}
memcpy
(
endpoint
->
extra
,
begin
,
len
);
endpoint
->
extralen
=
len
;
return
parsed
;
}
static
int
usb_parse_interface
(
struct
usb_interface
*
interface
,
unsigned
char
*
buffer
,
int
size
)
{
int
i
,
len
,
numskipped
,
retval
,
parsed
=
0
;
struct
usb_descriptor_header
*
header
;
struct
usb_interface_descriptor
*
ifp
;
unsigned
char
*
begin
;
interface
->
act_altsetting
=
0
;
interface
->
num_altsetting
=
0
;
interface
->
max_altsetting
=
USB_ALTSETTINGALLOC
;
interface
->
altsetting
=
kmalloc
(
sizeof
(
struct
usb_interface_descriptor
)
*
interface
->
max_altsetting
,
GFP_KERNEL
);
if
(
!
interface
->
altsetting
)
{
err
(
"couldn't kmalloc interface->altsetting"
);
return
-
1
;
}
while
(
size
>
0
)
{
if
(
interface
->
num_altsetting
>=
interface
->
max_altsetting
)
{
void
*
ptr
;
int
oldmas
;
oldmas
=
interface
->
max_altsetting
;
interface
->
max_altsetting
+=
USB_ALTSETTINGALLOC
;
if
(
interface
->
max_altsetting
>
USB_MAXALTSETTING
)
{
warn
(
"too many alternate settings (max %d)"
,
USB_MAXALTSETTING
);
return
-
1
;
}
ptr
=
interface
->
altsetting
;
interface
->
altsetting
=
kmalloc
(
sizeof
(
struct
usb_interface_descriptor
)
*
interface
->
max_altsetting
,
GFP_KERNEL
);
if
(
!
interface
->
altsetting
)
{
err
(
"couldn't kmalloc interface->altsetting"
);
interface
->
altsetting
=
ptr
;
return
-
1
;
}
memcpy
(
interface
->
altsetting
,
ptr
,
sizeof
(
struct
usb_interface_descriptor
)
*
oldmas
);
kfree
(
ptr
);
}
ifp
=
interface
->
altsetting
+
interface
->
num_altsetting
;
ifp
->
endpoint
=
NULL
;
ifp
->
extra
=
NULL
;
ifp
->
extralen
=
0
;
interface
->
num_altsetting
++
;
memcpy
(
ifp
,
buffer
,
USB_DT_INTERFACE_SIZE
);
/* Skip over the interface */
buffer
+=
ifp
->
bLength
;
parsed
+=
ifp
->
bLength
;
size
-=
ifp
->
bLength
;
begin
=
buffer
;
numskipped
=
0
;
/* Skip over any interface, class or vendor descriptors */
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
<
2
)
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
numskipped
++
;
buffer
+=
header
->
bLength
;
parsed
+=
header
->
bLength
;
size
-=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific interface descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
len
)
{
ifp
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
ifp
->
extra
)
{
err
(
"couldn't allocate memory for interface extra descriptors"
);
ifp
->
extralen
=
0
;
return
-
1
;
}
memcpy
(
ifp
->
extra
,
begin
,
len
);
ifp
->
extralen
=
len
;
}
/* Did we hit an unexpected descriptor? */
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
((
size
>=
sizeof
(
struct
usb_descriptor_header
))
&&
((
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
)))
return
parsed
;
if
(
ifp
->
bNumEndpoints
>
USB_MAXENDPOINTS
)
{
warn
(
"too many endpoints"
);
return
-
1
;
}
ifp
->
endpoint
=
(
struct
usb_endpoint_descriptor
*
)
kmalloc
(
ifp
->
bNumEndpoints
*
sizeof
(
struct
usb_endpoint_descriptor
),
GFP_KERNEL
);
if
(
!
ifp
->
endpoint
)
{
err
(
"out of memory"
);
return
-
1
;
}
memset
(
ifp
->
endpoint
,
0
,
ifp
->
bNumEndpoints
*
sizeof
(
struct
usb_endpoint_descriptor
));
for
(
i
=
0
;
i
<
ifp
->
bNumEndpoints
;
i
++
)
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
(
header
->
bLength
>
size
)
{
err
(
"ran out of descriptors parsing"
);
return
-
1
;
}
retval
=
usb_parse_endpoint
(
ifp
->
endpoint
+
i
,
buffer
,
size
);
if
(
retval
<
0
)
return
retval
;
buffer
+=
retval
;
parsed
+=
retval
;
size
-=
retval
;
}
/* We check to see if it's an alternate to this one */
ifp
=
(
struct
usb_interface_descriptor
*
)
buffer
;
if
(
size
<
USB_DT_INTERFACE_SIZE
||
ifp
->
bDescriptorType
!=
USB_DT_INTERFACE
||
!
ifp
->
bAlternateSetting
)
return
parsed
;
}
return
parsed
;
}
int
usb_parse_configuration
(
struct
usb_config_descriptor
*
config
,
char
*
buffer
)
{
int
i
,
retval
,
size
;
struct
usb_descriptor_header
*
header
;
memcpy
(
config
,
buffer
,
USB_DT_CONFIG_SIZE
);
le16_to_cpus
(
&
config
->
wTotalLength
);
size
=
config
->
wTotalLength
;
if
(
config
->
bNumInterfaces
>
USB_MAXINTERFACES
)
{
warn
(
"too many interfaces"
);
return
-
1
;
}
config
->
interface
=
(
struct
usb_interface
*
)
kmalloc
(
config
->
bNumInterfaces
*
sizeof
(
struct
usb_interface
),
GFP_KERNEL
);
dbg
(
"kmalloc IF %p, numif %i"
,
config
->
interface
,
config
->
bNumInterfaces
);
if
(
!
config
->
interface
)
{
err
(
"out of memory"
);
return
-
1
;
}
memset
(
config
->
interface
,
0
,
config
->
bNumInterfaces
*
sizeof
(
struct
usb_interface
));
buffer
+=
config
->
bLength
;
size
-=
config
->
bLength
;
config
->
extra
=
NULL
;
config
->
extralen
=
0
;
for
(
i
=
0
;
i
<
config
->
bNumInterfaces
;
i
++
)
{
int
numskipped
,
len
;
char
*
begin
;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin
=
buffer
;
numskipped
=
0
;
while
(
size
>=
sizeof
(
struct
usb_descriptor_header
))
{
header
=
(
struct
usb_descriptor_header
*
)
buffer
;
if
((
header
->
bLength
>
size
)
||
(
header
->
bLength
<
2
))
{
err
(
"invalid descriptor length of %d"
,
header
->
bLength
);
return
-
1
;
}
/* If we find another "proper" descriptor then we're done */
if
((
header
->
bDescriptorType
==
USB_DT_ENDPOINT
)
||
(
header
->
bDescriptorType
==
USB_DT_INTERFACE
)
||
(
header
->
bDescriptorType
==
USB_DT_CONFIG
)
||
(
header
->
bDescriptorType
==
USB_DT_DEVICE
))
break
;
dbg
(
"skipping descriptor 0x%X"
,
header
->
bDescriptorType
);
numskipped
++
;
buffer
+=
header
->
bLength
;
size
-=
header
->
bLength
;
}
if
(
numskipped
)
dbg
(
"skipped %d class/vendor specific endpoint descriptors"
,
numskipped
);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len
=
(
int
)(
buffer
-
begin
);
if
(
len
)
{
if
(
config
->
extralen
)
{
warn
(
"extra config descriptor"
);
}
else
{
config
->
extra
=
kmalloc
(
len
,
GFP_KERNEL
);
if
(
!
config
->
extra
)
{
err
(
"couldn't allocate memory for config extra descriptors"
);
config
->
extralen
=
0
;
return
-
1
;
}
memcpy
(
config
->
extra
,
begin
,
len
);
config
->
extralen
=
len
;
}
}
retval
=
usb_parse_interface
(
config
->
interface
+
i
,
buffer
,
size
);
if
(
retval
<
0
)
return
retval
;
buffer
+=
retval
;
size
-=
retval
;
}
return
size
;
}
// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally on disconnect/destroy path
void
usb_destroy_configuration
(
struct
usb_device
*
dev
)
{
int
c
,
i
,
j
,
k
;
if
(
!
dev
->
config
)
return
;
if
(
dev
->
rawdescriptors
)
{
for
(
i
=
0
;
i
<
dev
->
descriptor
.
bNumConfigurations
;
i
++
)
kfree
(
dev
->
rawdescriptors
[
i
]);
kfree
(
dev
->
rawdescriptors
);
}
for
(
c
=
0
;
c
<
dev
->
descriptor
.
bNumConfigurations
;
c
++
)
{
struct
usb_config_descriptor
*
cf
=
&
dev
->
config
[
c
];
if
(
!
cf
->
interface
)
break
;
for
(
i
=
0
;
i
<
cf
->
bNumInterfaces
;
i
++
)
{
struct
usb_interface
*
ifp
=
&
cf
->
interface
[
i
];
if
(
!
ifp
->
altsetting
)
break
;
for
(
j
=
0
;
j
<
ifp
->
num_altsetting
;
j
++
)
{
struct
usb_interface_descriptor
*
as
=
&
ifp
->
altsetting
[
j
];
if
(
as
->
extra
)
{
kfree
(
as
->
extra
);
}
if
(
!
as
->
endpoint
)
break
;
for
(
k
=
0
;
k
<
as
->
bNumEndpoints
;
k
++
)
{
if
(
as
->
endpoint
[
k
].
extra
)
{
kfree
(
as
->
endpoint
[
k
].
extra
);
}
}
kfree
(
as
->
endpoint
);
}
kfree
(
ifp
->
altsetting
);
}
kfree
(
cf
->
interface
);
}
kfree
(
dev
->
config
);
}
/* for returning string descriptors in UTF-16LE */
static
int
ascii2utf
(
char
*
ascii
,
__u8
*
utf
,
int
utfmax
)
...
...
@@ -1619,108 +1234,6 @@ int usb_set_address(struct usb_device *dev)
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
int
usb_get_configuration
(
struct
usb_device
*
dev
)
{
int
result
;
unsigned
int
cfgno
,
length
;
unsigned
char
*
buffer
;
unsigned
char
*
bigbuffer
;
struct
usb_config_descriptor
*
desc
;
if
(
dev
->
descriptor
.
bNumConfigurations
>
USB_MAXCONFIG
)
{
warn
(
"too many configurations"
);
return
-
EINVAL
;
}
if
(
dev
->
descriptor
.
bNumConfigurations
<
1
)
{
warn
(
"not enough configurations"
);
return
-
EINVAL
;
}
dev
->
config
=
(
struct
usb_config_descriptor
*
)
kmalloc
(
dev
->
descriptor
.
bNumConfigurations
*
sizeof
(
struct
usb_config_descriptor
),
GFP_KERNEL
);
if
(
!
dev
->
config
)
{
err
(
"out of memory"
);
return
-
ENOMEM
;
}
memset
(
dev
->
config
,
0
,
dev
->
descriptor
.
bNumConfigurations
*
sizeof
(
struct
usb_config_descriptor
));
dev
->
rawdescriptors
=
(
char
**
)
kmalloc
(
sizeof
(
char
*
)
*
dev
->
descriptor
.
bNumConfigurations
,
GFP_KERNEL
);
if
(
!
dev
->
rawdescriptors
)
{
err
(
"out of memory"
);
return
-
ENOMEM
;
}
buffer
=
kmalloc
(
8
,
GFP_KERNEL
);
if
(
!
buffer
)
{
err
(
"unable to allocate memory for configuration descriptors"
);
return
-
ENOMEM
;
}
desc
=
(
struct
usb_config_descriptor
*
)
buffer
;
for
(
cfgno
=
0
;
cfgno
<
dev
->
descriptor
.
bNumConfigurations
;
cfgno
++
)
{
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
cfgno
,
buffer
,
8
);
if
(
result
<
8
)
{
if
(
result
<
0
)
err
(
"unable to get descriptor"
);
else
{
err
(
"config descriptor too short (expected %i, got %i)"
,
8
,
result
);
result
=
-
EINVAL
;
}
goto
err
;
}
/* Get the full buffer */
length
=
le16_to_cpu
(
desc
->
wTotalLength
);
bigbuffer
=
kmalloc
(
length
,
GFP_KERNEL
);
if
(
!
bigbuffer
)
{
err
(
"unable to allocate memory for configuration descriptors"
);
result
=
-
ENOMEM
;
goto
err
;
}
/* Now that we know the length, get the whole thing */
result
=
usb_get_descriptor
(
dev
,
USB_DT_CONFIG
,
cfgno
,
bigbuffer
,
length
);
if
(
result
<
0
)
{
err
(
"couldn't get all of config descriptors"
);
kfree
(
bigbuffer
);
goto
err
;
}
if
(
result
<
length
)
{
err
(
"config descriptor too short (expected %i, got %i)"
,
length
,
result
);
result
=
-
EINVAL
;
kfree
(
bigbuffer
);
goto
err
;
}
dev
->
rawdescriptors
[
cfgno
]
=
bigbuffer
;
result
=
usb_parse_configuration
(
&
dev
->
config
[
cfgno
],
bigbuffer
);
if
(
result
>
0
)
dbg
(
"descriptor data left"
);
else
if
(
result
<
0
)
{
result
=
-
EINVAL
;
goto
err
;
}
}
kfree
(
buffer
);
return
0
;
err:
kfree
(
buffer
);
dev
->
descriptor
.
bNumConfigurations
=
cfgno
;
return
result
;
}
/*
* By the time we get here, the device has gotten a new device ID
* and is in the default state. We need to identify the thing and
...
...
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