USB Hid driver Help
Lucas Tanure
tanure at linux.com
Tue Feb 4 13:15:10 EST 2020
On Tue, Feb 4, 2020 at 1:27 PM Lucas Tanure <tanure at linux.com> wrote:
>
> On Mon, Feb 3, 2020 at 10:00 PM Lucas Tanure <tanure at linux.com> wrote:
> >
> > On Mon, Feb 3, 2020 at 8:11 PM Greg KH <greg at kroah.com> wrote:
> > >
> > > On Mon, Feb 03, 2020 at 04:32:46PM +0000, Lucas Tanure wrote:
> > > > Hi,
> > > >
> > > > I'm trying to write a Hid driver for MCP2210.
> > >
> > > What type of device is this?
> > It is a USB <-> SPI converter.
> >
> > >
> > > > But the USB Hid specification is quite complicated.
> > >
> > > The kernel should do it "all for you" already, why do you need to create
> > > a custom HID driver for this device?
> > I need a driver that register an SPI controller with in the kernel.
> > So this SPI controller would receive regmap reads/writes and translate
> > to USB HID packages and send to the SPI device attached in the other
> > side of the cable.
> >
> > >
> > > What type of HID reports does the device export and why doesn't the
> > > existing kernel drivers work for you?
> > I don't know enough yet to answer about HID Reports, but at end of
> > this e-mail I attached the lsub -v of the device.
> > I want to use this device in kernel space, registering a SPI
> > controller. And with this SPI controller another SPI slave device will
> > be registered.
> > So, for the SPI slave device it will be like there is no USB in
> > between itself and the kernel.
> >
> > >
> > > > I would like to know how to send and receive data to the device. Any
> > > > links to a good tutorial ?
> > >
> > > HID has the idea of "reports" and data comes in and out in that specific
> > > format, all depending on how the device describes itself. There's isn't
> > > usually a normal "send/receive" type of thing, but it all depends on the
> > > type of device.
> > Ok. Reading the datasheet of this device I need to send some 64 byte
> > arrays to configure the SPI bus.
> > And after that I start to send reports to communicate with the SPI slave device.
> >
> > >
> > > > This is my current driver is attached.
> > > >
> > > > Thanks
> > > > Lucas
> > >
> > > > #define DEBUG
> > > > #include <linux/module.h>
> > > > #include <linux/hid.h>
> > > > #include <linux/usb.h>
> > > >
> > > > static int mcp2210_probe(struct hid_device *hdev,
> > > > const struct hid_device_id *id)
> > > > {
> > > > struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> > > > int ret = 0;
> > > >
> > > > hid_dbg(hdev, "%s\n", __FUNCTION__);
> > > >
> > > > ret = hid_parse(hdev);
> > > > if (ret) {
> > > > hid_err(hdev, "parse failed\n");
> > > > return ret;
> > > > } else {
> > > > hid_dbg(hdev, "parse success\n");
> > > > }
> > > >
> > > > ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> > > > if (ret) {
> > > > hid_err(hdev, "hw start failed\n");
> > > > return ret;
> > > > } else {
> > > > hid_dbg(hdev, "start success\n");
> > > > }
> > >
> > > Does this all work?
> > For this version, it`s takes precedence from HID generic driver, wich is great.
> >
> > >
> > > What fails?
> > If I try to execute small test of data communcation:
> >
> > u8 *buf = kzalloc (64, GFP_KERNEL);
> > buf[0] = 0x50; //read EEPROM command
> > buf[1] = 0x03 ; // Address to read
> >
> > ret = hid_hw_raw_request(hdev, 0, buf, 64, HID_INPUT_REPORT, HID_REQ_GET_REPORT)
> > ret is -EPIPE.
> >
> > >
> > > thanks,
> > >
> > > greg k-h
> >
> > Many Thanks
> > Lucas
> >
> > Bus 001 Device 008: ID 04d8:00de Microchip Technology, Inc. MCP2210
> > USB to SPI Master
> > Couldn't open device, some information will be missing
> > Device Descriptor:
> > bLength 18
> > bDescriptorType 1
> > bcdUSB 2.00
> > bDeviceClass 0
> > bDeviceSubClass 0
> > bDeviceProtocol 0
> > bMaxPacketSize0 8
> > idVendor 0x04d8 Microchip Technology, Inc.
> > idProduct 0x00de
> > bcdDevice 0.02
> > iManufacturer 1
> > iProduct 2
> > iSerial 3
> > bNumConfigurations 1
> > Configuration Descriptor:
> > bLength 9
> > bDescriptorType 2
> > wTotalLength 0x0029
> > bNumInterfaces 1
> > bConfigurationValue 1
> > iConfiguration 0
> > bmAttributes 0x80
> > (Bus Powered)
> > MaxPower 100mA
> > Interface Descriptor:
> > bLength 9
> > bDescriptorType 4
> > bInterfaceNumber 0
> > bAlternateSetting 0
> > bNumEndpoints 2
> > bInterfaceClass 3 Human Interface Device
> > bInterfaceSubClass 0
> > bInterfaceProtocol 0
> > iInterface 0
> > HID Device Descriptor:
> > bLength 9
> > bDescriptorType 33
> > bcdHID 1.11
> > bCountryCode 0 Not supported
> > bNumDescriptors 1
> > bDescriptorType 34 Report
> > wDescriptorLength 29
> > Report Descriptors:
> > ** UNAVAILABLE **
> > Endpoint Descriptor:
> > bLength 7
> > bDescriptorType 5
> > bEndpointAddress 0x81 EP 1 IN
> > bmAttributes 3
> > Transfer Type Interrupt
> > Synch Type None
> > Usage Type Data
> > wMaxPacketSize 0x0040 1x 64 bytes
> > bInterval 1
> > Endpoint Descriptor:
> > bLength 7
> > bDescriptorType 5
> > bEndpointAddress 0x01 EP 1 OUT
> > bmAttributes 3
> > Transfer Type Interrupt
> > Synch Type None
> > Usage Type Data
> > wMaxPacketSize 0x0040 1x 64 bytes
> > bInterval 1
>
> Hi,
>
> If I use hid_hw_output_report I can write my 64 bytes buffer to the device.
> And I would expect a 64 bytes answer from the device, but I don't know
> how to get it.
>
> How do I know where my output data is going to ? Control Pipe or
> Interrupt Pipe ?
> How to I get the answer data from the device ?
>
> Thanks
> Lucas
>
> static int mcp2210_probe(struct hid_device *hdev,
> const struct hid_device_id *id)
> {
> //struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> int ret = 0;
> //struct hid_report *report = kzalloc(sizeof(struct
> hid_report), GFP_KERNEL);
> u8 *buf = kzalloc(64, GFP_KERNEL);
> u8 *buf2 = kzalloc(64, GFP_KERNEL);
>
> hid_dbg(hdev, "%s\n", __FUNCTION__);
>
> ret = hid_parse(hdev);
> if (ret) {
> hid_err(hdev, "parse failed\n");
> return ret;
> } else {
> hid_dbg(hdev, "parse success\n");
> }
>
> ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> if (ret) {
> hid_err(hdev, "hw start failed\n");
> return ret;
> } else {
> hid_dbg(hdev, "start success\n");
> }
> ret = hid_hw_open(hdev);
> hid_dbg(hdev, "hid_hw_open %d\n", ret);
>
> buf[0] = 0x50;
> buf[1] = 0x07;
> ret = hid_hw_output_report(hdev, buf, 64);
> hid_dbg(hdev, "hid_hw_output_report %d back
> [%x][%x][%x][%x]\n", ret, buf[0], buf[1], buf[2], buf[3]);
> //dmesg prints ret 0
>
> ret = hid_hw_raw_request(hdev, 0x81, buf2, 64,
> HID_INPUT_REPORT, HID_REQ_SET_REPORT);
> hid_dbg(hdev, "hid_input_report %d back [%x][%x][%x][%x]\n",
> ret, buf2[0], buf2[1], buf2[2], buf2[3]);
> //dmesg prints ret -32
>
> kfree(buf);
> kfree(buf2);
>
> return 0;
> }
>
> Dmesg:
> [ 72.991830] MCP2210 USB SPI Driver 0003:04D8:00DE.0002: mcp2210_probe
> [ 73.001793] MCP2210 USB SPI Driver 0003:04D8:00DE.0002: parse success
> [ 73.020234] MCP2210 USB SPI Driver 0003:04D8:00DE.0002:
> hiddev96,hidraw0: USB HID v1.11 Device [Microchip Technology Inc.
> MCP2210 USB-to-SPI Master] on usb-3f980000.usb-1.3/input0
> [ 73.039798] MCP2210 USB SPI Driver 0003:04D8:00DE.0002: start success
> [ 73.111858] MCP2210 USB SPI Driver 0003:04D8:00DE.0002: hid_hw_open 0
> [ 73.126599] MCP2210 USB SPI Driver 0003:04D8:00DE.0002:
> hid_hw_output_report 64 back [50][7][0][0]
> [ 73.140170] MCP2210 USB SPI Driver 0003:04D8:00DE.0002:
> hid_input_report -32 back [81][0][0][0]
Hi,
Doing some hacks I can see that using a user space library for this device uses:
[ 38.188226] [<806b9728>] (usbhid_output_report) from [<806b7db4>]
(hidraw_send_report+0x100/0x180)
And the layer between hidraw_send_report and usbhid_output_report is
hid_hw_output_report. So the function I should use is
hid_hw_output_report.
[ 38.137293] usbhid_output_report START
###############################################################################
[ 38.137306] usbhid_output_report 30 0 0 0 1 0 0
[ 38.148204] CPU: 3 PID: 475 Comm: hidusbtest Tainted: G C
4.19.69-v7+ #8
[ 38.148210] Hardware name: BCM2835
[ 38.164463] [<80111dac>] (unwind_backtrace) from [<8010d36c>]
(show_stack+0x20/0x24)
[ 38.172494] [<8010d36c>] (show_stack) from [<808166bc>]
(dump_stack+0xcc/0x110)
[ 38.179928] [<808166bc>] (dump_stack) from [<806b9728>]
(usbhid_output_report+0x94/0x144)
[ 38.188226] [<806b9728>] (usbhid_output_report) from [<806b7db4>]
(hidraw_send_report+0x100/0x180)
[ 38.197311] [<806b7db4>] (hidraw_send_report) from [<806b7e78>]
(hidraw_write+0x44/0x58)
[ 38.205517] [<806b7e78>] (hidraw_write) from [<802ac2ec>]
(__vfs_write+0x48/0x170)
[ 38.213193] [<802ac2ec>] (__vfs_write) from [<802ac5fc>]
(vfs_write+0xb4/0x1c4)
[ 38.220604] [<802ac5fc>] (vfs_write) from [<802ac8d4>] (ksys_write+0x6c/0xec)
[ 38.227841] [<802ac8d4>] (ksys_write) from [<802ac96c>] (sys_write+0x18/0x1c)
[ 38.235076] [<802ac96c>] (sys_write) from [<80101000>]
(ret_fast_syscall+0x0/0x28)
[ 38.242750] Exception stack(0xb391ffa8 to 0xb391fff0)
[ 38.247869] ffa0: 00000000 00014bec 00000003
7e9ec8b4 00000040 00000000
[ 38.256161] ffc0: 00000000 00014bec 00010f38 00000004 00000000
00000000 76fc9000 7e9ec844
[ 38.264451] ffe0: 0000006c 7e9ec810 00012f00 76cd4944
[ 38.272431] usbhid_output_report END
###############################################################################
And after using hid_hw_output_report my driver get a call at mcp2210_raw_event:
[ 38.333979] [<7f32a04c>] (mcp2210_raw_event [mcp2210]) from
[<806ae188>] (hid_input_report+0xf4/0x18c)
So, to receive the success status of the command sent with
hid_hw_output_report the driver receives an event.
Now I need to understand how to register my driver to receive this
event, once the hidraw driver will not be in use.
[ 38.284788] hid_irq_in 0
[ 38.284798] mcp2210_raw_event START
###############################################################################
[ 38.287370] CPU: 0 PID: 322 Comm: rs:main Q:Reg Tainted: G
C 4.19.69-v7+ #8
[ 38.306324] Hardware name: BCM2835
[ 38.309787] [<80111dac>] (unwind_backtrace) from [<8010d36c>]
(show_stack+0x20/0x24)
[ 38.317642] [<8010d36c>] (show_stack) from [<808166bc>]
(dump_stack+0xcc/0x110)
[ 38.325062] [<808166bc>] (dump_stack) from [<7f32a04c>]
(mcp2210_raw_event+0x4c/0x120 [mcp2210])
[ 38.333979] [<7f32a04c>] (mcp2210_raw_event [mcp2210]) from
[<806ae188>] (hid_input_report+0xf4/0x18c)
[ 38.343420] [<806ae188>] (hid_input_report) from [<806ba39c>]
(hid_irq_in+0x20c/0x248)
[ 38.351452] [<806ba39c>] (hid_irq_in) from [<8061bc48>]
(__usb_hcd_giveback_urb+0xa0/0x15c)
[ 38.359923] [<8061bc48>] (__usb_hcd_giveback_urb) from [<8061befc>]
(usb_hcd_giveback_urb+0xd4/0xf4)
[ 38.369188] [<8061befc>] (usb_hcd_giveback_urb) from [<80647434>]
(completion_tasklet_func+0x8c/0xcc)
[ 38.378542] [<80647434>] (completion_tasklet_func) from
[<80656374>] (tasklet_callback+0x20/0x24)
[ 38.387544] [<80656374>] (tasklet_callback) from [<80126a14>]
(tasklet_action_common.constprop.5+0x64/0xec)
[ 38.397426] [<80126a14>] (tasklet_action_common.constprop.5) from
[<80126af4>] (tasklet_hi_action+0x28/0x30)
[ 38.407394] [<80126af4>] (tasklet_hi_action) from [<801023f4>]
(__do_softirq+0x184/0x424)
[ 38.415687] [<801023f4>] (__do_softirq) from [<801266ac>]
(irq_exit+0xf8/0x134)
[ 38.423102] [<801266ac>] (irq_exit) from [<8017f710>]
(__handle_domain_irq+0x70/0xc4)
[ 38.431044] [<8017f710>] (__handle_domain_irq) from [<801021a0>]
(bcm2836_arm_irqchip_handle_irq+0x60/0xa8)
[ 38.440924] [<801021a0>] (bcm2836_arm_irqchip_handle_irq) from
[<801019bc>] (__irq_svc+0x5c/0x7c)
[ 38.449919] Exception stack(0xb63e5bf0 to 0xb63e5c38)
[ 38.455038] 5be0: b59d022c
00000005 80c66000 b9bb87c0
[ 38.463331] 5c00: b59d00b0 00000400 80c66000 b59d022c b97dc400
b63e5da0 b63e5cd4 b63e5c4c
[ 38.471622] 5c20: b63e5c50 b63e5c40 8036a1e4 808322fc 40000013 ffffffff
[ 38.478330] [<801019bc>] (__irq_svc) from [<808322fc>]
(_raw_spin_lock+0xc/0x54)
[ 38.485834] [<808322fc>] (_raw_spin_lock) from [<8036a1e4>]
(ext4_mark_iloc_dirty+0x108/0x8c8)
[ 38.494569] [<8036a1e4>] (ext4_mark_iloc_dirty) from [<8036aca4>]
(ext4_mark_inode_dirty+0x84/0x1f8)
[ 38.503832] [<8036aca4>] (ext4_mark_inode_dirty) from [<8037058c>]
(ext4_dirty_inode+0x54/0x70)
[ 38.512656] [<8037058c>] (ext4_dirty_inode) from [<802de768>]
(__mark_inode_dirty+0x50/0x414)
[ 38.521305] [<802de768>] (__mark_inode_dirty) from [<802c97a8>]
(generic_update_time+0xf4/0x11c)
[ 38.530215] [<802c97a8>] (generic_update_time) from [<802c9c88>]
(file_update_time+0x128/0x158)
[ 38.539039] [<802c9c88>] (file_update_time) from [<8023b158>]
(__generic_file_write_iter+0xa0/0x1e0)
[ 38.548305] [<8023b158>] (__generic_file_write_iter) from
[<80357a20>] (ext4_file_write_iter+0xfc/0x4b8)
[ 38.557921] [<80357a20>] (ext4_file_write_iter) from [<802ac3b0>]
(__vfs_write+0x10c/0x170)
[ 38.566390] [<802ac3b0>] (__vfs_write) from [<802ac5fc>]
(vfs_write+0xb4/0x1c4)
[ 38.573800] [<802ac5fc>] (vfs_write) from [<802ac8d4>] (ksys_write+0x6c/0xec)
[ 38.581034] [<802ac8d4>] (ksys_write) from [<802ac96c>] (sys_write+0x18/0x1c)
[ 38.588269] [<802ac96c>] (sys_write) from [<80101000>]
(ret_fast_syscall+0x0/0x28)
[ 38.595941] Exception stack(0xb63e5fa8 to 0xb63e5ff0)
[ 38.601059] 5fa0: 0000004a 75700bc0 00000007
75700bc0 0000004a 00000000
[ 38.609351] 5fc0: 0000004a 75700bc0 00000007 00000004 75700bc0
fffff815 00092410 000924e8
[ 38.617641] 5fe0: 00000002 760fe6e8 00000000 76eeb1bc
[ 38.622762] MCP2210 USB SPI Driver 0003:04D8:00DE.0001: mcp2210_raw_event 64
[ 38.629930] MCP2210 USB SPI Driver 0003:04D8:00DE.0001: 30 0 0 0 1
0 2 2 2 2 2 0 0 ff 1 ff 1 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
[ 38.646944] mcp2210_raw_event END
###############################################################################
More information about the Kernelnewbies
mailing list