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
7fde4915
Commit
7fde4915
authored
Jul 15, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://linuxusb.bkbits.net/linus-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
4ba438aa
12c2451c
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
364 additions
and
202 deletions
+364
-202
Documentation/usb/hiddev.txt
Documentation/usb/hiddev.txt
+14
-1
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-dbg.c
+17
-12
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hcd.c
+6
-4
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-q.c
+48
-20
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/ohci-sa1111.c
+1
-1
drivers/usb/host/ohci.h
drivers/usb/host/ohci.h
+13
-4
drivers/usb/input/hid-core.c
drivers/usb/input/hid-core.c
+102
-66
drivers/usb/input/hid-debug.h
drivers/usb/input/hid-debug.h
+0
-6
drivers/usb/input/hid-input.c
drivers/usb/input/hid-input.c
+4
-3
drivers/usb/input/hid.h
drivers/usb/input/hid.h
+9
-3
drivers/usb/input/hiddev.c
drivers/usb/input/hiddev.c
+124
-75
drivers/usb/storage/transport.c
drivers/usb/storage/transport.c
+6
-0
include/linux/hiddev.h
include/linux/hiddev.h
+20
-7
No files found.
Documentation/usb/hiddev.txt
View file @
7fde4915
...
...
@@ -18,7 +18,7 @@ normalised event interface - see Documentation/input/input.txt
The data flow for a HID event produced by a device is something like
the following :
usb.c ---> hid-core.c ----> input.c ----> [keyboard/mouse/joystick/event]
usb.c ---> hid-core.c ---->
hid-
input.c ----> [keyboard/mouse/joystick/event]
|
|
--> hiddev.c ----> POWER / MONITOR CONTROL
...
...
@@ -106,6 +106,15 @@ returns -1. You can find out beforehand how many application
collections the device has from the num_applications field from the
hiddev_devinfo structure.
HIDIOCGCOLLECTIONINFO - struct hiddev_collection_info (read/write)
This returns a superset of the information above, providing not only
application collections, but all the collections the device has. It
also returns the level the collection lives in the hierarchy.
The user passes in a hiddev_collection_info struct with the index
field set to the index that should be returned. The ioctl fills in
the other fields. If the index is larger than the last collection
index, the ioctl returns -1 and sets errno to -EINVAL.
HIDIOCGDEVINFO - struct hiddev_devinfo (read)
Gets a hiddev_devinfo structure which describes the device.
...
...
@@ -172,6 +181,10 @@ Sets the value of a usage in an output report. The user fills in
the hiddev_usage_ref structure as above, but additionally fills in
the value field.
HIDIOGCOLLECTIONINDEX - struct hiddev_usage_ref (write)
Returns the collection index associated with this usage. This
indicates where in the collection hierarchy this usage sits.
HIDIOCGFLAG - int (read)
HIDIOCSFLAG - int (write)
These operations respectively inspect and replace the mode flags
...
...
drivers/usb/host/ohci-dbg.c
View file @
7fde4915
...
...
@@ -12,13 +12,14 @@
#ifdef DEBUG
#define
pipestring(pi
pe) ({ char *temp; \
switch (
usb_pipetype (pipe)
) { \
#define
edstring(ed_ty
pe) ({ char *temp; \
switch (
ed_type
) { \
case PIPE_CONTROL: temp = "CTRL"; break; \
case PIPE_BULK: temp = "BULK"; break; \
case PIPE_INTERRUPT: temp = "INTR"; break; \
default: temp = "ISOC"; break; \
}; temp;})
#define pipestring(pipe) edstring(usb_pipetype(pipe))
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header
...
...
@@ -35,9 +36,9 @@ static void urb_print (struct urb * urb, char * str, int small)
#ifndef OHCI_VERBOSE_DEBUG
if
(
urb
->
status
!=
0
)
#endif
dbg
(
"%s
:[%4x] dev:%d,ep=%d-%c,%s,flags:%4
x,len:%d/%d,stat:%d"
,
dbg
(
"%s
%p dev:%d,ep=%d-%c,%s,flags:%
x,len:%d/%d,stat:%d"
,
str
,
u
sb_get_current_frame_number
(
urb
->
dev
),
u
rb
,
usb_pipedevice
(
pipe
),
usb_pipeendpoint
(
pipe
),
usb_pipeout
(
pipe
)
?
'O'
:
'I'
,
...
...
@@ -242,21 +243,25 @@ static void ohci_dump (struct ohci_hcd *controller, int verbose)
ohci_dump_roothub
(
controller
,
1
);
}
static
const
char
data0
[]
=
"DATA0"
;
static
const
char
data1
[]
=
"DATA1"
;
static
void
ohci_dump_td
(
char
*
label
,
struct
td
*
td
)
{
u32
tmp
=
le32_to_cpup
(
&
td
->
hwINFO
);
dbg
(
"%s td %p; urb %p index %d; hw next td %08x"
,
dbg
(
"%s td %p
%s
; urb %p index %d; hw next td %08x"
,
label
,
td
,
(
tmp
&
TD_DONE
)
?
" (DONE)"
:
""
,
td
->
urb
,
td
->
index
,
le32_to_cpup
(
&
td
->
hwNextTD
));
if
((
tmp
&
TD_ISO
)
==
0
)
{
char
*
toggle
,
*
pid
;
c
onst
c
har
*
toggle
,
*
pid
;
u32
cbp
,
be
;
switch
(
tmp
&
TD_T
)
{
case
TD_T_DATA0
:
toggle
=
"DATA0"
;
break
;
case
TD_T_DATA1
:
toggle
=
"DATA1"
;
break
;
case
TD_T_DATA0
:
toggle
=
data0
;
break
;
case
TD_T_DATA1
:
toggle
=
data1
;
break
;
case
TD_T_TOGGLE
:
toggle
=
"(CARRY)"
;
break
;
default:
toggle
=
"(?)"
;
break
;
}
...
...
@@ -297,9 +302,9 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
u32
tmp
=
ed
->
hwINFO
;
char
*
type
=
""
;
dbg
(
"%s: %s, ed %p state 0x%x type %
d
; next ed %08x"
,
dbg
(
"%s: %s, ed %p state 0x%x type %
s
; next ed %08x"
,
ohci
->
hcd
.
self
.
bus_name
,
label
,
ed
,
ed
->
state
,
ed
->
type
,
ed
,
ed
->
state
,
ed
string
(
ed
->
type
)
,
le32_to_cpup
(
&
ed
->
hwNextED
));
switch
(
tmp
&
(
ED_IN
|
ED_OUT
))
{
case
ED_OUT
:
type
=
"-OUT"
;
break
;
...
...
@@ -314,10 +319,10 @@ ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
0x000f
&
(
le32_to_cpu
(
tmp
)
>>
7
),
type
,
0x007f
&
le32_to_cpu
(
tmp
));
dbg
(
" tds: head %08x%s%s tail %08x%s"
,
dbg
(
" tds: head %08x
%s%s tail %08x%s"
,
tmp
=
le32_to_cpup
(
&
ed
->
hwHeadP
),
(
ed
->
hwHeadP
&
ED_C
)
?
data1
:
data0
,
(
ed
->
hwHeadP
&
ED_H
)
?
" HALT"
:
""
,
(
ed
->
hwHeadP
&
ED_C
)
?
" CARRY"
:
""
,
le32_to_cpup
(
&
ed
->
hwTailP
),
verbose
?
""
:
" (not listing)"
);
if
(
verbose
)
{
...
...
drivers/usb/host/ohci-hcd.c
View file @
7fde4915
...
...
@@ -208,6 +208,8 @@ static int ohci_urb_enqueue (
}
// FIXME: much of this switch should be generic, move to hcd code ...
// ... and what's not generic can't really be handled this way.
// need to consider periodicity for both types!
/* allocate and claim bandwidth if needed; ISO
* needs start frame index if it was't provided.
...
...
@@ -252,9 +254,9 @@ static int ohci_urb_enqueue (
/*
* decouple the URB from the HC queues (TDs, urb_priv); it's
* already marked
for deletion
. reporting is always done
* already marked
using urb->status
. reporting is always done
* asynchronously, and we might be dealing with an urb that's
*
almost completed anyway..
.
*
partially transferred, or an ED with other urbs being unlinked
.
*/
static
int
ohci_urb_dequeue
(
struct
usb_hcd
*
hcd
,
struct
urb
*
urb
)
{
...
...
drivers/usb/host/ohci-q.c
View file @
7fde4915
...
...
@@ -465,6 +465,25 @@ static struct ed *ed_get (
* we know it's already a power of 2
*/
ed
->
interval
=
interval
;
#ifdef DEBUG
/*
* There are two other cases we ought to change hwINFO, both during
* enumeration. There, the control request completes, unlinks, and
* the next request gets queued before the unlink completes, so it
* uses old/wrong hwINFO. How much of a problem is this? khubd is
* already retrying after such failures...
*/
}
else
if
(
type
==
PIPE_CONTROL
)
{
u32
info
=
le32_to_cpup
(
&
ed
->
hwINFO
);
if
(
!
(
info
&
0x7f
))
dbg
(
"RETRY ctrl: address != 0"
);
info
>>=
16
;
if
(
info
!=
udev
->
epmaxpacketin
[
0
])
dbg
(
"RETRY ctrl: maxpacket %d != 8"
,
udev
->
epmaxpacketin
[
0
]);
#endif
/* DEBUG */
}
done:
...
...
@@ -539,12 +558,15 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
/* aim for only one interrupt per urb. mostly applies to control
* and iso; other urbs rarely need more than one TD per urb.
* this way, only final tds (or ones with an error) cause IRQs.
*
* NOTE: could delay interrupts even for the last TD, and get fewer
* interrupts ... increasing per-urb latency by sharing interrupts.
* Drivers that queue bulk urbs may request that behavior.
*/
if
(
index
!=
(
urb_priv
->
length
-
1
))
info
|=
is_iso
?
TD_DI_SET
(
7
)
:
TD_DI_SET
(
1
);
if
(
index
!=
(
urb_priv
->
length
-
1
)
||
(
urb
->
transfer_flags
&
URB_NO_INTERRUPT
))
info
|=
TD_DI_SET
(
7
);
/* use this td as the next dummy */
td_pt
=
urb_priv
->
td
[
index
];
...
...
@@ -565,6 +587,7 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
td
->
hwINFO
=
cpu_to_le32
(
info
);
if
(
is_iso
)
{
td
->
hwCBP
=
cpu_to_le32
(
data
&
0xFFFFF000
);
td
->
hwPSW
[
0
]
=
cpu_to_le16
((
data
&
0x0FFF
)
|
0xE000
);
td
->
ed
->
intriso
.
last_iso
=
info
&
0xffff
;
}
else
{
td
->
hwCBP
=
cpu_to_le32
(
data
);
...
...
@@ -574,7 +597,6 @@ td_fill (struct ohci_hcd *ohci, unsigned int info,
else
td
->
hwBE
=
0
;
td
->
hwNextTD
=
cpu_to_le32
(
td_pt
->
td_dma
);
td
->
hwPSW
[
0
]
=
cpu_to_le16
((
data
&
0x0FFF
)
|
0xE000
);
/* HC might read the TD right after we link it ... */
wmb
();
...
...
@@ -596,17 +618,17 @@ static void td_submit_urb (struct urb *urb)
int
cnt
=
0
;
__u32
info
=
0
;
unsigned
int
toggle
=
0
;
int
is_out
=
usb_pipeout
(
urb
->
pipe
);
/* OHCI handles the DATA-toggles itself, we just use the
* USB-toggle bits for resetting
*/
if
(
usb_gettoggle
(
urb
->
dev
,
usb_pipeendpoint
(
urb
->
pipe
),
usb_pipeout
(
urb
->
pipe
)))
{
if
(
usb_gettoggle
(
urb
->
dev
,
usb_pipeendpoint
(
urb
->
pipe
),
is_out
))
{
toggle
=
TD_T_TOGGLE
;
}
else
{
toggle
=
TD_T_DATA0
;
usb_settoggle
(
urb
->
dev
,
usb_pipeendpoint
(
urb
->
pipe
),
usb_pipeout
(
urb
->
pipe
)
,
1
);
is_out
,
1
);
}
urb_priv
->
td_cnt
=
0
;
...
...
@@ -614,7 +636,7 @@ static void td_submit_urb (struct urb *urb)
if
(
data_len
)
{
data
=
pci_map_single
(
ohci
->
hcd
.
pdev
,
urb
->
transfer_buffer
,
data_len
,
usb_pipeout
(
urb
->
pipe
)
is_out
?
PCI_DMA_TODEVICE
:
PCI_DMA_FROMDEVICE
);
}
else
...
...
@@ -625,18 +647,20 @@ static void td_submit_urb (struct urb *urb)
*/
switch
(
usb_pipetype
(
urb
->
pipe
))
{
case
PIPE_BULK
:
info
=
usb_pipeout
(
urb
->
pipe
)
info
=
is_out
?
TD_CC
|
TD_DP_OUT
:
TD_CC
|
TD_DP_IN
;
/* TDs _could_ transfer up to 8K each */
while
(
data_len
>
4096
)
{
td_fill
(
ohci
,
info
|
(
cnt
?
TD_T_TOGGLE
:
toggle
),
data
,
4096
,
urb
,
cnt
);
data
+=
4096
;
data_len
-=
4096
;
cnt
++
;
}
info
=
usb_pipeout
(
urb
->
pipe
)
?
TD_CC
|
TD_DP_OUT
:
TD_CC
|
TD_R
|
TD_DP_IN
;
td_fill
(
ohci
,
info
|
(
cnt
?
TD_T_TOGGLE
:
toggle
),
/* maybe avoid ED halt on final TD short read */
if
(
!
(
urb
->
transfer_flags
&
URB_SHORT_NOT_OK
))
info
|=
TD_R
;
td_fill
(
ohci
,
info
|
(
cnt
?
TD_T_TOGGLE
:
toggle
),
data
,
data_len
,
urb
,
cnt
);
cnt
++
;
if
((
urb
->
transfer_flags
&
USB_ZERO_PACKET
)
...
...
@@ -653,8 +677,11 @@ static void td_submit_urb (struct urb *urb)
break
;
case
PIPE_INTERRUPT
:
/* current policy: only one TD per request.
* otherwise identical to bulk, except for BLF
*/
info
=
TD_CC
|
toggle
;
info
|=
usb_pipeout
(
urb
->
pipe
)
info
|=
is_out
?
TD_DP_OUT
:
TD_R
|
TD_DP_IN
;
td_fill
(
ohci
,
info
,
data
,
data_len
,
urb
,
cnt
++
);
...
...
@@ -670,14 +697,12 @@ static void td_submit_urb (struct urb *urb)
8
,
urb
,
cnt
++
);
if
(
data_len
>
0
)
{
info
=
TD_CC
|
TD_R
|
TD_T_DATA1
;
info
|=
usb_pipeout
(
urb
->
pipe
)
?
TD_DP_OUT
:
TD_DP_IN
;
info
|=
is_out
?
TD_DP_OUT
:
TD_DP_IN
;
/* NOTE: mishandles transfers >8K, some >4K */
td_fill
(
ohci
,
info
,
data
,
data_len
,
urb
,
cnt
++
);
}
info
=
usb_pipeout
(
urb
->
pipe
)
info
=
is_out
?
TD_CC
|
TD_DP_IN
|
TD_T_DATA1
:
TD_CC
|
TD_DP_OUT
|
TD_T_DATA1
;
td_fill
(
ohci
,
info
,
data
,
0
,
urb
,
cnt
++
);
...
...
@@ -806,10 +831,13 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
while
(
td_list_hc
)
{
td_list
=
dma_to_td
(
ohci
,
td_list_hc
);
td_list
->
hwINFO
|=
cpu_to_le32
(
TD_DONE
);
if
(
TD_CC_GET
(
le32_to_cpup
(
&
td_list
->
hwINFO
)))
{
urb_priv
=
(
urb_priv_t
*
)
td_list
->
urb
->
hcpriv
;
/* typically the endpoint halts on error; un-halt,
* and maybe dequeue other TDs from this urb
/* Non-iso endpoints can halt on error; un-halt,
* and dequeue any other TDs from this urb.
* No other TD could have caused the halt.
*/
if
(
td_list
->
ed
->
hwHeadP
&
ED_H
)
{
if
(
urb_priv
&&
((
td_list
->
index
+
1
)
...
...
drivers/usb/host/ohci-sa1111.c
View file @
7fde4915
...
...
@@ -175,7 +175,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
usb_bus_init
(
&
hcd
->
self
);
hcd
->
self
.
op
=
&
usb_hcd_operations
;
hcd
->
self
.
hcpriv
=
(
void
*
)
hcd
;
hcd
->
self
.
bus_name
=
"
SA-
1111"
;
hcd
->
self
.
bus_name
=
"
sa
1111"
;
hcd
->
product_desc
=
"SA-1111 OHCI"
;
INIT_LIST_HEAD
(
&
hcd
->
dev_list
);
...
...
drivers/usb/host/ohci.h
View file @
7fde4915
...
...
@@ -11,6 +11,9 @@
/*
* OHCI Endpoint Descriptor (ED) ... holds TD queue
* See OHCI spec, section 4.2
*
* This is a "Queue Head" for those transfers, which is why
* both EHCI and UHCI call similar structures a "QH".
*/
struct
ed
{
/* first fields are hardware-specified, le32 */
...
...
@@ -74,7 +77,7 @@ struct td {
/* these two bits are available for definition/use by HCDs in both
* general and iso tds ... others are available for only one type
*/
//#define TD____ 0x00020000
#define TD_DONE 0x00020000
/* retired to donelist */
#define TD_ISO 0x00010000
/* copy of ED_ISO */
/* hwINFO bits for general tds: */
...
...
@@ -349,12 +352,14 @@ struct ohci_hcd {
struct
device
*
parent_dev
;
/*
* I/O memory used to communicate with the HC (
uncached);
* I/O memory used to communicate with the HC (
dma-consistent)
*/
struct
ohci_regs
*
regs
;
/*
* main memory used to communicate with the HC (uncached)
* main memory used to communicate with the HC (dma-consistent).
* hcd adds to schedule for a live hc any time, but removals finish
* only at the start of the next frame.
*/
struct
ohci_hcca
*
hcca
;
dma_addr_t
hcca_dma
;
...
...
@@ -365,6 +370,9 @@ struct ohci_hcd {
struct
ed
*
ed_controltail
;
/* last in ctrl list */
struct
ed
*
ed_isotail
;
/* last in iso list */
/*
* memory management for queue data structures
*/
struct
pci_pool
*
td_cache
;
struct
pci_pool
*
ed_cache
;
struct
hash_list_t
td_hash
[
TD_HASH_SIZE
];
...
...
@@ -380,6 +388,7 @@ struct ohci_hcd {
unsigned
long
flags
;
/* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01
/* erratum #4 */
// there are also chip quirks/bugs in init logic
/*
* framework state
...
...
drivers/usb/input/hid-core.c
View file @
7fde4915
...
...
@@ -127,18 +127,41 @@ static int open_collection(struct hid_parser *parser, unsigned type)
usage
=
parser
->
local
.
usage
[
0
];
if
(
type
==
HID_COLLECTION_APPLICATION
&&
parser
->
device
->
maxapplication
<
HID_MAX_APPLICATIONS
)
parser
->
device
->
application
[
parser
->
device
->
maxapplication
++
]
=
usage
;
if
(
parser
->
collection_stack_ptr
==
HID_COLLECTION_STACK_SIZE
)
{
dbg
(
"collection stack overflow"
);
return
-
1
;
}
collection
=
parser
->
collection_stack
+
parser
->
collection_stack_ptr
++
;
if
(
parser
->
device
->
maxcollection
==
parser
->
device
->
collection_size
)
{
collection
=
kmalloc
(
sizeof
(
struct
hid_collection
)
*
parser
->
device
->
collection_size
*
2
,
GFP_KERNEL
);
if
(
collection
==
NULL
)
{
dbg
(
"failed to reallocate collection array"
);
return
-
1
;
}
memcpy
(
collection
,
parser
->
device
->
collection
,
sizeof
(
struct
hid_collection
)
*
parser
->
device
->
collection_size
);
memset
(
collection
+
parser
->
device
->
collection_size
,
0
,
sizeof
(
struct
hid_collection
)
*
parser
->
device
->
collection_size
);
kfree
(
parser
->
device
->
collection
);
parser
->
device
->
collection
=
collection
;
parser
->
device
->
collection_size
*=
2
;
}
parser
->
collection_stack
[
parser
->
collection_stack_ptr
++
]
=
parser
->
device
->
maxcollection
;
collection
=
parser
->
device
->
collection
+
parser
->
device
->
maxcollection
++
;
collection
->
type
=
type
;
collection
->
usage
=
usage
;
collection
->
level
=
parser
->
collection_stack_ptr
-
1
;
if
(
type
==
HID_COLLECTION_APPLICATION
)
parser
->
device
->
maxapplication
++
;
return
0
;
}
...
...
@@ -166,8 +189,8 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
{
int
n
;
for
(
n
=
parser
->
collection_stack_ptr
-
1
;
n
>=
0
;
n
--
)
if
(
parser
->
collection_stack
[
n
].
type
==
type
)
return
parser
->
collection_stack
[
n
].
usage
;
if
(
parser
->
device
->
collection
[
parser
->
collection_stack
[
n
]
].
type
==
type
)
return
parser
->
device
->
collection
[
parser
->
collection_stack
[
n
]
].
usage
;
return
0
;
/* we know nothing about this usage type */
}
...
...
@@ -181,7 +204,11 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage)
dbg
(
"usage index exceeded"
);
return
-
1
;
}
parser
->
local
.
usage
[
parser
->
local
.
usage_index
++
]
=
usage
;
parser
->
local
.
usage
[
parser
->
local
.
usage_index
]
=
usage
;
parser
->
local
.
collection_index
[
parser
->
local
.
usage_index
]
=
parser
->
collection_stack_ptr
?
parser
->
collection_stack
[
parser
->
collection_stack_ptr
-
1
]
:
0
;
parser
->
local
.
usage_index
++
;
return
0
;
}
...
...
@@ -221,8 +248,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
field
->
logical
=
hid_lookup_collection
(
parser
,
HID_COLLECTION_LOGICAL
);
field
->
application
=
hid_lookup_collection
(
parser
,
HID_COLLECTION_APPLICATION
);
for
(
i
=
0
;
i
<
usages
;
i
++
)
for
(
i
=
0
;
i
<
usages
;
i
++
)
{
field
->
usage
[
i
].
hid
=
parser
->
local
.
usage
[
i
];
field
->
usage
[
i
].
collection_index
=
parser
->
local
.
collection_index
[
i
];
}
field
->
maxusage
=
usages
;
field
->
flags
=
flags
;
...
...
@@ -460,7 +490,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
switch
(
item
->
tag
)
{
case
HID_MAIN_ITEM_TAG_BEGIN_COLLECTION
:
ret
=
open_collection
(
parser
,
data
&
3
);
ret
=
open_collection
(
parser
,
data
&
0xff
);
break
;
case
HID_MAIN_ITEM_TAG_END_COLLECTION
:
ret
=
close_collection
(
parser
);
...
...
@@ -621,17 +651,30 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
return
NULL
;
memset
(
device
,
0
,
sizeof
(
struct
hid_device
));
if
(
!
(
device
->
collection
=
kmalloc
(
sizeof
(
struct
hid_collection
)
*
HID_DEFAULT_NUM_COLLECTIONS
,
GFP_KERNEL
)))
{
kfree
(
device
);
return
NULL
;
}
memset
(
device
->
collection
,
0
,
sizeof
(
struct
hid_collection
)
*
HID_DEFAULT_NUM_COLLECTIONS
);
device
->
collection_size
=
HID_DEFAULT_NUM_COLLECTIONS
;
for
(
i
=
0
;
i
<
HID_REPORT_TYPES
;
i
++
)
INIT_LIST_HEAD
(
&
device
->
report_enum
[
i
].
report_list
);
if
(
!
(
device
->
rdesc
=
(
__u8
*
)
kmalloc
(
size
,
GFP_KERNEL
)))
{
kfree
(
device
->
collection
);
kfree
(
device
);
return
NULL
;
}
memcpy
(
device
->
rdesc
,
start
,
size
);
device
->
rsize
=
size
;
if
(
!
(
parser
=
kmalloc
(
sizeof
(
struct
hid_parser
),
GFP_KERNEL
)))
{
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
kfree
(
device
);
return
NULL
;
}
...
...
@@ -643,6 +686,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if
(
item
.
format
!=
HID_ITEM_FORMAT_SHORT
)
{
dbg
(
"unexpected long global item"
);
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
hid_free_device
(
device
);
kfree
(
parser
);
return
NULL
;
...
...
@@ -651,6 +696,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if
(
dispatch_type
[
item
.
type
](
parser
,
&
item
))
{
dbg
(
"item %u %u %u %u parsing failed
\n
"
,
item
.
format
,
(
unsigned
)
item
.
size
,
(
unsigned
)
item
.
type
,
(
unsigned
)
item
.
tag
);
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
hid_free_device
(
device
);
kfree
(
parser
);
return
NULL
;
...
...
@@ -659,12 +706,16 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
if
(
start
==
end
)
{
if
(
parser
->
collection_stack_ptr
)
{
dbg
(
"unbalanced collection at end of report description"
);
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
hid_free_device
(
device
);
kfree
(
parser
);
return
NULL
;
}
if
(
parser
->
local
.
delimiter_depth
)
{
dbg
(
"unbalanced delimiter at end of report description"
);
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
hid_free_device
(
device
);
kfree
(
parser
);
return
NULL
;
...
...
@@ -675,6 +726,8 @@ static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
}
dbg
(
"item fetching failed at offset %d
\n
"
,
(
int
)(
end
-
start
));
kfree
(
device
->
rdesc
);
kfree
(
device
->
collection
);
hid_free_device
(
device
);
kfree
(
parser
);
return
NULL
;
...
...
@@ -740,22 +793,8 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
hid_dump_input
(
usage
,
value
);
if
(
hid
->
claimed
&
HID_CLAIMED_INPUT
)
hidinput_hid_event
(
hid
,
field
,
usage
,
value
);
#ifdef CONFIG_USB_HIDDEV
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
{
struct
hiddev_usage_ref
uref
;
unsigned
type
=
field
->
report_type
;
uref
.
report_type
=
(
type
==
HID_INPUT_REPORT
)
?
HID_REPORT_TYPE_INPUT
:
((
type
==
HID_OUTPUT_REPORT
)
?
HID_REPORT_TYPE_OUTPUT
:
((
type
==
HID_FEATURE_REPORT
)
?
HID_REPORT_TYPE_FEATURE
:
0
));
uref
.
report_id
=
field
->
report
->
id
;
uref
.
field_index
=
field
->
index
;
uref
.
usage_index
=
(
usage
-
field
->
usage
);
uref
.
usage_code
=
usage
->
hid
;
uref
.
value
=
value
;
hiddev_hid_event
(
hid
,
&
uref
);
}
#endif
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
hiddev_hid_event
(
hid
,
field
,
usage
,
value
);
}
/*
...
...
@@ -851,21 +890,6 @@ static int hid_input_report(int type, struct urb *urb)
return
-
1
;
}
#ifdef CONFIG_USB_HIDDEV
/* Notify listeners that a report has been received */
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
{
struct
hiddev_usage_ref
uref
;
memset
(
&
uref
,
0
,
sizeof
(
uref
));
uref
.
report_type
=
(
type
==
HID_INPUT_REPORT
)
?
HID_REPORT_TYPE_INPUT
:
((
type
==
HID_OUTPUT_REPORT
)
?
HID_REPORT_TYPE_OUTPUT
:
((
type
==
HID_FEATURE_REPORT
)
?
HID_REPORT_TYPE_FEATURE
:
0
));
uref
.
report_id
=
report
->
id
;
uref
.
field_index
=
HID_FIELD_INDEX_NONE
;
hiddev_hid_event
(
hid
,
&
uref
);
}
#endif
size
=
((
report
->
size
-
1
)
>>
3
)
+
1
;
if
(
len
<
size
)
{
...
...
@@ -873,6 +897,9 @@ static int hid_input_report(int type, struct urb *urb)
return
-
1
;
}
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
hiddev_report_event
(
hid
,
report
);
for
(
n
=
0
;
n
<
report
->
maxfield
;
n
++
)
hid_input_field
(
hid
,
report
->
field
[
n
],
data
);
...
...
@@ -1284,6 +1311,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
#define USB_VENDOR_ID_MGE 0x0463
#define USB_DEVICE_ID_MGE_UPS 0xffff
#define USB_DEVICE_ID_MGE_UPS1 0x0001
struct
hid_blacklist
{
__u16
idVendor
;
__u16
idProduct
;
...
...
@@ -1301,6 +1332,8 @@ struct hid_blacklist {
{
USB_VENDOR_ID_ATEN
,
USB_DEVICE_ID_ATEN_CS124U
,
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_ATEN
,
USB_DEVICE_ID_ATEN_2PORTKVM
,
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_ATEN
,
USB_DEVICE_ID_ATEN_4PORTKVM
,
HID_QUIRK_NOGET
},
{
USB_VENDOR_ID_MGE
,
USB_DEVICE_ID_MGE_UPS
,
HID_QUIRK_HIDDEV
},
{
USB_VENDOR_ID_MGE
,
USB_DEVICE_ID_MGE_UPS1
,
HID_QUIRK_HIDDEV
},
{
0
,
0
}
};
...
...
@@ -1438,6 +1471,27 @@ static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
return
NULL
;
}
static
void
hid_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
{
struct
hid_device
*
hid
=
ptr
;
usb_unlink_urb
(
hid
->
urbin
);
usb_unlink_urb
(
hid
->
urbout
);
usb_unlink_urb
(
hid
->
urbctrl
);
if
(
hid
->
claimed
&
HID_CLAIMED_INPUT
)
hidinput_disconnect
(
hid
);
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
hiddev_disconnect
(
hid
);
usb_free_urb
(
hid
->
urbin
);
usb_free_urb
(
hid
->
urbctrl
);
if
(
hid
->
urbout
)
usb_free_urb
(
hid
->
urbout
);
hid_free_device
(
hid
);
}
static
void
*
hid_probe
(
struct
usb_device
*
dev
,
unsigned
int
ifnum
,
const
struct
usb_device_id
*
id
)
{
...
...
@@ -1462,7 +1516,7 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
hid
->
claimed
|=
HID_CLAIMED_HIDDEV
;
if
(
!
hid
->
claimed
)
{
hid_
free_device
(
hid
);
hid_
disconnect
(
dev
,
hid
);
return
NULL
;
}
...
...
@@ -1476,11 +1530,14 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
printk
(
"hiddev%d"
,
hid
->
minor
);
c
=
"Device"
;
for
(
i
=
0
;
i
<
hid
->
maxapplication
;
i
++
)
if
((
hid
->
application
[
i
]
&
0xffff
)
<
ARRAY_SIZE
(
hid_types
))
{
c
=
hid_types
[
hid
->
application
[
i
]
&
0xffff
];
for
(
i
=
0
;
i
<
hid
->
maxcollection
;
i
++
)
{
if
(
hid
->
collection
[
i
].
type
==
HID_COLLECTION_APPLICATION
&&
(
hid
->
collection
[
i
].
usage
&
HID_USAGE_PAGE
)
==
HID_UP_GENDESK
&&
(
hid
->
collection
[
i
].
usage
&
0xffff
)
<
ARRAY_SIZE
(
hid_types
))
{
c
=
hid_types
[
hid
->
collection
[
i
].
usage
&
0xffff
];
break
;
}
}
usb_make_path
(
dev
,
path
,
63
);
...
...
@@ -1490,27 +1547,6 @@ static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
return
hid
;
}
static
void
hid_disconnect
(
struct
usb_device
*
dev
,
void
*
ptr
)
{
struct
hid_device
*
hid
=
ptr
;
usb_unlink_urb
(
hid
->
urbin
);
usb_unlink_urb
(
hid
->
urbout
);
usb_unlink_urb
(
hid
->
urbctrl
);
if
(
hid
->
claimed
&
HID_CLAIMED_INPUT
)
hidinput_disconnect
(
hid
);
if
(
hid
->
claimed
&
HID_CLAIMED_HIDDEV
)
hiddev_disconnect
(
hid
);
usb_free_urb
(
hid
->
urbin
);
usb_free_urb
(
hid
->
urbctrl
);
if
(
hid
->
urbout
)
usb_free_urb
(
hid
->
urbout
);
hid_free_device
(
hid
);
}
static
struct
usb_device_id
hid_usb_ids
[]
=
{
{
match_flags
:
USB_DEVICE_ID_MATCH_INT_CLASS
,
bInterfaceClass:
USB_INTERFACE_CLASS_HID
},
...
...
drivers/usb/input/hid-debug.h
View file @
7fde4915
...
...
@@ -352,12 +352,6 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
unsigned
i
,
k
;
static
char
*
table
[]
=
{
"INPUT"
,
"OUTPUT"
,
"FEATURE"
};
for
(
i
=
0
;
i
<
device
->
maxapplication
;
i
++
)
{
printk
(
"Application("
);
resolv_usage
(
device
->
application
[
i
]);
printk
(
")
\n
"
);
}
for
(
i
=
0
;
i
<
HID_REPORT_TYPES
;
i
++
)
{
report_enum
=
device
->
report_enum
+
i
;
list
=
report_enum
->
report_list
.
next
;
...
...
drivers/usb/input/hid-input.c
View file @
7fde4915
...
...
@@ -474,11 +474,12 @@ int hidinput_connect(struct hid_device *hid)
struct
list_head
*
list
;
int
i
,
j
,
k
;
for
(
i
=
0
;
i
<
hid
->
maxapplication
;
i
++
)
if
(
IS_INPUT_APPLICATION
(
hid
->
application
[
i
]))
for
(
i
=
0
;
i
<
hid
->
maxcollection
;
i
++
)
if
(
hid
->
collection
[
i
].
type
==
HID_COLLECTION_APPLICATION
&&
IS_INPUT_APPLICATION
(
hid
->
collection
[
i
].
usage
))
break
;
if
(
i
==
hid
->
max
applica
tion
)
if
(
i
==
hid
->
max
collec
tion
)
return
-
1
;
hid
->
input
.
private
=
hid
;
...
...
drivers/usb/input/hid.h
View file @
7fde4915
...
...
@@ -205,6 +205,7 @@ struct hid_item {
#define HID_QUIRK_NOTOUCH 0x02
#define HID_QUIRK_IGNORE 0x04
#define HID_QUIRK_NOGET 0x08
#define HID_QUIRK_HIDDEV 0x10
/*
* This is the global enviroment of the parser. This information is
...
...
@@ -231,10 +232,11 @@ struct hid_global {
#define HID_MAX_DESCRIPTOR_SIZE 4096
#define HID_MAX_USAGES 1024
#define HID_
MAX_APPLICATIONS
16
#define HID_
DEFAULT_NUM_COLLECTIONS
16
struct
hid_local
{
unsigned
usage
[
HID_MAX_USAGES
];
/* usage array */
unsigned
collection_index
[
HID_MAX_USAGES
];
/* collection index array */
unsigned
usage_index
;
unsigned
usage_minimum
;
unsigned
delimiter_depth
;
...
...
@@ -249,10 +251,12 @@ struct hid_local {
struct
hid_collection
{
unsigned
type
;
unsigned
usage
;
unsigned
level
;
};
struct
hid_usage
{
unsigned
hid
;
/* hid usage code */
unsigned
collection_index
;
/* index into collection array */
__u16
code
;
/* input driver code */
__u8
type
;
/* input driver type */
__s8
hat_min
;
/* hat switch fun */
...
...
@@ -319,7 +323,9 @@ struct hid_control_fifo {
struct
hid_device
{
/* device report descriptor */
__u8
*
rdesc
;
unsigned
rsize
;
unsigned
application
[
HID_MAX_APPLICATIONS
];
/* List of HID applications */
struct
hid_collection
*
collection
;
/* List of HID collections */
unsigned
collection_size
;
/* Number of allocated hid_collections */
unsigned
maxcollection
;
/* Number of parsed collections */
unsigned
maxapplication
;
/* Number of applications */
unsigned
version
;
/* HID version */
unsigned
country
;
/* HID country */
...
...
@@ -374,7 +380,7 @@ struct hid_parser {
struct
hid_global
global_stack
[
HID_GLOBAL_STACK_SIZE
];
unsigned
global_stack_ptr
;
struct
hid_local
local
;
struct
hid_collection
collection_stack
[
HID_COLLECTION_STACK_SIZE
];
unsigned
collection_stack
[
HID_COLLECTION_STACK_SIZE
];
unsigned
collection_stack_ptr
;
struct
hid_device
*
device
;
};
...
...
drivers/usb/input/hiddev.c
View file @
7fde4915
...
...
@@ -80,6 +80,7 @@ extern struct usb_driver hiddev_driver;
static
struct
hid_report
*
hiddev_lookup_report
(
struct
hid_device
*
hid
,
struct
hiddev_report_info
*
rinfo
)
{
unsigned
flags
=
rinfo
->
report_id
&
~
HID_REPORT_ID_MASK
;
struct
hid_report_enum
*
report_enum
;
struct
list_head
*
list
;
...
...
@@ -88,8 +89,11 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
report_enum
=
hid
->
report_enum
+
(
rinfo
->
report_type
-
HID_REPORT_TYPE_MIN
);
if
((
rinfo
->
report_id
&
~
HID_REPORT_ID_MASK
)
!=
0
)
{
switch
(
rinfo
->
report_id
&
~
HID_REPORT_ID_MASK
)
{
switch
(
flags
)
{
case
0
:
/* Nothing to do -- report_id is already set correctly */
break
;
case
HID_REPORT_ID_FIRST
:
list
=
report_enum
->
report_list
.
next
;
if
(
list
==
&
report_enum
->
report_list
)
return
NULL
;
...
...
@@ -98,8 +102,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
case
HID_REPORT_ID_NEXT
:
list
=
(
struct
list_head
*
)
report_enum
->
report_id_hash
[
rinfo
->
report_id
&
HID_REPORT_ID_MASK
];
report_enum
->
report_id_hash
[
rinfo
->
report_id
&
HID_REPORT_ID_MASK
];
if
(
list
==
NULL
)
return
NULL
;
list
=
list
->
next
;
if
(
list
==
&
report_enum
->
report_list
)
return
NULL
;
...
...
@@ -109,7 +112,6 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
default:
return
NULL
;
}
}
return
report_enum
->
report_id_hash
[
rinfo
->
report_id
];
}
...
...
@@ -152,11 +154,8 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
return
NULL
;
}
/*
* This is where hid.c calls into hiddev to pass an event that occurred over
* the interrupt pipe
*/
void
hiddev_hid_event
(
struct
hid_device
*
hid
,
struct
hiddev_usage_ref
*
uref
)
static
void
hiddev_send_event
(
struct
hid_device
*
hid
,
struct
hiddev_usage_ref
*
uref
)
{
struct
hiddev
*
hiddev
=
hid
->
hiddev
;
struct
hiddev_list
*
list
=
hiddev
->
list
;
...
...
@@ -176,6 +175,44 @@ void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref)
wake_up_interruptible
(
&
hiddev
->
wait
);
}
/*
* This is where hid.c calls into hiddev to pass an event that occurred over
* the interrupt pipe
*/
void
hiddev_hid_event
(
struct
hid_device
*
hid
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
)
{
unsigned
type
=
field
->
report_type
;
struct
hiddev_usage_ref
uref
;
uref
.
report_type
=
(
type
==
HID_INPUT_REPORT
)
?
HID_REPORT_TYPE_INPUT
:
((
type
==
HID_OUTPUT_REPORT
)
?
HID_REPORT_TYPE_OUTPUT
:
((
type
==
HID_FEATURE_REPORT
)
?
HID_REPORT_TYPE_FEATURE
:
0
));
uref
.
report_id
=
field
->
report
->
id
;
uref
.
field_index
=
field
->
index
;
uref
.
usage_index
=
(
usage
-
field
->
usage
);
uref
.
usage_code
=
usage
->
hid
;
uref
.
value
=
value
;
hiddev_send_event
(
hid
,
&
uref
);
}
void
hiddev_report_event
(
struct
hid_device
*
hid
,
struct
hid_report
*
report
)
{
unsigned
type
=
report
->
type
;
struct
hiddev_usage_ref
uref
;
memset
(
&
uref
,
0
,
sizeof
(
uref
));
uref
.
report_type
=
(
type
==
HID_INPUT_REPORT
)
?
HID_REPORT_TYPE_INPUT
:
((
type
==
HID_OUTPUT_REPORT
)
?
HID_REPORT_TYPE_OUTPUT
:
((
type
==
HID_FEATURE_REPORT
)
?
HID_REPORT_TYPE_FEATURE
:
0
));
uref
.
report_id
=
report
->
id
;
hiddev_send_event
(
hid
,
&
uref
);
}
/*
* fasync file op
*/
...
...
@@ -256,8 +293,7 @@ static int hiddev_open(struct inode * inode, struct file * file) {
/*
* "write" file op
*/
static
ssize_t
hiddev_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
static
ssize_t
hiddev_write
(
struct
file
*
file
,
const
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
return
-
EINVAL
;
}
...
...
@@ -265,8 +301,7 @@ static ssize_t hiddev_write(struct file * file, const char * buffer,
/*
* "read" file op
*/
static
ssize_t
hiddev_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
static
ssize_t
hiddev_read
(
struct
file
*
file
,
char
*
buffer
,
size_t
count
,
loff_t
*
ppos
)
{
DECLARE_WAITQUEUE
(
wait
,
current
);
struct
hiddev_list
*
list
=
file
->
private_data
;
...
...
@@ -354,17 +389,20 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait)
/*
* "ioctl" file op
*/
static
int
hiddev_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
static
int
hiddev_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
struct
hiddev_list
*
list
=
file
->
private_data
;
struct
hiddev
*
hiddev
=
list
->
hiddev
;
struct
hid_device
*
hid
=
hiddev
->
hid
;
struct
usb_device
*
dev
=
hid
->
dev
;
struct
hiddev_collection_info
cinfo
;
struct
hiddev_report_info
rinfo
;
struct
hiddev_field_info
finfo
;
struct
hiddev_usage_ref
uref
;
struct
hiddev_devinfo
dinfo
;
struct
hid_report
*
report
;
struct
hid_field
*
field
;
int
i
;
if
(
!
hiddev
->
exist
)
return
-
EIO
;
...
...
@@ -376,11 +414,18 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
case
HIDIOCAPPLICATION
:
if
(
arg
<
0
||
arg
>=
hid
->
maxapplication
)
return
-
EINVAL
;
return
hid
->
application
[
arg
];
for
(
i
=
0
;
i
<
hid
->
maxcollection
;
i
++
)
if
(
hid
->
collection
[
i
].
type
==
HID_COLLECTION_APPLICATION
&&
arg
--
==
0
)
break
;
if
(
i
==
hid
->
maxcollection
)
return
-
EINVAL
;
return
hid
->
collection
[
i
].
usage
;
case
HIDIOCGDEVINFO
:
{
struct
hiddev_devinfo
dinfo
;
dinfo
.
bustype
=
BUS_USB
;
dinfo
.
busnum
=
dev
->
bus
->
busnum
;
dinfo
.
devnum
=
dev
->
devnum
;
...
...
@@ -389,11 +434,12 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
dinfo
.
product
=
dev
->
descriptor
.
idProduct
;
dinfo
.
version
=
dev
->
descriptor
.
bcdDevice
;
dinfo
.
num_applications
=
hid
->
maxapplication
;
return
copy_to_user
((
void
*
)
arg
,
&
dinfo
,
sizeof
(
dinfo
));
}
if
(
copy_to_user
((
void
*
)
arg
,
&
dinfo
,
sizeof
(
dinfo
)))
return
-
EFAULT
;
case
HIDIOCGFLAG
:
return
put_user
(
list
->
flags
,
(
int
*
)
arg
);
if
(
put_user
(
list
->
flags
,
(
int
*
)
arg
))
return
-
EFAULT
;
case
HIDIOCSFLAG
:
{
...
...
@@ -438,7 +484,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
}
case
HIDIOCINITREPORT
:
hid_init_reports
(
hid
);
return
0
;
...
...
@@ -480,11 +525,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
rinfo
.
num_fields
=
report
->
maxfield
;
return
copy_to_user
((
void
*
)
arg
,
&
rinfo
,
sizeof
(
rinfo
));
if
(
copy_to_user
((
void
*
)
arg
,
&
rinfo
,
sizeof
(
rinfo
)))
return
-
EFAULT
;
case
HIDIOCGFIELDINFO
:
{
struct
hiddev_field_info
finfo
;
if
(
copy_from_user
(
&
finfo
,
(
void
*
)
arg
,
sizeof
(
finfo
)))
return
-
EFAULT
;
rinfo
.
report_type
=
finfo
.
report_type
;
...
...
@@ -512,8 +556,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
finfo
.
unit_exponent
=
field
->
unit_exponent
;
finfo
.
unit
=
field
->
unit
;
return
copy_to_user
((
void
*
)
arg
,
&
finfo
,
sizeof
(
finfo
));
}
if
(
copy_to_user
((
void
*
)
arg
,
&
finfo
,
sizeof
(
finfo
)))
return
-
EFAULT
;
case
HIDIOCGUCODE
:
if
(
copy_from_user
(
&
uref
,
(
void
*
)
arg
,
sizeof
(
uref
)))
...
...
@@ -533,12 +577,18 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
uref
.
usage_code
=
field
->
usage
[
uref
.
usage_index
].
hid
;
return
copy_to_user
((
void
*
)
arg
,
&
uref
,
sizeof
(
uref
));
if
(
copy_to_user
((
void
*
)
arg
,
&
uref
,
sizeof
(
uref
)))
return
-
EFAULT
;
case
HIDIOCGUSAGE
:
case
HIDIOCSUSAGE
:
case
HIDIOCGCOLLECTIONINDEX
:
if
(
copy_from_user
(
&
uref
,
(
void
*
)
arg
,
sizeof
(
uref
)))
return
-
EFAULT
;
if
(
cmd
!=
HIDIOCGUSAGE
&&
uref
.
report_type
==
HID_REPORT_TYPE_INPUT
)
return
-
EINVAL
;
if
(
uref
.
report_id
==
HID_REPORT_ID_UNKNOWN
)
{
field
=
hiddev_lookup_usage
(
hid
,
&
uref
);
if
(
field
==
NULL
)
...
...
@@ -557,37 +607,36 @@ static int hiddev_ioctl(struct inode *inode, struct file *file,
return
-
EINVAL
;
}
switch
(
cmd
)
{
case
HIDIOCGUSAGE
:
uref
.
value
=
field
->
value
[
uref
.
usage_index
];
return
copy_to_user
((
void
*
)
arg
,
&
uref
,
sizeof
(
uref
));
if
(
copy_to_user
((
void
*
)
arg
,
&
uref
,
sizeof
(
uref
)))
return
-
EFAULT
;
return
0
;
case
HIDIOCSUSAGE
:
if
(
copy_from_user
(
&
uref
,
(
void
*
)
arg
,
sizeof
(
uref
)))
return
-
EFAULT
;
field
->
value
[
uref
.
usage_index
]
=
uref
.
value
;
return
0
;
if
(
uref
.
report_type
==
HID_REPORT_TYPE_INPUT
)
return
-
EINVAL
;
case
HIDIOCGCOLLECTIONINDEX
:
return
field
->
usage
[
uref
.
usage_index
].
collection_index
;
}
if
(
uref
.
report_id
==
HID_REPORT_ID_UNKNOWN
)
{
field
=
hiddev_lookup_usage
(
hid
,
&
uref
);
if
(
field
==
NULL
)
return
-
EINVAL
;
}
else
{
rinfo
.
report_type
=
uref
.
report_type
;
rinfo
.
report_id
=
uref
.
report_id
;
if
((
report
=
hiddev_lookup_report
(
hid
,
&
rinfo
))
==
NULL
)
return
-
EINVAL
;
return
0
;
if
(
uref
.
field_index
>=
report
->
maxfield
)
return
-
EINVAL
;
case
HIDIOCGCOLLECTIONINFO
:
if
(
copy_from_user
(
&
cinfo
,
(
void
*
)
arg
,
sizeof
(
cinfo
)))
return
-
EFAULT
;
field
=
report
->
field
[
uref
.
field_index
];
if
(
uref
.
usage_index
>=
field
->
maxusage
)
if
(
cinfo
.
index
>=
hid
->
maxcollection
)
return
-
EINVAL
;
}
field
->
value
[
uref
.
usage_index
]
=
uref
.
value
;
cinfo
.
type
=
hid
->
collection
[
cinfo
.
index
].
type
;
cinfo
.
usage
=
hid
->
collection
[
cinfo
.
index
].
usage
;
cinfo
.
level
=
hid
->
collection
[
cinfo
.
index
].
level
;
if
(
copy_to_user
((
void
*
)
arg
,
&
cinfo
,
sizeof
(
cinfo
)))
return
-
EFAULT
;
return
0
;
default:
...
...
@@ -628,11 +677,13 @@ int hiddev_connect(struct hid_device *hid)
int
retval
;
char
devfs_name
[
16
];
for
(
i
=
0
;
i
<
hid
->
maxapplication
;
i
++
)
if
(
!
IS_INPUT_APPLICATION
(
hid
->
application
[
i
]))
for
(
i
=
0
;
i
<
hid
->
maxcollection
;
i
++
)
if
(
hid
->
collection
[
i
].
type
==
HID_COLLECTION_APPLICATION
&&
!
IS_INPUT_APPLICATION
(
hid
->
collection
[
i
].
usage
))
break
;
if
(
i
==
hid
->
max
application
)
if
(
i
==
hid
->
max
collection
&&
(
hid
->
quirks
&
HID_QUIRK_HIDDEV
)
==
0
)
return
-
1
;
retval
=
usb_register_dev
(
&
hiddev_fops
,
HIDDEV_MINOR_BASE
,
1
,
&
minor
);
...
...
@@ -657,10 +708,8 @@ int hiddev_connect(struct hid_device *hid)
sprintf
(
devfs_name
,
"hiddev%d"
,
minor
);
hiddev
->
devfs
=
devfs_register
(
hiddev_devfs_handle
,
devfs_name
,
DEVFS_FL_DEFAULT
,
USB_MAJOR
,
minor
+
HIDDEV_MINOR_BASE
,
S_IFCHR
|
S_IRUGO
|
S_IWUSR
,
&
hiddev_fops
,
NULL
);
DEVFS_FL_DEFAULT
,
USB_MAJOR
,
minor
+
HIDDEV_MINOR_BASE
,
S_IFCHR
|
S_IRUGO
|
S_IWUSR
,
&
hiddev_fops
,
NULL
);
hid
->
minor
=
minor
;
hid
->
hiddev
=
hiddev
;
...
...
drivers/usb/storage/transport.c
View file @
7fde4915
...
...
@@ -344,6 +344,12 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
len
=
srb
->
request_bufflen
;
}
/* According to the linux-scsi people, any command sent which
* violates this invariant is a bug. In the hopes of removing
* all the complex logic above, let's find them and eliminate them.
*/
BUG_ON
(
len
!=
srb
->
request_bufflen
);
return
len
;
}
...
...
include/linux/hiddev.h
View file @
7fde4915
...
...
@@ -49,6 +49,13 @@ struct hiddev_devinfo {
unsigned
num_applications
;
};
struct
hiddev_collection_info
{
unsigned
index
;
unsigned
type
;
unsigned
usage
;
unsigned
level
;
};
#define HID_STRING_SIZE 256
struct
hiddev_string_descriptor
{
int
index
;
...
...
@@ -64,9 +71,9 @@ struct hiddev_report_info {
/* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and
* report_id. Set report_id to REPORT_ID_UNKNOWN if the rest of the fields
* are unknown. Otherwise use a usage_ref struct filled in from a previous
* successful GUSAGE
/SUSAGE call to save time. To actually send a valu
e
*
to the device, perform a SUSAGE first, followed by a SREPORT. If an
*
INITREPORT is done, a GREPORT isn't necessary before a GUSAGE
.
* successful GUSAGE
call to save time. To actually send a value to th
e
*
device, perform a SUSAGE first, followed by a SREPORT. An INITREPORT or a
*
GREPORT isn't necessary for a GUSAGE to return valid data
.
*/
#define HID_REPORT_ID_UNKNOWN 0xffffffff
#define HID_REPORT_ID_FIRST 0x00000100
...
...
@@ -129,7 +136,7 @@ struct hiddev_usage_ref {
* Protocol version.
*/
#define HID_VERSION 0x01000
3
#define HID_VERSION 0x01000
4
/*
* IOCTLs (0x00 - 0x7f)
...
...
@@ -150,6 +157,8 @@ struct hiddev_usage_ref {
#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref)
#define HIDIOCGFLAG _IOR('H', 0x0E, int)
#define HIDIOCSFLAG _IOW('H', 0x0F, int)
#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref)
#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info)
/*
* Flags to be used in HIDIOCSFLAG
...
...
@@ -193,13 +202,17 @@ struct hiddev_usage_ref {
#ifdef CONFIG_USB_HIDDEV
int
hiddev_connect
(
struct
hid_device
*
);
void
hiddev_disconnect
(
struct
hid_device
*
);
void
hiddev_hid_event
(
struct
hid_device
*
,
struct
hiddev_usage_ref
*
ref
);
void
hiddev_hid_event
(
struct
hid_device
*
hid
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
);
void
hiddev_report_event
(
struct
hid_device
*
hid
,
struct
hid_report
*
report
);
int
__init
hiddev_init
(
void
);
void
__exit
hiddev_exit
(
void
);
#else
static
inline
void
*
hiddev_connect
(
struct
hid_device
*
hid
)
{
return
NULL
;
}
static
inline
int
hiddev_connect
(
struct
hid_device
*
hid
)
{
return
-
1
;
}
static
inline
void
hiddev_disconnect
(
struct
hid_device
*
hid
)
{
}
static
inline
void
hiddev_event
(
struct
hid_device
*
hid
,
unsigned
int
usage
,
int
value
)
{
}
static
inline
void
hiddev_hid_event
(
struct
hid_device
*
hid
,
struct
hid_field
*
field
,
struct
hid_usage
*
usage
,
__s32
value
)
{
}
static
inline
void
hiddev_report_event
(
struct
hid_device
*
hid
,
struct
hid_report
*
report
)
{
}
static
inline
int
hiddev_init
(
void
)
{
return
0
;
}
static
inline
void
hiddev_exit
(
void
)
{
}
#endif
...
...
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