ELF program segments offset in file - elf

I have a question,about elf program segments offsize in file. For example , a program readelf -f xx -W like this:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x4ca8e6 0x4ca8e6 R E 0x200000
LOAD 0x4cb000 0x0000000000acb000 0x0000000000acb000 0x035db8 0x04ed80 RW 0x200000
DYNAMIC 0x4ed4c8 0x0000000000aed4c8 0x0000000000aed4c8 0x000230 0x000230 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
TLS 0x4cb000 0x0000000000acb000 0x0000000000acb000 0x000010 0x000018 R 0x10
GNU_EH_FRAME 0x3dcf04 0x00000000007dcf04 0x00000000007dcf04 0x024c64 0x024c64 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame .gcc_except_table
03 .tdata .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss
04 .dynamic
05 .note.ABI-tag .note.gnu.build-id
06 .tdata .tbss
07 .eh_frame_hdr
08
The first load begin at offset 0x000000 and the size is 0x4ca8e6. why the second offset not (0x000000 + 0x4ca8e6), I see the (0x4cb000 - 0x4ca8e6) content, all 0. I can't get it. What the rule about the offset in file?

The first load begin at offset 0x000000 and the size is 0x4ca8e6. why the second offset not (0x000000 + 0x4ca8e6)
Because the loader mmaps LOAD segments directly into memory, for each LOAD segment the following must be true: (p_vaddr - p_offset) % page_size == 0.
On x86_64 the maximum page size is 2MiB (0x200000). This places severe restriction on the second (and subsequent) LOAD segment location.

Related

Understanding ELF TBSS and TDATA section loading

My elf file's sections are as follows
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS fffffffff7e020b0 000000b0
0000000000074f50 0000000000000000 AX 0 0 16
[ 2] .rodata PROGBITS fffffffff7e77000 00075000
0000000000014000 0000000000000000 AM 0 0 16
[ 3] .eh_frame_hdr PROGBITS fffffffff7e8b000 00089000
000000000000000c 0000000000000000 A 0 0 4
[ 4] .data PROGBITS fffffffff7e8b010 00089010
0000000000001ff0 0000000000000000 WA 0 0 16
[ 5] .bss NOBITS fffffffff7e8d000 0008b000
0000000000014000 0000000000000000 WA 0 0 4096
[ 6] .got PROGBITS fffffffff7ea1000 0009f000
0000000000001000 0000000000000000 WA 0 0 8
[ 7] .tdata PROGBITS fffffffff7ea2000 000a0000
000000000000b000 0000000000000000 WAT 0 0 8
[ 8] .tbss NOBITS fffffffff7ead000 000ab000
000000000000012a 0000000000000000 WAT 0 0 8
[ 9] .debug_abbrev PROGBITS 0000000000000000 000ab000
000000000001a8d4 0000000000000000 0 0 1
[10] .debug_info PROGBITS 0000000000000000 000c58d4
000000000016c624 0000000000000000 0 0 1
[11] .debug_aranges PROGBITS 0000000000000000 00231ef8
0000000000024130 0000000000000000 0 0 1
[12] .debug_ranges PROGBITS 0000000000000000 00256028
000000000004bfa0 0000000000000000 0 0 1
[13] .debug_str PROGBITS 0000000000000000 002a1fc8
0000000000123ecd 0000000000000001 MS 0 0 1
[14] .debug_pubnames PROGBITS 0000000000000000 003c5e95
000000000005da3c 0000000000000000 0 0 1
[15] .debug_pubtypes PROGBITS 0000000000000000 004238d1
00000000000a1e07 0000000000000000 0 0 1
[16] .debug_frame PROGBITS 0000000000000000 004c56d8
0000000000056c10 0000000000000000 0 0 8
[17] .debug_line PROGBITS 0000000000000000 0051c2e8
00000000000b5c55 0000000000000000 0 0 1
[18] .debug_loc PROGBITS 0000000000000000 005d1f3d
000000000000628c 0000000000000000 0 0 1
[19] .symtab SYMTAB 0000000000000000 005d81d0
0000000000015a20 0000000000000018 21 2565 8
[20] .shstrtab STRTAB 0000000000000000 005edbf0
00000000000000da 0000000000000000 0 0 1
[21] .strtab STRTAB 0000000000000000 005edcca
000000000004783e 0000000000000000 0 0 1
and the program headers are
Elf file type is EXEC (Executable file)
Entry point 0xfffffffff7e39be0
There are 2 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0xfffffffff7e02000 0x0000000000000000
0x00000000000ab000 0x00000000000ab12a RWE 0x1000
TLS 0x00000000000a0000 0xfffffffff7ea2000 0x00000000000a0000
0x000000000000b000 0x000000000000b12a RW 0x8
Section to Segment mapping:
Segment Sections...
00 .text .rodata .eh_frame_hdr .data .bss .got .tdata
01 .tdata .tbss
The TLS section's total size is as expected being the size of tdata + tbss sections.
From the TLS handling document, i expect that tdata and tbss sections will be right before the fs register's pointed value and thus the total size would be 0xb12a.
But one of the variables which use thread_local have an offset of fs - 0xb130 which is outside of the expected TLS size.
I am trying to understand why the variable is not offset to at-most 0xb12a but more than that?
Although the size of TLS here is 0xb12a. The alignment of 0x8 will make the TLS pointer move to 0xb130 which is the address of variable observed here.

why does not readelf report right sizes?

I have a Linux executable file (which is an ELF file) called a.out.
I use
readelf -hl a.out
and get output
ELF Header:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4008e0
Start of program headers: 64 (bytes into file)
Start of section headers: 910680 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 6
Size of section headers: 64 (bytes)
Number of section headers: 33
Section header string table index: 30
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000c9be6 0x00000000000c9be6 R E 200000
LOAD 0x00000000000c9eb8 0x00000000006c9eb8 0x00000000006c9eb8
0x0000000000001c98 0x0000000000003550 RW 200000
NOTE 0x0000000000000190 0x0000000000400190 0x0000000000400190
0x0000000000000044 0x0000000000000044 R 4
TLS 0x00000000000c9eb8 0x00000000006c9eb8 0x00000000006c9eb8
0x0000000000000020 0x0000000000000050 R 8
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x00000000000c9eb8 0x00000000006c9eb8 0x00000000006c9eb8
0x0000000000000148 0x0000000000000148 R 1
Section to Segment mapping:
Segment Sections...
00 .note.ABI-tag .note.gnu.build-id .rela.plt .init .plt .text __libc_freeres_fn __libc_thread_freeres_fn .fini .rodata __libc_subfreeres __libc_atexit .stapsdt.base __libc_thread_subfreeres .eh_frame .gcc_except_table
01 .tdata .init_array .fini_array .jcr .data.rel.ro .got .got.plt .data .bss __libc_freeres_ptrs
02 .note.ABI-tag .note.gnu.build-id
03 .tdata .tbss
04
05 .tdata .init_array .fini_array .jcr .data.rel.ro .got
According to the above output, this ELF file should have size
ELF header size : 64
+
Section headers : 64*33 = 2112
+
Program headers : 56*6 = 336
+
Segments : 834090 = 0x00000000000c9be6 + 0x0000000000001c98 + 0x0000000000000044 + 0x0000000000000020 + 0x0000000000000148
= 64 + 2112 + 336 + 834090 = 836602
However, /bin/ls reports file size 912792.
where are the 912792 - 836602 = 76190 bytes?
which parts did I forget to count?
UPDATE
according to #Jonathon Reinhart, I re count the size using section sizes instead of segment size by
echo "print 0x020 + 0x024 + 0x0f0 + 0x01a + 0x0a0 + 0x09eda4 + 0x02529 + 0x0de + 0x09 + 0x01d320 + 0x050 + 0x08 + 0x01 + 0x08 + 0x0b04c + 0x0b2 + 0x020 + 0x010 + 0x010 + 0x08 + 0x0e4 + 0x010 + 0x068 + 0x01ad0 + 0x023 + 0x0f18 + 0x0169 + 0x0b100 + 0x0685a" | /usr/bin/python
The section size values used above are extracted from the output of readelf -S a.out and the size of section type of "NOBITS" were not counted.
The above code output 909459 which is bigger than segment size 834090,
however, the total size is still not equal to the file size.
64 + 2112 + 336 + 909459 = 911971 != 912792
still missing 912792 - 911971 = 821 bytes.
update2 [solved]
according to the comment, I have test the offset. The result tells me that the adding pad does exist.

What is the format of special section in ELF

I try to write a program to generate ELF(based on Arm and execute through qemu-arm). Most format in ELF has been well illustrated
on wiki. But I can't find any spec describe the format of special section(e.g. .text .data(especially what I want to know)).
I tried to put some initialized global variable in .data section. What format should I write in ELF(.data section) if I have global statement like: int a = 10;
There is not special format for .text and .data.
When the static linker links several .o file,
it simply concatenates the .text and .data segments (while resolving relocations)
and places them in the final .so or executable file according to the linker script (see gcc -Wl,-verbose /dev/null).
The .data segment simply contains the initial values of the instanciated global variables.
The .text segment simply contains the machine code of the routines/functions.
Let's take this simple C file:
char x[5] = {0xba, 0xbb, 0xbc, 0xbd, 0xbe};
char f(int i) {
return x[i];
}
Let's compile it:
$ gcc -c -o test.o test.c
Let's dump the .data section, using elfcat:
$ elfcat test.o --section-name .data | xxd
00000000: babb bcbd be .....
We can clearly explain the content of .data section.
Let's dump the .text section:
$ elfcat test.o --section-name .text | xxd
00000000: 5548 89e5 897d fc8b 45fc 4898 488d 1500 UH...}..E.H.H...
00000010: 0000 000f b604 105d c3
Let's decompile this:
$ elfcat test.o --section-name .text > test.text
$ r2 -a x86 -b 64 -qc pd test.text
0x00000000 55 push rbp
0x00000001 4889e5 mov rbp, rsp
0x00000004 897dfc mov dword [rbp - 4], edi
0x00000007 8b45fc mov eax, dword [rbp - 4]
0x0000000a 4898 cdqe
0x0000000c 488d15000000. lea rdx, qword [0x00000013] ; 19
0x00000013 0fb60410 movzx eax, byte [rax + rdx]
0x00000017 5d pop rbp
0x00000018 c3 ret
Again, there is nothing special in the text segment: it only contains the machine code of the routines/functions of my program.
Notice however the relocation and symbol informations in other segments:
$ readelf -a test.o
[ ... ]
Relocation section '.rela.text' at offset 0x1b8 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
00000000000f 000800000002 R_X86_64_PC32 0000000000000000 x - 4
Relocation section '.rela.eh_frame' at offset 0x1d0 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000000020 000200000002 R_X86_64_PC32 0000000000000000 .text + 0
[...]
Symbol table '.symtab' contains 10 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c
2: 0000000000000000 0 SECTION LOCAL DEFAULT 1
3: 0000000000000000 0 SECTION LOCAL DEFAULT 3
4: 0000000000000000 0 SECTION LOCAL DEFAULT 4
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 7
7: 0000000000000000 0 SECTION LOCAL DEFAULT 5
8: 0000000000000000 5 OBJECT GLOBAL DEFAULT 3 x
9: 0000000000000000 25 FUNC GLOBAL DEFAULT 1 f

Increasing the volume of an HID device using feature reports

What hex code do I need to send to the device (and what report index) to trigger a volume change?
I'm trying to use HID feature reports to increase the volume of a Jabra 410 headset. The Jabra provides the following interface and report description:
https://pastebin.com/ES8ivMym
Report Descriptor: (length is 273)
Item(Global): Usage Page, data= [ 0x0c ] 12
Consumer
Item(Local ): Usage, data= [ 0x01 ] 1
Consumer Control
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x01 ] 1
Item(Global): Usage Page, data= [ 0x0c ] 12
Consumer
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0xea ] 234
Volume Decrement
Item(Local ): Usage, data= [ 0xe9 ] 233
Volume Increment
Item(Local ): Usage, data= [ 0xe2 ] 226
Mute
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x03 ] 3
Item(Main ): Input, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x05 ] 5
Item(Main ): Input, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
(null)
Item(Local ): Usage, data= [ 0x01 ] 1
(null)
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x02 ] 2
Item(Local ): Usage, data= [ 0x01 ] 1
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x20 ] 32
Item(Main ): Output, data= [ 0x02 0x01 ] 258
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Buffered Bytes
Item(Local ): Usage, data= [ 0x01 ] 1
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x20 ] 32
Item(Main ): Input, data= [ 0x02 0x01 ] 258
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Buffered Bytes
Item(Global): Report ID, data= [ 0x04 ] 4
Item(Global): Usage Page, data= [ 0x30 0xff ] 65328
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x20 ] 32
(null)
Item(Local ): Usage, data= [ 0x97 ] 151
(null)
Item(Local ): Usage, data= [ 0x2b ] 43
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x03 ] 3
Item(Main ): Input, data= [ 0x23 ] 35
Constant Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x2f ] 47
(null)
Item(Local ): Usage, data= [ 0x21 ] 33
(null)
Item(Local ): Usage, data= [ 0x24 ] 36
(null)
Item(Local ): Usage, data= [ 0xfd 0xff ] 65533
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x04 ] 4
Item(Main ): Input, data= [ 0x07 ] 7
Constant Variable Relative No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x09 ] 9
Item(Main ): Input, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0xff 0xff ] 65535
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Main ): Feature, data= [ 0x22 ] 34
Data Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x07 ] 7
Item(Main ): Feature, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Usage Page, data= [ 0x40 0xff ] 65344
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x17 ] 23
(null)
Item(Local ): Usage, data= [ 0x1e ] 30
(null)
Item(Local ): Usage, data= [ 0x09 ] 9
(null)
Item(Local ): Usage, data= [ 0x18 ] 24
(null)
Item(Local ): Usage, data= [ 0x20 ] 32
(null)
Item(Local ): Usage, data= [ 0x21 ] 33
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x06 ] 6
Item(Main ): Output, data= [ 0x22 ] 34
Data Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Usage Page, data= [ 0x30 0xff ] 65328
(null)
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x9e ] 158
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Main ): Output, data= [ 0x22 ] 34
Data Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x09 ] 9
Item(Main ): Output, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Item(Global): Usage Page, data= [ 0x0b ] 11
Telephony
Item(Local ): Usage, data= [ 0x05 ] 5
Headset
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x03 ] 3
Item(Global): Usage Page, data= [ 0x0b ] 11
Telephony
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x20 ] 32
Hook Switch
Item(Local ): Usage, data= [ 0x97 ] 151
Line Busy Tone
Item(Local ): Usage, data= [ 0x2b ] 43
Speaker Phone
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x03 ] 3
Item(Main ): Input, data= [ 0x23 ] 35
Constant Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x2f ] 47
Phone Mute
Item(Local ): Usage, data= [ 0x21 ] 33
Flash
Item(Local ): Usage, data= [ 0x24 ] 36
Redial
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x03 ] 3
Item(Main ): Input, data= [ 0x07 ] 7
Constant Variable Relative No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x07 ] 7
Programmable Button
Item(Global): Usage Page, data= [ 0x09 ] 9
Buttons
Item(Local ): Usage, data= [ 0x01 ] 1
Button 1 (Primary)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Main ): Input, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x09 ] 9
Item(Main ): Input, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Usage Page, data= [ 0x08 ] 8
LEDs
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x17 ] 23
Off-Hook
Item(Local ): Usage, data= [ 0x1e ] 30
Speaker
Item(Local ): Usage, data= [ 0x09 ] 9
Mute
Item(Local ): Usage, data= [ 0x18 ] 24
Ring
Item(Local ): Usage, data= [ 0x20 ] 32
Hold
Item(Local ): Usage, data= [ 0x21 ] 33
Microphone
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x06 ] 6
Item(Main ): Output, data= [ 0x22 ] 34
Data Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Usage Page, data= [ 0x0b ] 11
Telephony
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Local ): Usage, data= [ 0x9e ] 158
(null)
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Main ): Output, data= [ 0x22 ] 34
Data Variable Absolute No_Wrap Linear
No_Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x09 ] 9
Item(Main ): Output, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
I have successfully used feature report #3 to interact with the device, including the manipulation of some LEDs and call states. However, no combination of data changes the volume, and I get no response whatsoever when interacting with feature report #1, which should be responsible for volume if I'm reading the report properly.
For example, sending a hex value of 05 (as in 00000101) to page #3 results in the device going to a muted state.
I decoded the report descriptor and it appears that the volume increment/decrement reports are sent from the device (headset) to the host (PC or whatever) using an input report, not a feature report. That is, the device tells the host to increment/decrement the volume - not the other way around.
BTW, I only see one feature report defined and it uses REPORT_ID 0x04.
Specifically, the input report with REPORT_ID 0x01 is used for volume control:
//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: ConsumerControl
uint8_t CD_ConsumerControlVolumeDecrement : 1; // Usage 0x000C00EA: Volume Decrement, Value = 0 to 1
uint8_t CD_ConsumerControlVolumeIncrement : 1; // Usage 0x000C00E9: Volume Increment, Value = 0 to 1
uint8_t CD_ConsumerControlMute : 1; // Usage 0x000C00E2: Mute, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} inputReport01_t;
The full decoded report descriptor is shown below...
hidrdd git:master ❯ rexx rd.rex --dump -dsa samples/headset-jabra410.rd
//--------------------------------------------------------------------------------
// Report descriptor data in hex (length 273 bytes)
//--------------------------------------------------------------------------------
// 050C0901 A1018501 050C1500 250109EA 09E909E2 75019503 81027501 95058101
// C00600FF 0901A101 85020901 150026FF 00750895 20920201 09011500 26FF0075
// 08952082 02018504 0630FF15 00250109 20099709 2B750195 03812309 2F092109
// 240AFDFF 75019504 81077501 95098101 0AFFFF75 019501B1 22750195 07B10106
// 40FF1500 25010917 091E0909 09180920 09217501 95069122 0630FF15 00250109
// 9E750195 01912275 01950991 01C0050B 0905A101 8503050B 15002501 09200997
// 092B7501 95038123 092F0921 09247501 95038107 09070509 09017501 95018102
// 95098101 05081500 25010917 091E0909 09180920 09217501 95069122 050B1500
// 2501099E 75019501 91227501 95099101 C0
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 0C (GLOBAL) USAGE_PAGE 0x000C Consumer Device Page
09 01 (LOCAL) USAGE 0x000C0001 Consumer Control (CA=Application Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x000C0001: Page=Consumer Device Page, Usage=Consumer Control, Type=CA)
85 01 (GLOBAL) REPORT_ID 0x01 (1)
05 0C (GLOBAL) USAGE_PAGE 0x000C Consumer Device Page <-- Redundant: USAGE_PAGE is already 0x000C
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
09 EA (LOCAL) USAGE 0x000C00EA Volume Decrement (RTC=Re-trigger Control)
09 E9 (LOCAL) USAGE 0x000C00E9 Volume Increment (RTC=Re-trigger Control)
09 E2 (LOCAL) USAGE 0x000C00E2 Mute (OOC=On/Off Control)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
81 02 (MAIN) INPUT 0x00000002 (3 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields
81 01 (MAIN) INPUT 0x00000001 (5 fields x 1 bit) 1=Constant 0=Array 0=Absolute
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: ConsumerControl
uint8_t CD_ConsumerControlVolumeDecrement : 1; // Usage 0x000C00EA: Volume Decrement, Value = 0 to 1
uint8_t CD_ConsumerControlVolumeIncrement : 1; // Usage 0x000C00E9: Volume Increment, Value = 0 to 1
uint8_t CD_ConsumerControlMute : 1; // Usage 0x000C00E2: Mute, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} inputReport01_t;
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
06 00FF (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
09 01 (LOCAL) USAGE 0xFF000001 <-- Warning: Undocumented usage
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0xFF000001: Page=Vendor-defined, Usage=, Type=)
85 02 (GLOBAL) REPORT_ID 0x02 (2)
09 01 (LOCAL) USAGE 0xFF000001 <-- Warning: Undocumented usage
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 20 (GLOBAL) REPORT_COUNT 0x20 (32) Number of fields
92 0201 (MAIN) OUTPUT 0x00000102 (32 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
09 01 (LOCAL) USAGE 0xFF000001 <-- Warning: Undocumented usage
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00 (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) <-- Redundant: LOGICAL_MAXIMUM is already 255
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 20 (GLOBAL) REPORT_COUNT 0x20 (32) Number of fields <-- Redundant: REPORT_COUNT is already 32
82 0201 (MAIN) INPUT 0x00000102 (32 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
85 04 (GLOBAL) REPORT_ID 0x04 (4)
06 30FF (GLOBAL) USAGE_PAGE 0xFF30 Vendor-defined
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
09 20 (LOCAL) USAGE 0xFF300020 <-- Warning: Undocumented usage
09 97 (LOCAL) USAGE 0xFF300097 <-- Warning: Undocumented usage
09 2B (LOCAL) USAGE 0xFF30002B <-- Warning: Undocumented usage
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
81 23 (MAIN) INPUT 0x00000023 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 2F (LOCAL) USAGE 0xFF30002F <-- Warning: Undocumented usage
09 21 (LOCAL) USAGE 0xFF300021 <-- Warning: Undocumented usage
09 24 (LOCAL) USAGE 0xFF300024 <-- Warning: Undocumented usage
0A FDFF (LOCAL) USAGE 0xFF30FFFD <-- Warning: Undocumented usage
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 04 (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
81 07 (MAIN) INPUT 0x00000007 (4 fields x 1 bit) 1=Constant 1=Variable 1=Relative 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09 (GLOBAL) REPORT_COUNT 0x09 (9) Number of fields
81 01 (MAIN) INPUT 0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute
0A FFFF (LOCAL) USAGE 0xFF30FFFF <-- Warning: Undocumented usage
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
B1 22 (MAIN) FEATURE 0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 07 (GLOBAL) REPORT_COUNT 0x07 (7) Number of fields
B1 01 (MAIN) FEATURE 0x00000001 (7 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
06 40FF (GLOBAL) USAGE_PAGE 0xFF40 Vendor-defined
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 17 (LOCAL) USAGE 0xFF400017 <-- Warning: Undocumented usage
09 1E (LOCAL) USAGE 0xFF40001E <-- Warning: Undocumented usage
09 09 (LOCAL) USAGE 0xFF400009 <-- Warning: Undocumented usage
09 18 (LOCAL) USAGE 0xFF400018 <-- Warning: Undocumented usage
09 20 (LOCAL) USAGE 0xFF400020 <-- Warning: Undocumented usage
09 21 (LOCAL) USAGE 0xFF400021 <-- Warning: Undocumented usage
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields
91 22 (MAIN) OUTPUT 0x00000022 (6 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
06 30FF (GLOBAL) USAGE_PAGE 0xFF30 Vendor-defined
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 9E (LOCAL) USAGE 0xFF30009E <-- Warning: Undocumented usage
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
91 22 (MAIN) OUTPUT 0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09 (GLOBAL) REPORT_COUNT 0x09 (9) Number of fields
91 01 (MAIN) OUTPUT 0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Vendor-defined featureReport 04 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x04 (4)
uint8_t VEN_VendorDefinedFFFF : 1; // Usage 0xFF30FFFF: , Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} featureReport04_t;
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 02 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x02 (2)
uint8_t VEN_VendorDefined0001[32]; // Usage 0xFF000001: , Value = 0 to 255
} inputReport02_t;
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 04 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x04 (4)
uint8_t VEN_VendorDefined0020 : 1; // Usage 0xFF300020: , Value = 0 to 1
uint8_t VEN_VendorDefined0097 : 1; // Usage 0xFF300097: , Value = 0 to 1
uint8_t VEN_VendorDefined002B : 1; // Usage 0xFF30002B: , Value = 0 to 1
uint8_t VEN_VendorDefined002F : 1; // Usage 0xFF30002F: , Value = 0 to 1
uint8_t VEN_VendorDefined0021 : 1; // Usage 0xFF300021: , Value = 0 to 1
uint8_t VEN_VendorDefined0024 : 1; // Usage 0xFF300024: , Value = 0 to 1
uint8_t VEN_VendorDefinedFFFD : 1; // Usage 0xFF30FFFD: , Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} inputReport04_t;
//--------------------------------------------------------------------------------
// Vendor-defined outputReport 02 (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x02 (2)
uint8_t VEN_VendorDefined0001[32]; // Usage 0xFF000001: , Value = 0 to 255
} outputReport02_t;
//--------------------------------------------------------------------------------
// Vendor-defined outputReport 04 (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x04 (4)
uint8_t VEN_VendorDefined0017 : 1; // Usage 0xFF400017: , Value = 0 to 1
uint8_t VEN_VendorDefined001E : 1; // Usage 0xFF40001E: , Value = 0 to 1
uint8_t VEN_VendorDefined0009 : 1; // Usage 0xFF400009: , Value = 0 to 1
uint8_t VEN_VendorDefined0018 : 1; // Usage 0xFF400018: , Value = 0 to 1
uint8_t VEN_VendorDefined0020 : 1; // Usage 0xFF400020: , Value = 0 to 1
uint8_t VEN_VendorDefined0021 : 1; // Usage 0xFF400021: , Value = 0 to 1
uint8_t VEN_VendorDefined009E : 1; // Usage 0xFF30009E: , Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} outputReport04_t;
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 0B (GLOBAL) USAGE_PAGE 0x000B Telephony Device Page
09 05 (LOCAL) USAGE 0x000B0005 Headset (CL=Logical Collection)
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x000B0005: Page=Telephony Device Page, Usage=Headset, Type=CL) <-- Warning: USAGE type should be CA (Application)
85 03 (GLOBAL) REPORT_ID 0x03 (3)
05 0B (GLOBAL) USAGE_PAGE 0x000B Telephony Device Page <-- Redundant: USAGE_PAGE is already 0x000B
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 20 (LOCAL) USAGE 0x000B0020 Hook Switch (OOC=On/Off Control)
09 97 (LOCAL) USAGE 0x000B0097 Line Busy Tone (MC=Momentary Control)
09 2B (LOCAL) USAGE 0x000B002B Speaker Phone (OOC=On/Off Control)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
81 23 (MAIN) INPUT 0x00000023 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 2F (LOCAL) USAGE 0x000B002F Phone Mute (OOC=On/Off Control)
09 21 (LOCAL) USAGE 0x000B0021 Flash (MC=Momentary Control)
09 24 (LOCAL) USAGE 0x000B0024 Redial (OSC=One Shot Control)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields <-- Redundant: REPORT_COUNT is already 3
81 07 (MAIN) INPUT 0x00000007 (3 fields x 1 bit) 1=Constant 1=Variable 1=Relative 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 07 (LOCAL) USAGE 0x000B0007 Programmable Button (NAry=Named Array)
05 09 (GLOBAL) USAGE_PAGE 0x0009 Button Page
09 01 (LOCAL) USAGE 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
81 02 (MAIN) INPUT 0x00000002 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 09 (GLOBAL) REPORT_COUNT 0x09 (9) Number of fields
81 01 (MAIN) INPUT 0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute
05 08 (GLOBAL) USAGE_PAGE 0x0008 LED Indicator Page
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 17 (LOCAL) USAGE 0x00080017 Off-Hook (OOC=On/Off Control)
09 1E (LOCAL) USAGE 0x0008001E Speaker (OOC=On/Off Control)
09 09 (LOCAL) USAGE 0x00080009 Mute (OOC=On/Off Control)
09 18 (LOCAL) USAGE 0x00080018 Ring (OOC=On/Off Control)
09 20 (LOCAL) USAGE 0x00080020 Hold (OOC=On/Off Control)
09 21 (LOCAL) USAGE 0x00080021 Microphone (OOC=On/Off Control)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 06 (GLOBAL) REPORT_COUNT 0x06 (6) Number of fields
91 22 (MAIN) OUTPUT 0x00000022 (6 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 0B (GLOBAL) USAGE_PAGE 0x000B Telephony Device Page
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 9E (LOCAL) USAGE 0x000B009E Ringer (OOC=On/Off Control)
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
91 22 (MAIN) OUTPUT 0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01 (GLOBAL) REPORT_SIZE 0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09 (GLOBAL) REPORT_COUNT 0x09 (9) Number of fields
91 01 (MAIN) OUTPUT 0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Telephony Device Page inputReport 03 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x03 (3)
// Collection: Headset
uint8_t TEL_HeadsetHookSwitch : 1; // Usage 0x000B0020: Hook Switch, Value = 0 to 1
uint8_t TEL_HeadsetLineBusyTone : 1; // Usage 0x000B0097: Line Busy Tone, Value = 0 to 1
uint8_t TEL_HeadsetSpeakerPhone : 1; // Usage 0x000B002B: Speaker Phone, Value = 0 to 1
uint8_t TEL_HeadsetPhoneMute : 1; // Usage 0x000B002F: Phone Mute, Value = 0 to 1
uint8_t TEL_HeadsetFlash : 1; // Usage 0x000B0021: Flash, Value = 0 to 1
uint8_t TEL_HeadsetRedial : 1; // Usage 0x000B0024: Redial, Value = 0 to 1
uint8_t TEL_HeadsetProgrammableButton : 1; // Usage 0x000B0007: Programmable Button, Value = 0 to 1
// Usage 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot) Value = 0 to 1 <-- Ignored: REPORT_COUNT (1) is too small
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} inputReport03_t;
//--------------------------------------------------------------------------------
// LED Indicator Page outputReport 03 (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x03 (3)
// Collection: Headset
uint8_t LED_HeadsetOffHook : 1; // Usage 0x00080017: Off-Hook, Value = 0 to 1
uint8_t LED_HeadsetSpeaker : 1; // Usage 0x0008001E: Speaker, Value = 0 to 1
uint8_t LED_HeadsetMute : 1; // Usage 0x00080009: Mute, Value = 0 to 1
uint8_t LED_HeadsetRing : 1; // Usage 0x00080018: Ring, Value = 0 to 1
uint8_t LED_HeadsetHold : 1; // Usage 0x00080020: Hold, Value = 0 to 1
uint8_t LED_HeadsetMicrophone : 1; // Usage 0x00080021: Microphone, Value = 0 to 1
uint8_t TEL_HeadsetRinger : 1; // Usage 0x000B009E: Ringer, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} outputReport03_t;

How to detect text mode or graphics mode on boot loader?

I want to detect which mode I just using now with BIOS intXX when running bootloader I wrote.
How to detect now is text mode or graphics mode?
Which interrupt function I should use?
Thank you~
I didn't figure out why when I run int 10 ,the value of AL doesn't change.
(0) Breakpoint 1, 0x00007c00 in ?? ()
Next at t=12943079
(0) [0x00007c00] 0000:7c00 (unk. ctxt): mov ah, 0x0f ; b40f
<bochs:3> reg
eax: 0x0000aa55 43605
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e476c 935788
edi: 0x0000ffac 65452
eip: 0x00007c00
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
<bochs:4> n
Next at t=12943080
(0) [0x00007c02] 0000:7c02 (unk. ctxt): mov al, 0xaa ; b0aa
<bochs:5> reg
eax: 0x00000f55 3925
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e476c 935788
edi: 0x0000ffac 65452
eip: 0x00007c02
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
<bochs:6> n
Next at t=12943081
(0) [0x00007c04] 0000:7c04 (unk. ctxt): int 0x0a ; cd0a
<bochs:7> reg
eax: 0x00000faa 4010
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e476c 935788
edi: 0x0000ffac 65452
eip: 0x00007c04
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
<bochs:8> n
Next at t=12943083
(0) [0x00007c06] 0000:7c06 (unk. ctxt): mov dl, al ; 88c2
<bochs:9> reg
eax: 0x00000faa 4010
ecx: 0x00090000 589824
edx: 0x00000000 0
ebx: 0x00000000 0
esp: 0x0000ffd6 65494
ebp: 0x00000000 0
esi: 0x000e476c 935788
edi: 0x0000ffac 65452
eip: 0x00007c06
eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf
<bochs:10>
INT10, F
AH = 0F
on return:
AL = mode currently set(page mode)
BH = current display page
Page mode:
AL = 00 40x25 B/W text (CGA,EGA,MCGA,VGA)
= 01 40x25 16 color text (CGA,EGA,MCGA,VGA)
= 02 80x25 16 shades of gray text (CGA,EGA,MCGA,VGA)
= 03 80x25 16 color text (CGA,EGA,MCGA,VGA)
= 04 320x200 4 color graphics (CGA,EGA,MCGA,VGA)
= 05 320x200 4 color graphics (CGA,EGA,MCGA,VGA)
= 06 640x200 B/W graphics (CGA,EGA,MCGA,VGA)
= 07 80x25 Monochrome text (MDA,HERC,EGA,VGA)
= 08 160x200 16 color graphics (PCjr)
= 09 320x200 16 color graphics (PCjr)
= 0A 640x200 4 color graphics (PCjr)
= 0B Reserved (EGA BIOS function 11)
= 0C Reserved (EGA BIOS function 11)
= 0D 320x200 16 color graphics (EGA,VGA)
= 0E 640x200 16 color graphics (EGA,VGA)
= 0F 640x350 Monochrome graphics (EGA,VGA)
= 10 640x350 16 color graphics (EGA or VGA with 128K)
640x350 4 color graphics (64K EGA)
= 11 640x480 B/W graphics (MCGA,VGA)
= 12 640x480 16 color graphics (VGA)
= 13 320x200 256 color graphics (MCGA,VGA)
= 8x EGA, MCGA or VGA ignore bit 7, see below
= 9x EGA, MCGA or VGA ignore bit 7, see below