Porting windows USB HID code to libusb - linux

I'm trying to port some windows code that uses HidD_GetInputReport to linux using libusb. From what I can tell I need to make a call to usb_control_msg but I'm having problems figuring out what parameters to pass in.
The report id I'm after is 0x01. Here is what I have so far.
#define HID_GET_REPORT 0x01
#define HID_REPORT_TYPE_INPUT 0x01
#define INTERFACE_NUMBER 0x00
int reportId = 0x01;
int bytesSent = usb_control_msg(
devHandle,
USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
HID_GET_REPORT,
(HID_REPORT_TYPE_INPUT << 8) | reportId,
INTERFACE_NUMBER,
buf,
sizeof(buf),
10000);
I'm really not sure about HID_GET_REPORT, HID_REPORT_TYPE_INPUT, and INTERFACE_NUMBER. I found them in an example on the web. Changing the various values does result in different return codes but those don't appear to be documented anywhere either.

Looks like you need to detach the kernel and claim the interface before calling other functions. I made calls to the following and it fixed the problem.
usb_detach_kernel_driver_np
usb_claim_interface

Related

STM32F4 ADXL345 I2C communication

I have started to work on I2C communication by examining adxl345 sensor. I wrote basic code to test if my code works or not. According to the ADXL345 technical documentation, the 0x00 register should return device id which is 0xE5.When I tried this register , the return value is 0. This application should be basic but I guess , I still missing something. Beside my experience, I also make a search at this community about the adxl345 problems,but I could not find answer. I would be very appreciated if you guide me in this problems. I attached my code.
void SysTick_Handler(void){
HAL_IncTick();
HAL_SYSTICK_IRQHandler();}
void SysClockEn();
/*System Configuration PA8-> I2C Clock , PC9-> I2C Data Lane*/
int main(){
SysClockEn();
HAL_Init();
/*------GPIO Configuration For I2C3------*/
__GPIOA_CLK_ENABLE();
GPIO_InitTypeDef *ptrB6,addrB6;
ptrB6 = &addrB6;
ptrB6->Alternate = GPIO_AF4_I2C3;
ptrB6->Pin = GPIO_PIN_8;
ptrB6->Pull = GPIO_NOPULL;
ptrB6->Speed =GPIO_SPEED_FREQ_HIGH;
ptrB6->Mode = GPIO_MODE_AF_OD;
HAL_GPIO_Init(GPIOA,ptrB6);
__GPIOC_CLK_ENABLE();
GPIO_InitTypeDef *ptrC,addrC;
ptrC = &addrC;
ptrC->Alternate =GPIO_AF4_I2C3;
ptrC->Mode =GPIO_MODE_AF_OD;
ptrC->Pin =GPIO_PIN_9;
ptrC->Pull =GPIO_NOPULL;
ptrC->Speed =GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC,ptrC);
/*-----I2C Configurations-----*/
//__HAL_RCC_I2C3_CLK_ENABLE();
__I2C3_CLK_ENABLE();
I2C_HandleTypeDef *ptrI2C,addrI2C;
ptrI2C = &addrI2C;
ptrI2C->Instance = I2C3;
ptrI2C->Init.ClockSpeed = 100000; //100Khz
ptrI2C->Init.DutyCycle = I2C_DUTYCYCLE_2;
ptrI2C->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
ptrI2C->Mode =HAL_I2C_MODE_MASTER;
//ptrI2C->Init.GeneralCallMode =I2C_GENERALCALL_DISABLE;
//ptrI2C->Init.NoStretchMode=I2C_NOSTRETCH_DISABLE;
HAL_I2C_Init(ptrI2C);
__HAL_I2C_ENABLE(ptrI2C);
uint8_t data=0x00;
unsigned char buffer[2];
uint8_t *buf;
unsigned char pt;
uint32_t ptr;
uint8_t val
while(1){
val=HAL_I2C_IsDeviceReady(ptrI2C,0x1D,0xe5,1000);
pt=HAL_I2C_GetState(ptrI2C);
//HAL_I2C_Master_Transmit(ptrI2C,0x1d,0x00,1,0);
//HAL_I2C_Master_Receive(ptrI2C,0x1d,buffer,1,100);
//HAL_Delay(2);
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
ptr=HAL_I2C_GetError(ptrI2C);
}
}
void SysClockEn(){
__PWR_CLK_ENABLE();
}
The documentation of the sensor says:
the 7-bit I2C address for the device is 0x1D
So in your code your should write:
#define SensAddr (0x1D<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...
This is because ST HAL considers the 7 bit address left shifted.
The documentation also says:
An alternate I2C address of 0x53 (followed by the R/W bit) can be chosen by grounding the SDO/ALT ADDRESS
If this is the case of your hardware, change the code to:
#define SensAddr (0x53<<1)
...
HAL_I2C_Mem_Read(ptrI2C,SensAddr,0x00,1,buffer,2,1000);
...

Custom SPI driver to implement lseek

I am trying to implement a SPI driver for custom hardware. I have started with a copy of the spidev driver, which has support for almost everything I need.
We're using a protocol that has three parts: a command bit (read / write) an address, and an arbitrary amount of data.
I had assumed that simply adding lseek capabilities would be the best way to do this. "Seek" to the desired address, then read or write any number of bytes. I created a custom .llseek in the new driver's file_operations, but I have never seen that function even be called. I have tried using fseek(), lseek(), and pread() and none of those functions seem to call the new my_lseek() function. Every call reports "errno 29 ESPIPE Illegal Seek"
The device is defined in the board.c file:
static struct spi_board_info my_spi_board_info[] __initdata = {
[0] = {
.modalias = "myspi",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 3000000,
.mode = SPI_MODE_0,
.controller_data = &spidev_mcspi_config,
}, ...
I suspect there might be something with the way that the dev files get created, mainly because the example that I found references filp->f_pos
static int myspi_llseek(struct file *filp, loff_t off, int whence)
{
...
newpos = filp->f_pos + off;
...
}
So my questions are: Is there a way to have this driver (lightly modified spidev) support the "seek" call? At what point does this get defined to return errno 29? Will I have to start from a new driver and not be able to rely on the spi_board_info() and spi_register_board_info() setup?
Only one driver in the /drivers/spi directory (spi-dw) references lseek, and they use the default_llseek implementation. There are a couple of "hacks" that we've come up with to get everything up and running, but I tend to be a person who wants to learn to get it done the right way.
Any suggestions are greatly appreciated! (PS, the kernel version is 3.4.48 for an OMAP Android system)
Spi driver dose not support any llseek or fseek functionality. It has these many call back functions.
struct spi_driver {
const struct spi_device_id *id_table;
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};
Now drivers/spi/spi-dw.c is register as a charter-driver(debugfs_create_file("registers", S_IFREG | S_IRUGO,
dws->debugfs, (void *)dws, &dw_spi_regs_ops);). So they implement to create a file in the debugfs filesystem. they implement lseek callback function.
static const struct file_operations dw_spi_regs_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = dw_spi_show_regs,
.llseek = default_llseek,
};
The file_operations structure is defined in linux/fs.h, and holds pointers to functions defined by the driver that perform various operations on the device. Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation
lseek -: lseek is a system call that is used to change the location of the read/write pointer of a file descriptor.
SPI -: The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial link used to connect microcontrollers to sensors, memory, and peripherals. SPI can not provide any lseek and fseek functionlity.
There are two type of SPI driver (https://www.kernel.org/doc/Documentation/spi/spi-summary)
Controller drivers ... controllers may be built into System-On-Chip
processors, and often support both Master and Slave roles.
These drivers touch hardware registers and may use DMA.
Or they can be PIO bitbangers, needing just GPIO pins.
Protocol drivers ... these pass messages through the controller
driver to communicate with a Slave or Master device on the
other side of an SPI link.
If you want to user read, write and llseek then you will have to register a charter-driver on top of SPI. Then you will able to achieve your acquirement.

Remove input driver bound to the HID interface

I'm playing with some driver code for a special kind of keyboard. And this keyboard does have special modes. According to the specification those modes could only be enabled by sending and getting feature reports.
I'm using 'hid.c' file and user mode to send HID reports. But both 'hid_read' and 'hid_get_feature_report' failed with error number -1.
I already tried detaching keyboard from kernel drivers using libusb, but when I do that, 'hid_open' fails. I guess this is due to that HID interface already using by 'input' or some driver by the kernel. So I may not need to unbind kernel hidraw driver, instead I should try unbinding the keyboard ('input') driver top of 'hidraw' driver. Am I correct?
And any idea how I could do that? And how to find what are drivers using which drivers and which low level driver bind to which driver?
I found the answer to this myself.
The answer is to dig this project and find it's hid implementation on libusb.
Or you could directly receive the report.
int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
{
int res = -1;
int skipped_report_id = 0;
int report_number = data[0];
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
data++;
length--;
skipped_report_id = 1;
}
res = libusb_control_transfer(dev->device_handle,
LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
0x01/*HID get_report*/,
(3/*HID feature*/ << 8) | report_number,
dev->interface,
(unsigned char *)data, length,
1000/*timeout millis*/);
if (res < 0)
return -1;
if (skipped_report_id)
res++;
return res;
}
I'm sorry I can't post my actual code due to some legal reasons. However the above code is from hidapi implementation.
So even you work with an old kernel , you still have the chance to make your driver working.
This answers to this question too: https://stackoverflow.com/questions/30565999/kernel-version-2-6-32-does-not-support-hidiocgfeature

UART takes some "kicking" to start receiving data

I am using a UART on a single board computer (Olimex A13) and I am trying to send and receive data through the UART. On the send side I have no problems. The Olimex board sends data to the serial buss and it is received on an external PC that is running putty terminal.
When I try to go in the other direction (PC sends data to be received by the Olimex board) I am running into a weird problem. When I start to send data, initially no data shows up on the Olimex board (I have tried 2 methods... cat /dev/ttyS0 and setting up a receive C program. Both exhibit the same results).
If I send data for a while (seems to vary from less than 10 characters to something over 20) at some point the uart seems to "wake up" and now data appears on the Olimex board. Once the data transfer starts it will keep going as long as I want and at fast or slow data rates. If I break out of the receive program or end the cat /dev/ttyS0 process and try to start receiving again, I need to go through the same process of "kicking" the uart until it decides it wants to receive again.
I have put an oscilloscope on the RX pin leading into the UART. The data coming in is at good levels and the data appears here from the very first send so the data is not being blocked initially and then arriving at the RX pin at some time later. So I am currently assuming that the issue is with a UART setting of some kind. Does anyone know of a UART setting that could possibly explain this behavior?
Below is the receive program that I am running. I don't think that there is an issue with it because I see the same behavior when I do a cat /dev/ttyS0. Any help here would be appreciated.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); return(-1); }
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* loop for input */
res = read(fd,buf,255); /* returns after 5 chars have been input */
buf[res]=0; /* so we can printf... */
printf("String:%s - Character Count:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
Sawdust made these comments....
"sends data to the serial buss" -- RS232 is not a "buss". "When I
start to send data" -- Your writing style is confusing. What kind of
data is sent to the Olimex? For the cat /dev/ttyS0 test, how did you
set up the serial port, or was it in an unknown mode? bzero(&newtio,
sizeof(newtio)); -- That is a dangerous way to setup the termios
structure. newtio.c_cflag = BAUDRATE... That is not the proper way to
set the baud rate; you need to use the cfset[io]speed() functions. You
write of a "kick", yet you don't mention doing anything explicit
ok, RS232 is not a buss, I misspoke....
The data I am sending is a stream of characters that are typed on Putty terminal.
For the /dev/ttyS0 test the settings are the same as are set in the c program. I verified this using stty.
I copied this code from another post. I was not sure what bzero did. If you could expand on "dangerous" that would be great. Or better if you have a better way to do what bzero does?
I will update the way to set baud rate.. but send is working perfectly and I verified using stty that baudrate was indeed 115200.
As far as "kicking" I mean that I need to send a number of bytes of data to the uart before any appear on the console. Others have mentioned a FIFO that may be an issue here but the first characters that are sent are lost. For example if I were to send the string of characters abcdefg.... I could type up until k and then l would appear on the console, and then any future characters after l would also appear in the console. If I were to go through the same process again after starting the receive program (or cat /dev/ttyS0) the point where the receive starts appearing could be in a different place (i.e. at h or n).

Sending UDP packets from the Linux Kernel

Even if a similar topic already exists, I noticed that it dates back two years, thus I guess it's more appropriate to open a fresh one...
I'm trying to figure out how to send UDP packets from the Linux Kernel (3.3.4), in order to monitor the behavior of the random number generator (/drivers/char/random.c). So far, I've managed to monitor a few things owing to the sock_create and sock_sendmsg functions. You can find the typical piece of code I use at the end of this message. (You might also want to download the complete modified random.c file here.)
By inserting this code inside the appropriate random.c functions, I'm able to send a UDP packet for each access to /dev/random and /dev/urandom, and each keyboard/mouse events used by the random number generator to harvest entropy. However it doesn't work at all when I try to monitor the disk events: it generates a kernel panic during boot.
Consequently, here's my main question: Have you any idea why my code causes so much trouble when inserted in the disk events function? (add_disk_randomness)
Alternatively, I've read about the netpoll API, which is supposed to handle this kind of UDP-in-kernel problems. Unfortunately I haven't found any relevant documentation apart from an quite interesting but outdated Red Hat presentation from 2005. Do you think I should rather use this API? If yes, have you got any example?
Any help would be appreciated.
Thanks in advance.
PS: It's my first question here, so please don't hesitate to tell me if I'm doing something wrong, I'll keep it in mind for future :)
#include <linux/net.h>
#include <linux/in.h>
#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_SEND ((unsigned long int)0x0a00020f) //10.0.2.15
static bool sock_init;
static struct socket *sock;
static struct sockaddr_in sin;
static struct msghdr msg;
static struct iovec iov;
[...]
int error, len;
mm_segment_t old_fs;
char message[MESSAGE_SIZE];
if (sock_init == false)
{
/* Creating socket */
error = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock);
if (error<0)
printk(KERN_DEBUG "Can't create socket. Error %d\n",error);
/* Connecting the socket */
sin.sin_family = AF_INET;
sin.sin_port = htons(1764);
sin.sin_addr.s_addr = htonl(INADDR_SEND);
error = sock->ops->connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr), 0);
if (error<0)
printk(KERN_DEBUG "Can't connect socket. Error %d\n",error);
/* Preparing message header */
msg.msg_flags = 0;
msg.msg_name = &sin;
msg.msg_namelen = sizeof(struct sockaddr_in);
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_iov = &iov;
msg.msg_control = NULL;
sock_init = true;
}
/* Sending a message */
sprintf(message,"EXTRACT / Time: %llu / InputPool: %4d / BlockingPool: %4d / NonblockingPool: %4d / Request: %4d\n",
get_cycles(),
input_pool.entropy_count,
blocking_pool.entropy_count,
nonblocking_pool.entropy_count,
nbytes*8);
iov.iov_base = message;
len = strlen(message);
iov.iov_len = len;
msg.msg_iovlen = len;
old_fs = get_fs();
set_fs(KERNEL_DS);
error = sock_sendmsg(sock,&msg,len);
set_fs(old_fs);
I solved my problem a few months ago. Here's the solution I used.
The standard packet-sending API (sock_create, connect, ...) cannot be used in a few contexts (interruptions). Using it in the wrong place leads to a KP.
The netpoll API is more "low-level" and works in every context. However, there are several conditions :
Ethernet devices
IP network
UDP only (no TCP)
Different computers for sending and receiving packets (You can't send to yourself.)
Make sure to respect them, because you won't get any error message if there's a problem. It will just silently fail :) Here's a bit of code.
Declaration
#include <linux/netpoll.h>
#define MESSAGE_SIZE 1024
#define INADDR_LOCAL ((unsigned long int)0xc0a80a54) //192.168.10.84
#define INADDR_SEND ((unsigned long int)0xc0a80a55) //192.168.10.85
static struct netpoll* np = NULL;
static struct netpoll np_t;
Initialization
np_t.name = "LRNG";
strlcpy(np_t.dev_name, "eth0", IFNAMSIZ);
np_t.local_ip = htonl(INADDR_LOCAL);
np_t.remote_ip = htonl(INADDR_SEND);
np_t.local_port = 6665;
np_t.remote_port = 6666;
memset(np_t.remote_mac, 0xff, ETH_ALEN);
netpoll_print_options(&np_t);
netpoll_setup(&np_t);
np = &np_t;
Use
char message[MESSAGE_SIZE];
sprintf(message,"%d\n",42);
int len = strlen(message);
netpoll_send_udp(np,message,len);
Hope it can help someone.
Panic during boot might be caused by you trying to use something which wasn't initialized yet. Looking at stack trace might help figuring out what actually happened.
As for you problem, I think you are trying to do a simple thing, so why not stick with simple tools? ;) printks might be bad idea indeed, but give trace_printk a go. trace_printk is part of Ftrace infrastructure.
Section Using trace_printk() in following article should teach you everything you need to know:
http://lwn.net/Articles/365835/

Resources