I am novice to Linux device driver and writing driver module for TI-ADS1292R chip. This driver is loading without any error, creates character device entry in /dev directory. I am also able to transfer data on SPI bus (verified it on logic analyzer and DSO).
There are two problems here.
(1) in logic analyzer it shows that chip is responding with correct chip id (0x73) on read id command, but in my driver I am getting incorrect value (0x80). Why this is happening and where the problem is?
(2) As far as I understood, my driver should automatically loaded if I have configured it through defconfig file, which is not happening in my case. Right now, I am loading it as a built-in module with obj-y option.
My code has following snippets through which I am trying to read the chip id.
static int ads_send_byte(struct ads1292_chip *dev, int data)
{
int status;
struct spi_message msg = { };
struct spi_transfer transfer = { };
dev->tx_buff[0] = data;
transfer.tx_buf = dev->tx_buff;
transfer.rx_buf = dev->rx_buff;
transfer.len = 1;
transfer.speed_hz = SPI_BUS_SPEED;
spi_message_init(&msg);
spi_message_add_tail(&transfer, &msg);
status = spi_sync(dev->spi, &msg);
printk(KERN_DEBUG "ecg: %s (%#x) %d\n", __func__, data, status);
return status;
};
static int ads_send_RREG(struct ads1292_chip *dev, char __user * buf, u8 reg, u8 size)
{
struct spi_message msg = { };
struct spi_transfer transfer = { };
int ret;
dev->tx_buff[0] = ADS1292_RREG | reg;
dev->tx_buff[1] = size - 1; // datasheet: no of regs - 1
memset(dev->rx_buff, 0, size);
memset(dev->tx_buff + 2, 0, size);
transfer.speed_hz = SPI_BUS_SPEED;
transfer.tx_buf = dev->tx_buff;
transfer.rx_buf = dev->rx_buff;
transfer.len = size + 2; // 2 is for command tx
transfer.delay_usecs = 40; // datasheet: 4 clocks after each message
transfer.cs_change = 1; // Always toggle CS line after transfer
spi_message_init(&msg);
spi_message_add_tail(&transfer, &msg);
ret = spi_sync(dev->spi, &msg);
//printk(KERN_DEBUG "ecg: %s %x\n", __func__, dev->rx_buff[0]);
if (unlikely(ret))
return ret;
ret = copy_to_user(buf, dev->rx_buff, size);
return ret;
}
static int ads_cdev_open(struct inode *inode, struct file *filp)
{
struct ads1292_dev *ads = container_of(inode->i_cdev, struct ads1292_dev, dev);
char buff[1];
printk(KERN_DEBUG "ecg: %s\n", __func__);
filp->private_data = ads;
gpio_set_value_cansleep(ads1292_gpio_start.gpio, 0);
ads_send_byte(&ads->chip, ADS1292_RESET);
mdelay(1);
ads_send_byte(&ads->chip, ADS1292_SDATAC);
mdelay(10);
ads_send_RREG(&ads->chip, buff, ADS1292_ID, 1);
printk(KERN_DEBUG "ecg: ID - %x\n", buff[0]);
return 0;
}
Related
Summarize the Problem:
I wrote a userspace SPI driver in linux for the NRF24L01+ transceiver. My goal is to send files to a server. A jetson nano is the sender, and a raspberry pi 3b+ the receiver. Both the spi and nano are running Linux.
I can consistently send packets and receive acknowledgements.
However, the issue is whenever I send a packet such as 0x ff ee dd 00 cc bb aa the receiver only receives the packet 0x ff ee dd 00 00 00 00. So what is happening is that whenever the first byte encountered is zero, the rest of the packet becomes zero. This causes the files I send to become corrupted.
I was able to reproduce this bug with a char array having a similar pattern. I noticed this trend when I printed out the file contents I was sending on the transmitter and receiver.
What I've tried:
I've tried altering my SPI read function. What I thought was happening was the chip select line was being flipped high early. This did not work, I got the same results.
I've printed the packets before calling the ioctl() function from the transmitter and the packet remains intact.
I've printed the return value of the ioctl() function to see how many bytes I was receiving and sending. I was sending 31 bytes from the transmitter, and receiving 32 bytes from the receiver. So it doesn't look like my reads and sends are failing.
If I had a logic analyzer my next step would be to check the SPI pins on the transmitter, but unfortunately I don't have one.
I've added a 10uF decoupling capacitor on the transceivers and that sped up communication.
Show Some Code:
Receiver side:
/**
* Reads the payload when data pipe
* is available.
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_rx_read(int spi_dev_fd, char * payload, int * pipe, int * bytes)
{
int pipe_temp, rtn;
// TODO: Add timeout.
do
{
rtn = nrf_rx_pipe_available(spi_dev_fd, &pipe_temp);
}while(rtn != 0);
if(rtn == 0)
{
char status;
if(bytes != NULL)
{
char size;
spi_read_msg(spi_dev_fd, R_RX_PL_WID, &status, &size, 1);
*bytes = (int) size;
}
spi_read_msg(spi_dev_fd, R_RX_PAYLOAD , &status, payload, (int) NUM_PAYLOAD_BYTES);
*pipe = pipe_temp;
char msg;
msg = RX_DR;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &msg, 1);
return 0;
}
return 1;
}
bool nrf_rx_pipe_available(int spi_dev_fd, int * pipe)
{
char addr = NOP;
char status;
spi_read_msg(spi_dev_fd, addr, &status, NULL, 0);
if((status & RX_DR) > 0)
{
*pipe = (status >> RX_P_NO) & 0x07;
if(*pipe > 5)
{
return 1;
}
return 0;
}
return 1;
}
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
string temp = string(recv_buffer);
temp = temp.substr(1);
strncpy(copy_to, temp.c_str(), len);
}
// debug code
for(int i = 0; i < len; ++i)
{
printf("copy_to: %x \n ", copy_to[i]);
}
// end debug code.
}
return res;
}
Transmitter side:
/**
* Function to load a payload and send a packet.
*
*
* spi_dev_fd: file descriptor for spi device.
* */
int nrf_tx_send_packet(int spi_dev_fd, char * payload, int len)
{
int rtn;
// Put low so we can add the payload.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW);
// Set a new payload.
nrf_tx_new_payload(spi_dev_fd, payload, len);
// Start tx transmission.
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_HIGH);
do
{
rtn = nrf_tx_pending_send(spi_dev_fd);
if(rtn == 2)
{
char clr = MAX_RT;
spi_send_msg(spi_dev_fd, W_REGISTER | STATUS, &clr, 1);
}
}while(rtn != 1);
// Go back to standby mode
gpio_set_value((unsigned int) GPIO_CE, (unsigned int) GPIO_LVL_LOW); // Setting chip enable to 0.
char reg = W_REGISTER | STATUS;
char val = RX_DR | TX_DS | MAX_RT;
spi_send_msg(spi_dev_fd, reg, &val, 1);
return 0;
}
int spi_send_msg(int spi_dev_fd, char addr, char * data, int len)
{
char data_buffer[len + 1];
char recv_buffer;
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer[0] = addr;
for(int i = 1; i < len + 1; ++i)
{
data_buffer[i] = data[i-1];
printf("databuffer[i]: %x \n", data_buffer[i]);
}
xfer.tx_buf = (unsigned long) data_buffer;
xfer.rx_buf = (unsigned long) NULL;
xfer.len = len + 1;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
//xfer.rx_nbits = 8;
xfer.rx_nbits = 0;
xfer.tx_nbits = (8 * len) + 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
printf("res: %i \n", res);
return res;
}
I tried to add all the relevant code, sorry if it is a bit much. Main thing to look at is the send and receive functions. They all work as expected until I encounter the zeroed out byte.
If I am missing any information that can help someone out please let me know and I can add it. I think the send and receive functions are the most important however. I'm able to set and read the registers of the transceiver.
I can send files now!
The fix was done in spi_read_msg() function.
The problem was I was converting the buffer received to a string, which caused the data to be trimmed when the byte 0x00 was encountered. This is also equivalent to the null terminating character.
Receiver code:
int spi_read_msg(int spi_dev_fd, char addr, char * status, char * copy_to, int len)
{
char data_buffer;
char recv_buffer[len + 1];
struct spi_ioc_transfer xfer;
memset(&xfer, 0, sizeof(xfer));
memset(&recv_buffer, 0, sizeof(recv_buffer));
data_buffer = addr;
xfer.tx_buf = (unsigned long) &data_buffer;
xfer.rx_buf = (unsigned long) recv_buffer;
xfer.len = len + 2;
xfer.bits_per_word = 8;
xfer.speed_hz = 1000000;
xfer.cs_change = 0;
xfer.rx_nbits = len * 8;
xfer.tx_nbits = 8;
int res = ioctl(spi_dev_fd, SPI_IOC_MESSAGE(1), xfer);
if(res > 0)
{
status[0] = recv_buffer[0];
if(copy_to != NULL)
{
for(int i = 0; i < len; ++i)
{
copy_to[i] = recv_buffer[i + 1];
}
}
}
return res;
}
I have an issue with this code:
bool send_packet(uint8_t *frame, const uint32_t size)
{
int len, ret;
struct iphdr *ip;
struct msghdr msg;
struct kvec vec;
ip = (struct iphdr*)(frame + ETH_HLEN); // Align ip header with buffer
tgb_pr_debug("packet ip version : %d\n",ip->version);
tgb_pr_debug("packet from %pI4 to %pI4\n",&ip->saddr, &ip->daddr);
tgb_pr_debug("packet ip protocol : %d\n",ip->protocol);
memset(&msg,0,sizeof(msg));
len = size - ETH_HLEN;
vec.iov_base = ip;
vec.iov_len = len;
ret = kernel_sendmsg(sock,&msg,&vec,1,len);
if (ret < 0) {
pr_err("sendmsg return code %d\n",ret);
return false;
}
kfree(frame);
return true;
}
With high rate it's freeze the computer. Is socket right way to send packet in Linux Kernel?
With this implémention i have no issue, it's work perfectly, if someone know why i'm interested
struct sk_buff* skb, *trailer;
struct net_device *dev;
dev = dev_get_by_name(&init_net,"enp0s5");
skb = alloc_skb(size+ETH_HLEN+2,GFP_ATOMIC);
memcpy(skb_put(skb, size), frame, size);
kfree(frame); //free buffer get from ipseclib
skb_reset_network_header(skb);
skb->dev = dev;
skb->pkt_type = PACKET_OUTGOING;
skb_cow_data(skb,1,&trailer);
dev_queue_xmit(skb);
I'm trying to make a LKM netfilter that drops incoming packets if the number of packets arrived exceeds a certain limit.
There are five ports that the packets comes through, and netfiltering is done for each of those ports.
Here's part of my LKM netfilter (it uses procfs to write from user program):
#define MAX_PORT 5
static unsigned short int port[MAX_PORT];
static unsigned long limit;
static char char_limit[256];
static unsigned long data_count[MAX_PORT];
bool check_port(unsigned short int);
static unsigned int my_hook_fn( void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct iphdr *ip = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
unsigned int source, dest;
if(!skb) return NF_ACCEPT;
if(ip->protocol==IPPROTO_TCP)
{
source = htons((unsigned short int) th->source);
dest = htons((unsigned short int) th->dest);
printk(KERN_ALERT "source: %u, destination: %u\n", source, dest);
if(!check_port(source))
{
printk(KERN_ALERT "packet dropped!\n");
return NF_DROP;
}
}
return NF_ACCEPT;
}
bool check_port(unsigned short int source)
{
int i = 0;
bool found = false;
while(!found && i < MAX_PORT)
{
if(port[i] == source)
found = true;
else if(port[i] == 0)
{
port[i] = source;
found = true;
}
i++;
}
i--;
data_count[i]++;
if(data_count[i] >= limit)
{
data_count[i] = limit;
printk(KERN_ALERT "port %hu has reached the limit!\n", port[i]);
return false;
}
return true;
}
static struct nf_hook_ops my_nf_ops = {
.hook = my_hook_fn,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
};
In my hook function, the NF_DROP seems to be correctly returned.
However, the result in my user space program shows that it's not.
Next is my user space program; this produces results in txt files.
void *thread_recv(void *arg);
#define MAX_CON 5
#define BUF_SIZE 200
int port[MAX_CON];
char ip[20];
int sock[MAX_CON];
void error_handling(char *msg);
void main(){
int i;
unsigned long limit;
char char_limit[256];
FILE *fp;
printf("packet limit : ");
scanf("%lu", &limit);
sprintf(char_limit, "%lu", limit);
fp = fopen("/proc/myproc/myproc", "w");
if(fp == NULL)
printf("unable to open myproc\n");
else
fprintf(fp, "%s", char_limit);
fclose(fp);
struct sockaddr_in serv_adr;
pthread_t thread_id[MAX_CON];
printf("ip :\n");
scanf("%s",ip);
printf("<port> <port> <port> <port> <port>\n");
scanf("%d %d %d %d %d", &(port[0]), &(port[1]), &(port[2]), &(port[3]), &(port[4]));
printf("%s %d\n", ip, port[0]);
for(i=0;i<5;i++){
sock[i]=socket(PF_INET, SOCK_STREAM, 0);
if(sock[i]==-1)
error_handling("socket() error");
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(ip);
serv_adr.sin_port=htons(port[i]);
if(connect(sock[i], (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("connect() error");
else
printf("port %d connected\n", port[i]);
pthread_create(&(thread_id[i]),NULL, thread_recv,(void*)&(sock[i]));
}
while(1); // do infinitely, so user should end by their own. Ctrl + C
}
void *thread_recv(void *arg){
int clnt_sock= *(int*)arg; // get socketnumber from main
int str_len=0, i; // recv byte length
int tport=0; // portnumber matching socketnumber
char msg[BUF_SIZE];
time_t timer;
struct tm *t;
struct timespec spec;
unsigned long ms;
FILE *fp;
char filename[20]={NULL};
for(i=0;i<5;i++)
if(sock[i]==clnt_sock)
tport=port[i];
sprintf(filename,"%d.txt",tport);
fp=fopen(filename,"w+");
printf("%d port thread run\n", tport);
while((str_len=read(clnt_sock, msg, sizeof(msg)))){
msg[str_len]=NULL;
timer= time(NULL);
t= localtime(&timer);
clock_gettime(CLOCK_REALTIME, &spec);
ms = round(spec.tv_nsec / 1.0e6);
fprintf(fp,"%d:%d:%d.%lu %d %s\n",t->tm_hour,t->tm_min,t->tm_sec,ms,str_len,msg);
}
fclose(fp);
}
void error_handling(char *msg){
fputs(msg, stderr);
fputc('\n', stderr);
exit(1);
}
Within the thread_recv function, a txt file is created with its name as the matching port number.
What I was expecting from this was that once packet is dropped, the resulting txt file will stop being updated.
For example, if the limit is 10, then only 10 socket information will be written to the file.
But even when the ports have reached the limit, they keep updating the resulting txt files.
Does that mean that the packets have not been dropped properly?
I have 3 devices which are working in the similar way. I have a driver designed for one of the devices. I have added compatibility with
.compatible = "xyz,hmcSPI-0.00.a"
.compatible = "xyz,hmcSPI-1.00.a" and
.compatible = "xyz,hmcSPI-2.00.a"
It probes only the last device "xyz,hmcSPI-2.00.a" but first and second are seems to be disconnected. Meaning when I send data to the driver in /proc/hmcSPI0 then it reflects on only last device but not on first and second. When I remove third device "xyz,hmcSPI-2.00.a" from the device tree and driver then it detect "xyz,hmcSPI-1.00.a" but not "xyz,hmcSPI-0.00.a". Also, it shows probing physical address of the last device. I want to use this single driver for all three devices which are having different addresses.
Following is my platform driver.
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h> /* Needed for copy_from_user */
#include <asm/io.h> /* Needed for IO Read/Write Functions */
#include <linux/proc_fs.h> /* Needed for Proc File System Functions */
#include <linux/seq_file.h> /* Needed for Sequence File Operations */
#include <linux/platform_device.h> /* Needed for Platform Driver Functions */
#include<linux/slab.h>
/* Define Driver Name */
#define DRIVER_NAME "hmcSPI0"
unsigned long *base_addr; /* Vitual Base Address */
struct resource *res; /* Device Resource Structure */
unsigned long remap_size; /* Device Memory Size */
u16 slave_reg_add=0;
char hmcSPI0_phrase[16];
/* Write operation for /proc/hmcSPI0
* -----------------------------------
* When user cat a string to /proc/hmcSPI0 file, the string will be stored in
* const char __user *buf. This function will copy the string from user
* space into kernel space, and change it to an unsigned long value.
* It will then write the value to the register of hmcSPI0 controller.
*/
static ssize_t proc_hmcSPI0_write(struct file *file, const char __user * buf,
size_t count, loff_t * ppos)
{
u32 hmcSPI0_value;
if (count < 14) {
if (copy_from_user(hmcSPI0_phrase, buf, count))
return -EFAULT;
hmcSPI0_phrase[count] = '\0';
slave_reg_add=hmcSPI0_phrase[2]; //Copy first hex number which is offset to variable
hmcSPI0_phrase[2]=48; //Replace it by zero
if (slave_reg_add>=48){ //48='0' ASCII
slave_reg_add=(slave_reg_add-48); // //Convert the ACSII chr to Decimal Number
if(slave_reg_add<15){
hmcSPI0_value = simple_strtoul(hmcSPI0_phrase, NULL, 0);
wmb();
iowrite32(0x0, (base_addr+2)); //Clear Done slave reg2
iowrite32(hmcSPI0_value, (base_addr+slave_reg_add));
if(slave_reg_add == 0){
if((hmcSPI0_phrase[3]-48)==4)
iowrite32(0x4, (base_addr));
else if ((hmcSPI0_phrase[3]-48)==1 || (hmcSPI0_phrase[3]-48)==3){
while (ioread32((base_addr+2)) == 0);//wait untill transfer of all data
iowrite32(0x0, (base_addr+2));//Clear Done slave reg2
iowrite32(0x0, (base_addr));
}
else{}
}
}else {
slave_reg_add=hmcSPI0_phrase[3];
slave_reg_add=(slave_reg_add-48);
}
}
}
return count;
}
/* Callback function when opening file /proc/hmcSPI0
* ------------------------------------------------------
* Read the register value of hmcSPI0 controller, print the value to
* the sequence file struct seq_file *p. In file open operation for /proc/hmcSPI0
* this callback function will be called first to fill up the seq_file,
* and seq_read function will print whatever in seq_file to the terminal.
*/
static int proc_hmcSPI0_show(struct seq_file *p, void *v)
{
u32 hmcSPI0_value;
slave_reg_add=3;
hmcSPI0_value = ioread32((base_addr+slave_reg_add));
seq_printf(p, "Slave Reg=0x%x , Data=0x%x \n", slave_reg_add,hmcSPI0_value);
return 0;
}
/* Open function for /proc/hmcSPI0
* ------------------------------------
* When user want to read /proc/hmcSPI0 (i.e. cat /proc/hmcSPI0), the open function
* will be called first. In the open function, a seq_file will be prepared and the modprobe chdir no such file or directory zynq
* status of hmcSPI0 will be filled into the seq_file by proc_hmcSPI0_show function.
*/
static int proc_hmcSPI0_open(struct inode *inode, struct file *file)
{
unsigned int size = 16;
char *buf;
struct seq_file *m;
int res;
buf = (char *)kmalloc(size * sizeof(char), GFP_KERNEL);
if (!buf)
return -ENOMEM;
res = single_open(file, proc_hmcSPI0_show, NULL);
if (!res) {
m = file->private_data;
m->buf = buf;
m->size = size;
} else {
kfree(buf);
}
return res;
}
/* File Operations for /proc/hmcSPI0 */
static const struct file_operations proc_hmcSPI0_operations = {
.open = proc_hmcSPI0_open,
.read = seq_read,
.write = proc_hmcSPI0_write,
.llseek = seq_lseek,
.release = single_release
};
/* Shutdown function for hmcSPI0
* -----------------------------------
* Before hmcSPI0 shutdown, clear the data
*/
static void hmcSPI0_shutdown(struct platform_device *pdev)
{
iowrite32(0, base_addr);
}
/* Remove function for hmcSPI0
* ----------------------------------
* When hmcSPI0 module is removed, clear all data first,
* release virtual address and the memory region requested.
*/
static int hmcSPI0_remove(struct platform_device *pdev)
{
hmcSPI0_shutdown(pdev);
/* Remove /proc/hmcSPI0 entry */
remove_proc_entry(DRIVER_NAME, NULL);
/* Release mapped virtual address */
iounmap(base_addr);
/* Release the region */
release_mem_region(res->start, remap_size);
return 0;
}
/* Device Probe function for hmcSPI0
* ------------------------------------
* Get the resource structure from the information in device tree.
* request the memory regioon needed for the controller, and map it into
* kernel virtual memory space. Create an entry under /proc file system
* and register file operations for that entry.
*/
static int hmcSPI0_probe(struct platform_device *pdev)
{
struct proc_dir_entry *hmcSPI0_proc_entry;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "No memory resource\n");
return -ENODEV;
}
remap_size = res->end - res->start + 1;
if (!request_mem_region(res->start, remap_size, pdev->name)) {
dev_err(&pdev->dev, "Cannot request IO\n");
return -ENXIO;
}
base_addr = ioremap(res->start, remap_size);
if (base_addr == NULL) {
dev_err(&pdev->dev, "Couldn't ioremap memory at 0x%08lx\n",
(unsigned long)res->start);
ret = -ENOMEM;
goto err_release_region;
}
hmcSPI0_proc_entry = proc_create(DRIVER_NAME, 0, NULL,
&proc_hmcSPI0_operations);
if (hmcSPI0_proc_entry == NULL) {
dev_err(&pdev->dev, "Couldn't create proc entry\n");
ret = -ENOMEM;
goto err_create_proc_entry;
}
printk(KERN_INFO DRIVER_NAME " probed at VA 0x%08lx\n",
(unsigned long) base_addr);
printk(KERN_INFO DRIVER_NAME " probed at PA 0x%08lx\n",
(unsigned long)res->start);
return 0;
err_create_proc_entry:
iounmap(base_addr);
err_release_region:
release_mem_region(res->start, remap_size);
return ret;
}
/* device match table to match with device node in device tree */
static const struct of_device_id hmcSPI0_of_match[] = {
{.compatible = "xyz,hmcSPI-0.00.a"},
{.compatible = "xyz,hmcSPI-1.00.a"},
{.compatible = "xyz,hmcSPI-2.00.a"},
{},
};
MODULE_DEVICE_TABLE(of, hmcSPI0_of_match);
/* platform driver structure for hmcSPI0 driver */
static struct platform_driver hmcSPI0_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = hmcSPI0_of_match},
.probe = hmcSPI0_probe,
.remove = hmcSPI0_remove,
.shutdown = hmcSPI0_shutdown
};
/* Register hmcSPI0 platform driver */
module_platform_driver(hmcSPI0_driver);
/* Module Informations */
MODULE_AUTHOR("Ganesh Kalbhor, xyz.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_NAME ": hmcSPI0 driver (Simple Version)");
MODULE_ALIAS(DRIVER_NAME);
device tree entry is as follows
/ {
model = "Zynq Zed Development Board";
compatible = "xlnx,zynq-zed", "xlnx,zynq-7000";
aliases {
ethernet0 = &gem0;
serial0 = &uart1;
spi0 = &qspi;
};
memory {
device_type = "memory";
reg = <0x0 0x20000000>;
};
chosen {
bootargs = "console=ttyPS0,115200 root=/dev/ram rw earlyprintk";
linux,stdout-path = &uart1;
stdout-path = &uart1;
};
usb_phy0: phy0 {
compatible = "usb-nop-xceiv";
#phy-cells = <0>;
};
hmcSPI0 {
compatible = "xyz,hmcSPI-0.00.a";
reg = <0x43C00000 0x1000>;
};
hmcSPI0 {
compatible = "xyz,hmcSPI-1.00.a";
reg = <0x43C10000 0x1000>;
};
hmcSPI0 {
compatible = "xyz,hmcSPI-2.00.a";
reg = <0x43C20000 0x1000>;
};
};
Please help me to resolve this problem.
Hello I've written the following code which is a part of a project. It is used to find the ESSID of the current associated network.
But it has a flaw: it also the displays the ESSID of the network with which I am not associated i.e. if I try to associate myself with a wireless n/w and if it is unsuccessful i.e. NO DHCP OFFERS ARE RECEIVED, then also it will display the that ESSID with which I have made my attempt.
Could anyone give me an ioctl call to find the BSSID of current associated wireless n/w?. In my opinion it is the only way with which I a can mark b/w associated and non associated.
CODE:-
int main (void)
{
int errno;
struct iwreq wreq;
CStdString result = "None";
int sockfd;
char * id;
char ESSID[100];
memset(&wreq, 0, sizeof(struct iwreq));
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
fprintf(stderr, "Cannot open socket \n");
fprintf(stderr, "errno = %d \n", errno);
fprintf(stderr, "Error description is : %s\n",strerror(errno));
return result ;
}
CLog::Log(LOGINFO,"Socket opened successfully");
FILE* fp = fopen("/proc/net/dev", "r");
if (!fp)
{
// TBD: Error
return result;
}
char* line = NULL;
size_t linel = 0;
int n;
char* p;
int linenum = 0;
while (getdelim(&line, &linel, '\n', fp) > 0)
{
// skip first two lines
if (linenum++ < 2)
continue;
p = line;
while (isspace(*p))
++p;
n = strcspn(p, ": \t");
p[n] = 0;
strcpy(wreq.ifr_name, p);
id = new char[IW_ESSID_MAX_SIZE+100];
wreq.u.essid.pointer = id;
wreq.u.essid.length = 100;
if ( ioctl(sockfd,SIOCGIWESSID, &wreq) == -1 ) {
continue;
}
else
{
strcpy(ESSID,id);
return ESSID;
}
free(id);
}
free(line);
fclose(fp);
return result;
}