Uinput and Raspberry Pi - linux

I tried to ask this question on the Raspberry Pi forums, but I have received no responses at all. I thought I might query the minds of the StackOverflow community that has been so helpful in the past.
I'm writing a userspace driver for the Raspberry Pi (specifically, may be ported to other platforms later) which makes use of the bcm2835 library (GPIO) and uinput (Linux user-input virtual devices). I need to read GPIO pins and translate their values into simulated keypresses on a virtual keyboard. The GPIO part has been completed, and the translation part is also completed. Unfortunately, the virtual-keyboard part has not been solved. Uinput refuses to cooperate.
Now, the exact same code works perfectly on a Debian desktop machine. The evdev and uinput modules are required, both of which were loaded in all test cases. On the desktop, inputs can be triggered, however, on the Raspberry Pi, I can verify that the GPIO subsystem has registered the input, but the uinput events do not trigger. Does anyone have a lead on what I might do?
Thank you very much, if you need any information, logs, or otherwise, please let me know and I will post them as soon as I can.

This is a complete solution that works for me. I have a custom-made keypad and these are the keys I have defined. Here is the link to original pdf I used.
Of course you can define whatever key you want, just add it to the array.
Note: this code only works with elevated permission.
int allowed_keys[allowed_KEYS_size][2] = {0};
void main()
{
init_keys();
int fd = open_uinput();
int key_evt = getKeyEVT(49); // ASCII code for 1
// simulate key press and key release
emit(fd, EV_KEY, key_evt, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, key_evt, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);
}
long int emit(int fd, int type, int code, int val)
{
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
long int y = write(fd, &ie, sizeof(ie));
return y;
}
int open_uinput()
{
int fdui = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fdui < 0)
{
printf("uinput fd creation failed!\n");
exit(EXIT_FAILURE);
}
ioctl(fdui, UI_SET_EVBIT, EV_KEY);
ioctl(fdui, UI_SET_EVBIT, EV_SYN); //added by behzad
for (int i = 0; i < allowed_KEYS_size; i++)
ioctl(fdui, UI_SET_KEYBIT, allowed_keys[i][1]);
struct uinput_setup usetup;
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */
strcpy(usetup.name, "My Keypad. Ver 1.1");
ioctl(fdui, UI_DEV_SETUP, &usetup);
ioctl(fdui, UI_DEV_CREATE);
sleep(2);
return fdui;
}
int getKeyEVT(int k)
{
for (int i = 0; i < allowed_KEYS_size; i++)
{
if (allowed_keys[i][0] == k)
return allowed_keys[i][1];
}
return -1;
}
void init_keys()
{
// Reference:
// https://www.alt-codes.net/arrow_alt_codes.php
// /usr/include/linux/input-event-codes.h
allowed_keys[0][0] = 48; //ASCII ---> 0
allowed_keys[0][1] = KEY_0; //LINUX
allowed_keys[1][0] = 49; //ASCII
allowed_keys[1][1] = KEY_1; //LINUX
allowed_keys[2][0] = 50; //ASCII
allowed_keys[2][1] = KEY_2; //LINUX
allowed_keys[3][0] = 51; //ASCII
allowed_keys[3][1] = KEY_3; //LINUX
}

Related

How does generating an interrupt (calling irqfd) calls an interrupt on the KVM VM?

The KVM irqfd ioctl starts the irqfd for a file descriptor.
It does this:
case KVM_IRQFD: {
struct kvm_irqfd data;
r = -EFAULT;
if (copy_from_user(&data, argp, sizeof(data)))
goto out;
r = kvm_irqfd(kvm, &data);
break;
}
where kvm_irqfd is here
and calls kvm_irqfd_assign which initiates a wakeup queue:
init_waitqueue_func_entry(&irqfd->wait, irqfd_wakeup);
That is, irqfd_wakeup does this:
if (flags & EPOLLIN) {
u64 cnt;
eventfd_ctx_do_read(irqfd->eventfd, &cnt);
idx = srcu_read_lock(&kvm->irq_srcu);
do {
seq = read_seqcount_begin(&irqfd->irq_entry_sc);
irq = irqfd->irq_entry;
} while (read_seqcount_retry(&irqfd->irq_entry_sc, seq));
/* An event has been signaled, inject an interrupt */
if (kvm_arch_set_irq_inatomic(&irq, kvm,
KVM_USERSPACE_IRQ_SOURCE_ID, 1,
false) == -EWOULDBLOCK)
schedule_work(&irqfd->inject);
srcu_read_unlock(&kvm->irq_srcu, idx);
ret = 1;
}
As you can see in schedule_work(&irqfd->inject), it schedules the inject function, which is here:
static void
irqfd_inject(struct work_struct *work)
{
struct kvm_kernel_irqfd *irqfd =
container_of(work, struct kvm_kernel_irqfd, inject);
struct kvm *kvm = irqfd->kvm;
if (!irqfd->resampler) {
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 1,
false);
kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, irqfd->gsi, 0,
false);
} else
kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
irqfd->gsi, 1, false);
}
It calls kvm_set_irq defined here which does this:
int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
bool line_status)
{
struct kvm_kernel_irq_routing_entry irq_set[KVM_NR_IRQCHIPS];
int ret = -1, i, idx;
trace_kvm_set_irq(irq, level, irq_source_id);
/* Not possible to detect if the guest uses the PIC or the
* IOAPIC. So set the bit in both. The guest will ignore
* writes to the unused one.
*/
idx = srcu_read_lock(&kvm->irq_srcu);
i = kvm_irq_map_gsi(kvm, irq_set, irq);
srcu_read_unlock(&kvm->irq_srcu, idx);
while (i--) {
int r;
r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level,
line_status);
if (r < 0)
continue;
ret = r + ((ret < 0) ? 0 : ret);
}
return ret;
}
It looks like it finally calls something at:
r = irq_set[i].set(&irq_set[i], kvm, irq_source_id, level,
line_status);
This set function is filled by this.
It sets to this function:
static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id,
int level, bool line_status)
{
unsigned int spi_id = e->irqchip.pin + VGIC_NR_PRIVATE_IRQS;
if (!vgic_valid_spi(kvm, spi_id))
return -EINVAL;
return kvm_vgic_inject_irq(kvm, 0, spi_id, level, NULL);
}
which calls kvm_vgic_inject_irq which finally calls vgic_put_irq which calls this:
void __vgic_put_lpi_locked(struct kvm *kvm, struct vgic_irq *irq)
{
struct vgic_dist *dist = &kvm->arch.vgic;
if (!kref_put(&irq->refcount, vgic_irq_release))
return;
list_del(&irq->lpi_list);
dist->lpi_list_count--;
kfree(irq);
}
but I don't see how the GIC is called here, I only see the list being deleted.
I thought here it would send the interrupt to the GIC, which would then call the VM somehow.
I'm trying to understand how calling the irqfd file descriptor ends up calling an interrupt in the VM.
VGIC is for arm, you should check arm support file. While x86 is using either APIC or PIC. mostly APIC now.
You can check the specification of how those IRQ chip works to transfer the external signal to the destination core(vcpu).
For example, if you were using a x86 virtual machine(I have no idea of VGIC) which is using IOAPIC, there are 24 pins for example(emulated), and you should understand the APIC(hardware), then you know how it works.
https://elixir.bootlin.com/linux/v5.2.12/source/arch/x86/kvm/irq_comm.c#L271
https://elixir.bootlin.com/linux/v5.2.12/source/arch/x86/kvm/irq_comm.c#L38

Why my code is not able to create simple input device using uinput?

I am trying to learn using /dev/uinput in linux and copied simple code from kernel.org/doc/html/v4.12/input/uinput.html which is below:
#include <linux/uinput.h>
void emit(int fd, int type, int code, int val)
{
struct input_event ie;
ie.type = type;
ie.code = code;
ie.value = val;
/* timestamp values below are ignored */
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
write(fd, &ie, sizeof(ie));
}
int main(void)
{
struct uinput_setup usetup;
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
/*
* The ioctls below will enable the device that is about to be
* created, to pass key events, in this case the space key.
*/
ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);
memset(&usetup, 0, sizeof(usetup));
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234; /* sample vendor */
usetup.id.product = 0x5678; /* sample product */
strcpy(usetup.name, "Example device");
ioctl(fd, UI_DEV_SETUP, &usetup);
ioctl(fd, UI_DEV_CREATE);
/*
* On UI_DEV_CREATE the kernel will create the device node for this
* device. We are inserting a pause here so that userspace has time
* to detect, initialize the new device, and can start listening to
* the event, otherwise it will not notice the event we are about
* to send. This pause is only needed in our example code!
*/
sleep(1);
/* Key press, report the event, send key release, and report again */
emit(fd, EV_KEY, KEY_SPACE, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, KEY_SPACE, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);
/*
* Give userspace some time to read the events before we destroy the
* device with UI_DEV_DESTOY.
*/
sleep(1);
//ioctl(fd, UI_DEV_DESTROY);
close(fd);
return 0;
}
It compiles and run successfully without error. But i can't found any device created using this command xinput in terminal. I also checked inside /dev/input/ , but no changes found after executing my that program.
I tried it on Ubuntu, Kali. What i am missing ?
May be it help others.
int i=0;
while(i<100){
i++;
sleep(1);
emit(fd, EV_KEY, KEY_SPACE, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, KEY_SPACE, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);
}
I found that while program in loop, device is created. During that you can check with xinput command. After program ends, device get destroyed even if i don't call ioctl(fd,UI_DEV_DESTROY).

Difficulty establishing Bulk Transfer In USB Driver

I'm trying to send BULK data using BULK end point. But each time I submit the URB, it never fires the URB Callback function until I disconnect the device. Once I disconnect, it fires the callback throwing an EPROTO error. Anyone faced similar condition? Am I doing something incorrectly? I'm sure my device and data cable is okay. Here goes my code. Please suggest possible solution
static void urb_received(struct urb *urb)
{
printk("URB Received\n");
switch (urb->status) {
case 0:
printk("case SUCCESS\n");
break;
case -ETIMEDOUT:
printk("case ETIMEDOUT\n");
return;
case -ENOENT:
printk("case ENONET\n");
return;
case -EPROTO:
printk("case EPROTO\n");
return;
case -ECONNRESET:
printk("case ECONNRESET\n");
return;
case -ESHUTDOWN:
printk("case ESHUTDOWN\n");
return;
default:
printk("unknown urb status %i\n", urb->status);
}
printk("URB Received Exit\n");
}
static int myprobe(struct usb_interface *intf,
const struct usb_device_id *id)
{
static int intfcount = 0;
int ret = 0;
int i;
struct device *dev = &intf->dev;
struct mydevice *mydev;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct usb_host_interface *interface_descriptor;
struct usb_endpoint_descriptor *endpoint;
if (id->idVendor == MY_DEVICE_ID && id->idProduct == MY_PRODUCT_ID){
interface_descriptor = intf->cur_altsetting;
mydev = kzalloc(sizeof(struct mydev), GFP_KERNEL);
mydev->dev = dev;
mydev->udev = usb_get_dev(interface_to_usbdev(intf));
interface_descriptor = intf->cur_altsetting;
for(i=0; i<interface_descriptor->desc.bNumEndpoints; i++){
endpoint = &interface_descriptor->endpoint[i].desc;
if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
(endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK
){
printk("MEDEV: Bulk out endpoint");
mydev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
break;
}
}
bulk_urb = usb_alloc_urb(0, GFP_ATOMIC);
bulk_urb->transfer_buffer = kzalloc(8, GFP_ATOMIC);
usb_fill_bulk_urb(bulk_urb, usb_dev, usb_sndbulkpipe(mydev->udev, endpoint->bEndpointAddress),
bulk_urb->transfer_buffer, 8,
urb_received, NULL);
printk("BULK OUT PIPE = %d\n", mydev->bulk_out_pipe);
ret = usb_submit_urb(bulk_urb, GFP_ATOMIC);
return 0;
}
}
Just found out one interesting & same time annoying thing.
If in the above code I declare the usb_fill_bulk_urb with buffer_length=4, then it works perfectly. I can get the data from my android device. Even though I'm creating a buffer size of 8 bytes, I can't use buffer_length=8. I also played with other number but seems it only works for buffer_length=4.
To be sure I checked the endpoint descriptor of my device using lsusb -v command which shows it has a capacity of 512 bytes. Also in my android app, I've taken care off how many bytes I want to read. There is nothing wrong with the android app. I just can't understand why I won't be able to send more than 4 bytes at a time. By the way, if I send less than 4 bytes, that also works.

SoftwareSerial issues. Only when on power jack

My Code:
#include <SoftwareSerial.h>
SoftwareSerial bluetooth(2,3);
// Output
int redPin = 6; // Red LED,
int grnPin = 11; // Green LED,
int bluPin = 5; // Blue LED,
// Color arrays
int black[3] = { 0, 0, 0 };
int white[3] = { 100, 100, 100 };
int red[3] = { 100, 0, 0 };
int green[3] = { 0, 100, 0 };
int blue[3] = { 0, 0, 100 };
int yellow[3] = { 40, 95, 0 };
int dimWhite[3] = { 30, 30, 30 };
// etc.
// Set initial color
int redVal = black[0];
int grnVal = black[1];
int bluVal = black[2];
int wait = 10; // 10ms internal crossFade delay; increase for slower fades
int hold = 0; // Optional hold when a color is complete, before the next crossFade
int r = 0;
int g = 0;
int b = 0;
char mode = '\0';
// Initialize color variables
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;
// Set up the LED outputs
void setup()
{
pinMode(redPin, OUTPUT); // sets the pins as output
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);
Serial.begin(9600);
delay(1000);
bluetooth.begin(115200);
delay(100);
bluetooth.print("$$$");
delay(100);
bluetooth.println("U,9600,N");
bluetooth.begin(9600);
delay(100);
analogWrite(redPin, 0);
analogWrite(grnPin, 0);
analogWrite(bluPin, 0);
Serial.println("Bluetooth initiated.");
}
void printHEX() {
Serial.print(r, HEX);
Serial.print(g, HEX);
Serial.println(b, HEX);
bluetooth.print(r, HEX);
bluetooth.print(g, HEX);
bluetooth.println(b, HEX);
}
// Main program: list the order of crossfades
void loop()
{
//Read from bluetooth and write to usb serial
while(bluetooth.available())
{
if(mode == '\0') {
mode = (char)bluetooth.read();
}
if(mode == 'c'){
int r1 = bluetooth.parseInt();
int g1 = bluetooth.parseInt();
int b1 = bluetooth.parseInt();
if (bluetooth.read() == '\n') {
if(r1 != r || g1 != g || b1 != b) {
r = r1;
g = g1;
b = b1;
analogWrite(redPin, r);
analogWrite(grnPin, g);
analogWrite(bluPin, b);
printHEX();
mode = '\0';
} else {
printHEX();
mode = '\0';
}
}
} else if(mode == 'p') {
if (bluetooth.read() == '\n') {
printHEX();
mode = '\0';
}
}
}
//Read from usb serial to bluetooth
if(Serial.available())
{
char toSend = (char)Serial.read();
bluetooth.print(toSend);
}
}
If I run this code, everything works great. That is until I plug it into the power source and nothing else.
If I plug it into the power source, the program doesn't start (no bluetooth response). If I plug it into usb and power or usb only, the program works. If I unplug usb after plugging usb and power source the program still works! I have tried debugging as much as I can, but I don't know where the error is. The power supply is rated at 12V 2 Amps to light up the LED strips.
Update: I found out that if I press the reset button after power on everything starts to work. Is there a way to automatically reset arduino on startup???
I think you are using arduino leonardo.
Try this at very beginning of setup:
while(!Serial){}
while(!bluetooth){}
The arduino leonardo prepare the serial port after some while and may cause some problems.

Poll() to monitor a pin on BeagleBone Black. Continuous output even though pin not connected.

I want to trigger an event whenever there is a rising edge on one of the pins of Beaglebone Black.
Problem is, even though I havent connected that pin to anything, the output just goes on printing, interrupt occured, interrupt occured. I came across question Interrupts in Beaglebone
on stackoverflow and tried to follow the steps. There was a link to a Program which implements the functionality.
I read about poll() and I made slight changes in the program since I want to monitor just one pin. The changed code is :
int main(int argc, char **argv, char **envp)
{
struct pollfd fdset[1]; // fdset[2] changed to fdset[1] since I will monitor just 1 pin
int nfds = 1; // nfds changed from 2 to 1
int gpio_fd, timeout, rc;
char *buf[MAX_BUF];
unsigned int gpio;
int len;
if (argc < 2) {
printf("Usage: gpio-int <gpio-pin>\n\n");
printf("Waits for a change in the GPIO pin voltage level or input on stdin\n");
exit(-1);
}
gpio = atoi(argv[1]);
gpio_export(gpio);
gpio_set_dir(gpio, 0);
gpio_set_edge(gpio, "rising");
gpio_fd = gpio_fd_open(gpio);
timeout = POLL_TIMEOUT;
while (1) {
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = gpio_fd; // This is the pin to be monitored
fdset[0].events = POLLIN;
//fdset[1].fd = gpio_fd; // commented since I do not need this
//fdset[1].events = POLLPRI;
rc = poll(fdset, nfds, timeout);
if (rc < 0) {
printf("\npoll() failed!\n");
return -1;
}
if (rc == 0) {
printf(".");
}
if (fdset[0].revents & POLLIN) {
len = read(fdset[0].fd, buf, MAX_BUF);
printf("\npoll() GPIO %d interrupt occurred\n", gpio);
}
// ****Commented block****
//if (fdset[0].revents & POLLIN) {
// (void)read(fdset[0].fd, buf, 1);
// printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
//}
fflush(stdout);
}
gpio_fd_close(gpio_fd);
return 0;
}
Running Angstrom on Beaglebone black.
https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
If the pin can be configured as interrupt-generating interrupt
and if it has been configured to generate interrupts (see the
description of "edge"), you can poll(2) on that file and
poll(2) will return whenever the interrupt was triggered. If
you use poll(2), set the events POLLPRI and POLLERR. If you
use select(2), set the file descriptor in exceptfds. After
poll(2) returns, either lseek(2) to the beginning of the sysfs
file and read the new value or close the file and re-open it
to read the value.
You have not set events POLLPRI and POLLERR.
struct pollfd fdset[1];
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = fd;
fdset[0].events = POLLPRI | POLLERR;
...
poll()
...
lseek(fdset[0].fd, 0, SEEK_SET);
const ssize_t rc = read(fdset[0].fd, buf, MAX_BUF);
The above works on a BeagleBone Black Rev. C running Debian with linux 3.8.13-bone47.
Since you "havent connected that pin to anything", if it isn't internally tied low or high then it's just a floating input, which could cause the apparent interrupts you're seeing.

Resources