use uart driver from linux kernel - linux-kernel

There is an external device (sensor keyboard) connected to processor thrue uart port (tx rx) and gpio interrupt line. Need to write driver for this keyboard (not standart own protocol, linux kernel 4.1).
I writed module whith a line discipline and requested irq on open() function (when open from user space /dev/ttymxc3). It's work, but line discipline structure has no released callbacks for suspend and resume functions.
It's need to release sleep keyboard when system is sleeping.
I try to write tty driver that use uart driver, but don't know how.
How to communicate from kernel module with external devices thrue uart port?
Thanks.

You can use uart device in kernel space
// call userspace
{
mm_segment_t fs;
fs=get_fs();
set_fs(get_ds());//KERNEL DS
handle = sys_open(UTS_UART_DEV_NAME, O_RDWR | O_NOCTTY | O_NONBLOCK, 0);
if( handle < 0 )
{
printk(KERN_INFO "UTS Port Open Fail [%s] \n ", UTS_UART_DEV_NAME);
return -1;
}
set_fs(fs);
}
// call userspace

Related

wake up k70 from VLPS deep sleep by GPIO interrupt

I can not wake up k70 (Kinetis) from VLPS deep sleep by GPIO interrupt.
This is under uCLinux, where I enabled CONFIG_PM. After that, I can put K70 to deep sleep by "echo mem > /sys/power/state" and wake it up from UART debug console. But I can not wake up by triggering GPIO interrupt. I have confirmed that the interrupt works before and after the sleep by printing from the interrupt handler and I have also confirmed the GPIO pin value changes from 0 to 1 during sleep after I triggered the GPIO interrupt.
According to the K70 manual, I should be able to wake up VLPS by a GPIO interrupt. Does any have any insight why I could not?
Thanks
First of all, your GPIO driver should implement IRQ chip. (From the above description I have no clue what is the platform and what is the GPIO driver is used there).
Second, the IRQ chip implementation has to have ->irq_set_wake() callback to be present and properly implemented.
Third, the caller, which does get GPIO line via gpiod_get() has to perform:
struct gpio_desc *gd;
int irq;
gd = gpiod_get(...);
if (IS_ERR(gd))
return PTR_ERR(gd);
irq = gpiod_to_irq(gd);
if (irq < 0)
return irq;
/* Now! */
enable_irq_wake(irq); /* This does the trick */

Handle GPIO in Kernel and User Space ARM9 Embedded Linux AM1808

I have to handle (i.e. turn on and off) my LCD Power Pin kernel and userspace both side.
We have configured the gpio pin in Mux.h,da850.c and board-da850-evm.c properly.
The problem is that when we configure this pin in kernel then this pin is not access by /sys/class/gpio.
We have configured this in in board-da850-evm.c as below,
ret = gpio_request(DA850_LCD_GP3, "LCD GP3");
if (ret)
pr_warning("Cannot open GPIO %d\n", DA850_LCD_GP3);
gpio_direction_output(DA850_LCD_GP3, 1);
gpio_set_value(DA850_LCD_GP3,1);
If we comment this section.and export from userspace then we used this pin form userspace successfully.
Is it possible to handle gpio form kernel and userspace?
Or do we need to write the gpio drive ?

Detect USB Connection Event on STM32

I'm currently working with a USB-enabled low power device that I'm having a bit of trouble with. During normal operation, the system clock is set to a significantly slower speed (since this is a data logger only active once every few minutes, this isn't a problem). However, when the device is then plugged into a USB port on a computer, it needs to recognize this, initialize the USB stack (which I can do), and reset the system clock to full speed (I can do this, as well).
My problem, as you might have noticed, is the "USB Connected" event. I'm looking through the STM32 evaluation materials and they have in the IRQn table a "USB_FS_WKUP_IRQn", and the STM32 eval board also has USB-5V power routed to pin PE6, which can also act as WKUP3.
Do I need to enable an external interrupt for that pin, or is there a better way to detect such an event and set/reset the clocks as needed?
Thanks in advance.
Basing on the interrupt name you mentioned I found this implementation:
// Enable the USB Wake-up interrupt
NVICInit.NVIC_IRQChannel = USB_FS_WKUP_IRQn;
NVICInit.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&NVICInit);
It seems you don't need much more. The implementation can differ from the STM32 family you use.
I use the stm32l4
I set up an interrupt on the Vbus pin.
While not in USB mode, configure the pin as a pull-down (so it isn't floating).
Your pin and interrupt line would be different, but
//Configure the pin
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PA9 */
GPIO_InitStruct.Pin = VBUS_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(VBUS_GPIO_Port, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
//Configure the interrupt
EXTI_ConfigTypeDef exti_conf;
exti_conf.Line = EXTI_LINE_9;
exti_conf.GPIOSel = EXTI_GPIOA;
exti_conf.Mode = EXTI_MODE_INTERRUPT;
exti_conf.Trigger = EXTI_TRIGGER_RISING;
HAL_EXTI_SetConfigLine(&hexti_vbus, &exti_conf);
And make sure you have an interrupt handler taken care of. Set a flag for going to USB in the interrupt handler. And you should be set.

PCIe Interrupt number

I am trying to write a Kernel Module that I can use to service PCIe MSI interrupts. Right now I am having trouble trying to configure my interrupts and am trying to follow along with "Linux Device Drivers Ed. 3" The book states:
"The driver doesn't need to bother checking the interrupt number, because the value found in PCI_INTERRUPT_LINE is guaranteed to be the right one."
So of course this seems to be the logical way to setup my interrupts:
err = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &myirq);
if(err)
{
printk(KERN_WARNING "Could not get IRQ number\n");
return err;
}
err = request_irq(myirq, fpga_isr, IRQF_SHARED, fpga_driver.name, dev);
Now this registers me for interrupt 60. I then go about using jTag to manually trigger an interrupt and I get a Kernel message saying that the interrupt does not have a handler attatched to it (interrupt 576). If I hardcode irq_line to 576 I then fail the request_irq.
What is the best way to find out my interrupt line? and why can I not get the IRQ that I need?
One more thing, during boot, my device is automatically set to IRQ pin 1 (Legacy interrupt A) which correseponds to irq line 572 which is also the value stored in dev->irq. If the boot sequence automatically set the IRQ to pin 0 (Legacy interrupts disabled) would dev->irq point to my MSI interrupt # 576?
For MSI, you need to enable the MSI interrupt on your device first with pci_enable_msi. The MSI interrupt is not the same as the "standard PCI" interrupt. After calling pci_enable_msi, the interrupt number should be gotten from pci_dev->irq for calling request_irq. Look for an example in the kernel source tree.
More info in Documentation/PCI/MSI-HOWTO.txt

SetupComm, SetCommState, SetCommTimeouts fail with USB device

i am opening a USB device:
for communication using CreateFile:
HANDLE hUsb = CreateFile("\\.\LCLD9",
GENERIC_READ | GENERIC_WRITE,
0,
null,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
The call succeeds (i.e. hUsb is not equal to INVALID_HANDLE_VALUE). But then it comes time to do what we do with every serial port:
SetupComm (set receive and transit buffer sizes)
SetCommState (set flow-control, baud rate, etc)
SetCommTimeouts (set timeouts)
Each of these calls returns a GetLastError() code of 1. E.g.:
SetupComm(hUsb, 1024, 1024);
Why are operations to configure the serial device failing when using a "USB" serial device, but work when using a "virtual COM port"? Do USB devices not support such baud rates, buffers, flow control, and timeouts?
If this is a limitation/feature of Universal Serial devices, how can i detect that a handle refers to a "Universal Serial Device", rather than a "COMM Port"? For example, the user is the one who specifies which port to use:
\.\COM5
\.\LCLD9
Other serial functions that fail when talking to Universal Serial Bus serial device:
GetCommModemStatus (with error code 1)
ReadFile (with error code 6)
PurgeComm (with error code 6)
WriteFile (with error code 6)
Which begs the larger question, how do you communicate with a USB device once it's been opened with CreateFile?
No, USB devices do not use these things. If your device is an actual USB-to-RS232 (or other slow serial), then you should be opening the COM port it associated with. Let the drivers handle the work of sending that data.
USB communication is not like COM ports. You can think of it more as an external PCI bus than a simple send-whatever-data-you-want line.
Turns out that i don't have to do anything with Comm, because it's not a COM port. The reason my WriteFile was failing was because i was attempting to write to \\.\LCLD9 rather than \\.\LCLD9\.
The trailing backslash is critical; even though CreateFile returns success both ways.
void WriteToDisplay(String s)
{
//Open the display
var hLineDisplay = CreateFile("\\.\LCLD9\", GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
//Write the command
DWORD bytesWritten;
WriteFile(hLineDisplay, s, s.Length, ref bytesWritten, nil);
FileClose(hLineDisplay);
}
Anyone using Logic Controls LD9000 USB Line Display, the above is how you write to the display.
After reverse engineering their .NET Line Display driver i will also mention that the name of the port you use, e.g.:
\\.\LCLD9\
\\.\LCPD6\
\\.\LCPD3\
can be inferred from the full devicePath returned using the Windows Setup APIs. For example, my pole display's full device path is:
\\?\USB#VID_0FA8&PID_A090#6&DF2EE03&0&1#{A5DCBF10-6530-11D2-901F-00C04FB951ED}
\______/
|
ProductID
The rule is to check the device path for Product IDs. In my case PID_A090 means it will be available as file \\.\LCLD9\. Other product IDs and their associated file paths:
Contains DeviceName (trailing backslash is not optional)
======== ===============================================
PID_A030 \\.\LCPD3\
PID_A060 \\.\LCPD6\
PID_A090 \\.\LCLD9\
Note: Any code is released into the public domain. No attribution required.

Resources