How to access GPIO from kernel space? (zynq-microzed board) - linux-kernel

I am using zynq-microzed board and I want to access GPIO with kernel space.
Can anyone please tell me how can i attempt doing this?

*NOTE: This is from the Zynq-7000. I believe it's largely the same.
Assuming you're using a devicetree, this is an example entry (in the devicetree):
gpio-device {
compatible = "gpio-control";
gpios = <&gpio0 54 0>; //(Add 32 to get the actual pin number. This is GPIO 86)
};
And you need to state in the driver that you're compatible with the devicetree entry (look at other drivers to see where to put this line):
.compatible = "gpio-control"
In your driver, include #include <linux/gpio.h> and read the pin from the devicetree:
struct device_node *np = pdev->dev.of_node;
int pin;
pin = of_get_gpio(np, 0);
if (pin < 0) {
pr_err("failed to get GPIO from device tree\n");
return -1;
}
Request the use of the GPIO:
int ret = gpio_request(pin, "Some name"); //Name it whatever you want
And set it's direction:
int ret = gpio_direction_output(pin, 0); //The second parameter is the initial value. 0 is low, 1 is high.
Afterwards, set the value like so:
gpio_set_value(pin, 1);
For input:
ret = gpio_direction_input(pin);
value = gpio_get_value(pin);
Free the GPIO when you're finished with it (including on error!):
gpio_free(pin);
At the end of the day, a good method is to grep around the kernel to find drivers that do what you want. In fact grep -r gpio <<kernel_source>> will tell you everything in this answer and more.

Check the following link: enter link description here
Summarizing:
There is an include file for working with GPIOs:
#include <linux/gpio.h>
GPIOs must be allocated before use:
int gpio_request(unsigned int gpio, const char *label);
And GPIO can be returned to the system with:
void gpio_free(unsigned int gpio);
Configure GPIO as Input/Output:
int gpio_direction_input(unsigned int gpio);
int gpio_direction_output(unsigned int gpio, int value);
Operations:
int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value);
Regards.

Related

Why does the `bool` data type render my data structure unreadable to avr-gdb?

I have a data structure that looks like this:
#include <stdbool.h>
.
.
.
typedef struct Input {
uint8_t pin; /**< Pin associated with this input */
bool state, /**< Current pin state */
last_state; /**< Pin state last time we checked */
} Input;
I initialize the data structure like this:
Input *input = (Input *)malloc(sizeof(Input));
input->pin = 0;
input->state = false;
input->last_state = false;
I am compiling the code with avr-gcc 7.2.0 and running the code using simulavr ("SimularAVR 1.2dev") and attaching to it using avr-gdb.
When I print out the data structure in gdb just after initialization I see this:
(gdb) p *input
$1 = {pin = 0 '\000', state = false}
Note that the last_state member isn't showing up. Futhermore, if I set either one of the existing members, it appears that they are actually referring to the same location:
(gdb) set input->pin=123
(gdb) p *input
$8 = {pin = 123 '{', state = 123}
If I change the data type of state and last_state from bool to, say, uint8_t, like this...
typedef struct Input {
uint8_t pin; /**< Pin associated with this input */
uint8_t state, /**< Current pin state */
last_state; /**< Pin state last time we checked */
} Input;
...then everything displays correctly:
(gdb) p *input
$1 = {pin = 0 '\000', state = 0 '\000', last_state = 0 '\000'}
What's going on here? Is this a bug in gdb? In simulavr? Something else? Note that the code itself runs correctly when deployed on the target microcontroller (an attiny85); this is entirely a debugging/simulation issue.
Is this a bug in gdb?
It is definitely a bug in either gdb or avr-gcc -- either the debug info is incorrect (bug in gcc) or GDB is not interpreting it correctly (bug in GDB).
The simulavr has nothing to do with this.
To find out more, readelf -wi a.out and compare the description of struct Input in the working and non-working case. They should only differ in the type of state and last_state fields. If that's what you in fact observe, GDB bug is most likely.

AVR Atmega32a USART library isn't working

/*
RC_Car_AVR.c
Created: 4/18/2018 7:55:07 PM
Author :
*/
#define F_CPU 16000000
#define BAUD 9600
#define TUBRR (((F_CPU / 16) / BAUD) - 1)
#include <avr/io.h>
#include <util/delay.h>
char Read;
void USART_Init(void){
UBRRL = TUBRR;
UCSRB = (1<<TXEN)|(1<<RXEN);
UCSRC = (1<<UCSZ1)|(1<<UCSZ0);
}
char USART_Receive(void){
/* Wait for data to be received */
while (!(UCSRA & (1<<RXC)));
/* Get and return received data from buffer */
return UDR;
}
int main(void){
USART_Init();
DDRB |= (1<<0);
PORTB |= (1<<0);
while (1){
Read = USART_Receive();
if(Read == 'F'){
PORTB ^= (1<<0);
_delay_ms(100);
}
}
}
I'm trying to toggle an LED when I receive a certain character through the Bluetooth module (HC05).
I've written the USART library just like the datasheet but it doesn't seem to work (I'm only concerned with the initialization and receiving code since I'm working on a half duplex system so i don't need the transmition part).
I'm using Atmega32a with a 16MHz external crystal Oscillator.
Please tell me if you find anything wrong.
Thanks in advance.
Your Initialization is wrong.
Try this
void USART_Init(void){
UBRRL = TUBRR;
UBRRH = TUBRR >> 8;
UCSRB = (1<<TXEN)|(1<<RXEN);
UCSRC = (1<<UCSZ1)|(3<<UCSZ0);
}
This is the following initialization code provided in data sheet of atmega32
void USART_Init( unsigned int baud )
{
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}
I know following datasheet is little overhead in beginning But eventually you will see all your answers are provided there.

setting an i2c register to high

I have this project that my boss asked me to do and the first step is to figure out how to set a given I2C register to high or low using the silicon lab library, if anyone knows any good sources for this type of problem please provide them thank you. The pic that I am using is the pic16f1823, I've already looked at the documentation of the pic but into only states how to read and write to an I2c.
I use this as a header file and seems to work well for PIC16F1827 which is basically the same as the 1823. It used the peripheral of the PIC. Just include in in any c file you want to use i2c in. Make sure you #define FOSC in order to calculate the correct baud rate. Also double check the port and tris assignments are correct for your device and make adjustments.
It uses polling instead of an interrupt. Uncomment the interrupt setup code and write an interrupt service routine to catch the interrupts.
#ifndef I2C_H
#define I2C_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Hi-Tech C I2C library for 12F1822
* Master mode routines for I2C MSSP port to read and write to slave device
* Copyright (C)2011 HobbyTronics.co.uk 2011
* Freely distributable.
*/
#define I2C_WRITE 0
#define I2C_READ 1
// Initialise MSSP port. (12F1822 - other devices may differ)
void i2c_Init(void){
// Initialise I2C MSSP
// Master 100KHz
TRISB2 = 1;
TRISB5 = 1;
SSP1CON1 = 0b00101000; // I2C Master mode
SSP1CON2 = 0b00000000;
SSP1CON3 = 0b00000000;
//SSP1MSK = 0b00000000;
SSP1ADD = I2C_BRG; // clock = FOSC/(4 * (SSPxADD+1))
//SSP1IE = 1; // enable interrupt
SSP1STAT = 0b10000000;
}
// i2c_Wait - wait for I2C transfer to finish
void i2c_Wait(void){
while ( ( SSP1CON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
}
// i2c_Start - Start I2C communication
void i2c_Start(void)
{
i2c_Wait();
SSP1CON2bits.SEN=1;
}
// i2c_Restart - Re-Start I2C communication
void i2c_Restart(void){
i2c_Wait();
SSP1CON2bits.RSEN=1;
}
// i2c_Stop - Stop I2C communication
void i2c_Stop(void)
{
i2c_Wait();
SSP1CON2bits.PEN=1;
}
// i2c_Write - Sends one byte of data
void i2c_Write(unsigned char data)
{
i2c_Wait();
SSPBUF = data;
}
// i2c_Address - Sends Slave Address and Read/Write mode
// mode is either I2C_WRITE or I2C_READ
void i2c_Address(unsigned char address, unsigned char mode)
{
unsigned char l_address;
l_address=address<<1;
l_address+=mode;
i2c_Wait();
SSPBUF = l_address;
}
// i2c_Read - Reads a byte from Slave device
unsigned char i2c_Read(unsigned char ack)
{
// Read data from slave
// ack should be 1 if there is going to be more data read
// ack should be 0 if this is the last byte of data read
unsigned char i2cReadData;
i2c_Wait();
SSP1CON2bits.RCEN=1;
i2c_Wait();
i2cReadData = SSPBUF;
i2c_Wait();
if ( ack ) SSP1CON2bits.ACKDT=0; // Ack
else SSP1CON2bits.ACKDT=1; // NAck
SSP1CON2bits.ACKEN=1; // send acknowledge sequence
return( i2cReadData );
}
#ifdef __cplusplus
}
#endif
#endif /* I2C_H */
Then you can use the higher level functions defined above to control a device, which is described in the datasheet of the slave device.
For example, to read from an eeprom:
#include <xc.h>
#define FOSC 16000000
#include "i2c.h"
unsigned char i2c_read_eeprom( unsigned char slaveaddress, unsigned char memaddress )
{
unsigned char data;
data = 123;
i2c_Start();
i2c_Address( slaveaddress, I2C_WRITE);
i2c_Write(memaddress);
if( SSP1CON2bits.ACKSTAT )
txstring("ACK!\r\n");
else txstring("nACK!\r\n");
i2c_Start();
i2c_Address( slaveaddress, I2C_READ);
data = i2c_Read(0);
i2c_Stop();
return data;
}

Getting process base address in Mac OSX

I'm trying to read the memory of a process using task_for_pid / vm_read.
uint32_t sz;
pointer_t buf;
task_t task;
pid_t pid = 9484;
kern_return_t error = task_for_pid(current_task(), pid, &task);
vm_read(task, 0x10e448000, 2048, &buf, &sz);
In this case I read the first 2048 bytes.
This works when I know the base address of the process (which I can find out using gdb "info shared" - in this case 0x10e448000), but how do I find out the base address at runtime (without looking at it with gdb)?
Answering my own question. I was able to get the base address using mach_vm_region_recurse like below. The offset lands in vmoffset. If there is another way that is more "right" - don't hesitate to comment!
#include <stdio.h>
#include <mach/mach_init.h>
#include <sys/sysctl.h>
#include <mach/mach_vm.h>
...
mach_port_name_t task;
vm_map_offset_t vmoffset;
vm_map_size_t vmsize;
uint32_t nesting_depth = 0;
struct vm_region_submap_info_64 vbr;
mach_msg_type_number_t vbrcount = 16;
kern_return_t kr;
if ((kr = mach_vm_region_recurse(task, &vmoffset, &vmsize,
&nesting_depth,
(vm_region_recurse_info_t)&vbr,
&vbrcount)) != KERN_SUCCESS)
{
printf("FAIL");
}
Since you're calling current_task(), I assume you're aiming at your own process at runtime. So the base address you mentioned should be the dynamic base address, i.e. static base address + image slide caused by ASLR, right? Based on this assumption, you can use "Section and Segment Accessors" to get the static base address of your process, and then use the dyld functions to get the image slide. Here's a snippet:
#import <Foundation/Foundation.h>
#include </usr/include/mach-o/getsect.h>
#include <stdio.h>
#include </usr/include/mach-o/dyld.h>
#include <string.h>
uint64_t StaticBaseAddress(void)
{
const struct segment_command_64* command = getsegbyname("__TEXT");
uint64_t addr = command->vmaddr;
return addr;
}
intptr_t ImageSlide(void)
{
char path[1024];
uint32_t size = sizeof(path);
if (_NSGetExecutablePath(path, &size) != 0) return -1;
for (uint32_t i = 0; i < _dyld_image_count(); i++)
{
if (strcmp(_dyld_get_image_name(i), path) == 0)
return _dyld_get_image_vmaddr_slide(i);
}
return 0;
}
uint64_t DynamicBaseAddress(void)
{
return StaticBaseAddress() + ImageSlide();
}
int main (int argc, const char *argv[])
{
printf("dynamic base address (%0llx) = static base address (%0llx) + image slide (%0lx)\n", DynamicBaseAddress(), StaticBaseAddress(), ImageSlide());
while (1) {}; // you can attach to this process via gdb/lldb to view the base address now :)
return 0;
}
Hope it helps!

how to use CryptoAPI in the linux kernel 2.6

I have been looking for some time but have not found anywhere near sufficient documentation / examples on how to use the CryptoAPI that comes with linux in the creation of syscalls / in kernel land.
If anyone knows of a good source please let me know, I would like to know how to do SHA1 / MD5 and Blowfish / AES within the kernel space only.
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#define SHA1_LENGTH 20
static int __init sha1_init(void)
{
struct scatterlist sg;
struct crypto_hash *tfm;
struct hash_desc desc;
unsigned char output[SHA1_LENGTH];
unsigned char buf[10];
int i;
printk(KERN_INFO "sha1: %s\n", __FUNCTION__);
memset(buf, 'A', 10);
memset(output, 0x00, SHA1_LENGTH);
tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
desc.tfm = tfm;
desc.flags = 0;
sg_init_one(&sg, buf, 10);
crypto_hash_init(&desc);
crypto_hash_update(&desc, &sg, 10);
crypto_hash_final(&desc, output);
for (i = 0; i < 20; i++) {
printk(KERN_ERR "%d-%d\n", output[i], i);
}
crypto_free_hash(tfm);
return 0;
}
static void __exit sha1_exit(void)
{
printk(KERN_INFO "sha1: %s\n", __FUNCTION__);
}
module_init(sha1_init);
module_exit(sha1_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Me");
There are a couple of places in the kernel which use the crypto module: the eCryptfs file system (linux/fs/ecryptfs/) and the 802.11 wireless stack (linux/drivers/staging/rtl8187se/ieee80211/). Both of these use AES, but you may be able to extrapolate what you find there to MD5.
Another good example is from the 2.6.18 kernel source in security/seclvl.c
Note: You can change CRYPTO_TFM_REQ_MAY_SLEEP if needed
static int
plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
{
struct crypto_tfm *tfm;
struct scatterlist sg;
if (len > PAGE_SIZE) {
seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
"characters). Largest possible is %lu "
"bytes.\n", len, PAGE_SIZE);
return -EINVAL;
}
tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
if (tfm == NULL) {
seclvl_printk(0, KERN_ERR,
"Failed to load transform for SHA1\n");
return -EINVAL;
}
sg_init_one(&sg, (u8 *)plaintext, len);
crypto_digest_init(tfm);
crypto_digest_update(tfm, &sg, 1);
crypto_digest_final(tfm, hash);
crypto_free_tfm(tfm);
return 0;
}
Cryptodev-linux
https://github.com/cryptodev-linux/cryptodev-linux
It is a kernel module that exposes the kernel crypto API to userspace through /dev/crypto .
SHA calculation example: https://github.com/cryptodev-linux/cryptodev-linux/blob/da730106c2558c8e0c8e1b1b1812d32ef9574ab7/examples/sha.c
As others have mentioned, the kernel does not seem to expose the crypto API to userspace itself, which is a shame since the kernel can already use native hardware accelerated crypto functions internally.
Crypto operations cryptodev supports: https://github.com/nmav/cryptodev-linux/blob/383922cabeea7dca354415e8c590f8e932f4d7a8/crypto/cryptodev.h
Crypto operations Linux x86 supports: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/x86/crypto?id=refs/tags/v4.0
The best place to start is Documentation/crytpo in the kernel sources. dm-crypt is one of the many components that probably uses the kernel crypto API and you can refer to it to get an idea about usage.
how to do SHA1 / MD5 and Blowfish / AES within the kernel space only.
Example of hashing data using a two-element scatterlist:
struct crypto_hash *tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
if (tfm == NULL)
fail;
char *output_buf = kmalloc(crypto_hash_digestsize(tfm), GFP_KERNEL);
if (output_buf == NULL)
fail;
struct scatterlist sg[2];
struct hash_desc desc = {.tfm = tfm};
ret = crypto_hash_init(&desc);
if (ret != 0)
fail;
sg_init_table(sg, ARRAY_SIZE(sg));
sg_set_buf(&sg[0], "Hello", 5);
sg_set_buf(&sg[1], " World", 6);
ret = crypto_hash_digest(&desc, sg, 11, output_buf);
if (ret != 0)
fail;
One critical note:
Never compare the return value of crypto_alloc_hash function to NULL for detecting the failure.
Steps:
Always use IS_ERR function for this purpose. Comparing to NULL does not capture the error, hence you get segmentation faults later on.
If IS_ERR returns fail, you possibly have a missing crypto algorithm compiled into your kernel image (or as a module). Make sure you have selected the appropriate crypto algo. form make menuconfig.

Resources