Virtual address to physical address translation in Linux proc module - c

I'm trying to create my own proc node "os_pagemap" on Linux(using odroid)
This node's goal is to print all physical memory page's information.
(sudo cat /proc/os_pagemap)
Like this :
[PHY] Virt 483252 Phy 266908 VMA 0 PID 5773 PNAME com.sec.android.app.keyboard
[PHY] Virt 483253 Phy 266909 VMA 0 PID 5773 PNAME com.sec.android.app.keyboard
[PHY] Virt 483254 Phy 266910 VMA 0 PID 5773 PNAME com.sec.android.app.keyboard
[PHY] Virt 398391 Phy 266920 VMA /dev/ashmem/dalvik-bitmap-1 PID 5773 PNAME com.sec.android.app.keyboard
where VMA refers VMA name
To acheive the goal, my design is like this :
1. read_lock(&tasklock)
2. for_each_process(p) => get pids
3. read_unlock(&tasklock)
4. Loop for each pid
1)task = get_pid_task(pid)
2)if task==NULL => skip
3)mm=task->mm
4)down_read(&mm->mmap_sem)
5)Loop for each vma in mm
1>store vma information into os_pagemap_struct
6)up_read(&mm->mmap_sem)
5. Print os_pagemap_struct
However, I can't find out how to
"get vma information" and "Print os_pagemap_struct"
This is the code that I've done:
I only get "vm_start" and "vm_end" and I can't print it well.
struct os_pagemap{
unsigned long vm_start;
unsigned long vm_end;
//more on...
};
static ssize_t ospagemap_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
struct task_struct * p = NULL;
char * pagemap_buf = kmalloc(500, GFP_KERNEL);
int i = 0, j;
int cur = 0, bytes=0;
struct pid *pid_struct;
int pid[100];
struct mm_struct* mm;
struct os_pagemap pagemap;
struct vm_area_struct * vma;
int count = 0;
int buf_size = 0;
read_lock(&tasklist_lock);
for_each_process(p){ //get all process' pids
pid[i] = p->pid;
i++;
}
read_unlock(&tasklist_lock);
for (j = 0; j < i; j++){ //loop for each process
pid_struct = find_get_pid(pid[j]);
p = get_pid_task(pid_struct, PIDTYPE_PID);
put_pid(pid_struct);
if (p == NULL){ //skip this task
printk("[%d]p is NULL", pid[j]);
continue;
}
mm = p->mm;
if (mm == NULL){
printk("\n[%d]mm is NULL!\n",pid[j]);
continue;
}
down_read(&mm->mmap_sem);
vma = mm->mmap;
count = 0;
while (1){ //loop for each vma
if (vma == NULL){
printk("\n[%d]vma is NULL!\n", pid[j]);
break;
}
if (buf_size >= 450){
printk("Realloc size : %d\n", cur + 500);
krealloc(pagemap_buf, cur + 500, GFP_KERNEL);
buf_size = 0;
}
pagemap.vm_start = vma->vm_start;
pagemap.vm_end = vma->vm_end;
bytes = snprintf((cur > 0) ? cur + pagemap_buf : pagemap_buf,
500 - cur,
"Task : [%d]%s start : %lu end : %lu\n", p->pid, p->comm,
pagemap.vm_start, pagemap.vm_end);
printk("Task : [%d]%s start : %lu end : %lu\n", p->pid, p->comm,
pagemap.vm_start, pagemap.vm_end);
cur += bytes;
buf_size += bytes;
vma = vma->vm_next;
count++;
}
up_read(&mm->mmap_sem);
}
printk("cur : %d\n", cur);
copy_to_user(buf, pagemap_buf, (size<cur) ? size : cur);
return (size<cur) ? size : cur;
}
static int ospagemap_open(struct inode *inode, struct file *file)
{
printk("ospagemap opened");
return 0;
}
const struct file_operations proc_ospagemap_operations = {
.llseek = mem_lseek, /* borrow this */
.read = ospagemap_read,
.open = ospagemap_open,
};
static int __init proc_ospagemap_init(void)
{
proc_create("os_pagemap", 0, NULL, &proc_ospagemap_operations);
return 0;
}
fs_initcall(proc_ospagemap_init);

Related

C MultiThread Value not printed

First, Here is an entire code.
Read the file
Input file content into structure value
Begin Multithread
$ cat sunje.conf
{
DSN:GOLDILOCKS
UID:TEST
PWD:test
COMMIT INTERVAL:1
}
$ cat sh.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
//EXEC SQL INCLUDE SQLCA;
typedef struct thread
{
char *dsn;
char *uid;
char *pwd;
char mode;
int num;
int start;
int end;
int interval;
} thread;
pthread_mutex_t mutex;
void *MultiThread(void* threadInfo);
int main(int argc, char **argv)
{
char s[1024];
FILE *fp;
char conn[4][1024];
int i = 0;
int session = 0;
int record = 0;
char mode = NULL;
//int interval;
fp = fopen("sunje.conf", "r");
while(!feof(fp))
{
fgets(s, 1024, fp);
char *ptr = strchr(s, ':');
if (ptr != NULL)
{
strcpy(conn[i], ptr + 1);
conn[i][strlen(conn[i]) - 1] = '\0';
//printf("conn[%d]=\"%s\"\n", i, conn[i]);
i++;
}
}
fclose(fp);
session = atoi(argv[1]);
record = atoi(argv[2]);
mode = argv[4][0];
printf("=========================================\n");
printf("DSN = [%s]\n"
"ID = [%s]\n"
"PW = [%s]\n"
"Commit Interval = [%s]\n"
"\n"
"Total Session = %d\n"
"Total Record = %d\n"
"Mode = %c\n", conn[0], conn[1], conn[2], conn[3], session, record, mode);
printf("=========================================\n");
int init = 1;
int init_div = record / session ;
int init_mod = record % session ;
if (mode == 's')
{
init = record;
init_div = 0;
}
pthread_mutex_init(&mutex, NULL);
thread threadInfo[session];
pthread_t threadCount[session];
i = 0;
for ( i = 0 ; i < session ; i ++)
{
pthread_mutex_lock(&mutex);
if( i != ( session - 1 ) )
{
threadInfo[i].dsn = conn[0];
threadInfo[i].uid = conn[1];
threadInfo[i].pwd = conn[2];
threadInfo[i].interval = atoi(conn[3]);
threadInfo[i].mode = mode;
threadInfo[i].num = i;
threadInfo[i].start = init;
threadInfo[i].end = init + init_div - 1;
}else
{
threadInfo[i].dsn = conn[0];
threadInfo[i].uid = conn[1];
threadInfo[i].pwd = conn[2];
threadInfo[i].interval = atoi(conn[3]);
threadInfo[i].mode = mode;
threadInfo[i].num = i;
threadInfo[i].start = init;
threadInfo[i].end = init + init_div + init_mod - 1;
}
pthread_mutex_unlock(&mutex);
printf("Thread Num = [%d]\n"
"Mode = [%c]\n"
"Start = [%d]\n"
"End = [%d]\n"
"Interval = [%d]\n"
"DSN = [%s]\n\n"
,threadInfo[i].num, threadInfo[i].mode, threadInfo[i].start, threadInfo[i].end, threadInfo[i].interval, threadInfo[i].dsn);
pthread_create ( &threadCount[i], NULL, MultiThread, (void*)&threadInfo[i] );
init = init + init_div;
}
int result;
i = 0;
for ( i = 0 ; i < session ; i ++)
{
pthread_join ( threadCount[i], (void *)&result );
}
printf("Thread Success\n");
return 0;
}
void *MultiThread(void* threadInfo)
{
thread* info = (thread*)threadInfo;
// struct timeval st, et;
char mode;
int num;
int start;
int end;
int interval;
mode = info->mode;
num = info->num;
start = info->start;
end = info->end;
interval = info->interval;
printf("num[%d] dsn[%s] uid[%s] pwd[%s] mode[%c] interval[%d] start[%d] end[%d]\n", num, info->dsn, info->uid, info->pwd, mode, interval, start, end);
return NULL;
}
Now, I ask a question..
I want to print last thread's value. But only "dsn" value not printed..
I used mutex of pthread to solve this problem. But it was not.
$ ./sh 3 300 2 i
=========================================
DSN = [GOLDILOCKS]
ID = [TEST]
PW = [test]
Commit Interval = [1]
Total Session = 3
Total Record = 300
Mode = i
=========================================
Thread Num = [0]
Mode = [i]
Start = [1]
End = [100]
Interval = [1]
DSN = [GOLDILOCKS]
Thread Num = [1]
Mode = [i]
Start = [101]
End = [200]
Interval = [1]
DSN = [GOLDILOCKS]
num[0] dsn[GOLDILOCKS] uid[TEST] pwd[test] mode[i] interval[1] start[1] end[100]
Thread Num = [2]
Mode = [i]
Start = [201]
End = [300]
Interval = [1]
DSN = [GOLDILOCKS]
num[1] dsn[GOLDILOCKS] uid[TEST] pwd[test] mode[i] interval[1] start[101] end[200]
num[2] dsn[] uid[TEST] pwd[test] mode[i] interval[1] start[201] end[300]
Thread Success
Could you help me?
I can't understand why num[2]'s dsn is not show
int result is 4 bytes.
(void *)&result is 8 bytes.
If the memory structure made like [ int 4 byte result ][ conn[0][0] .. ] .. on first time,
the return will be like [ 8 byte (void **)&result ][ conn[0][4] .. ] ..
Where is conn[0][0] ~ conn[0][3] ? this location covered with NULL(\000).
This program doesn't read after NULL value.
Here is gdb result.
Breakpoint 1, main (argc=5, argv=0x7fffffffdbf8) at sh.gc:131
131 pthread_join ( threadCount[i], (void **)&result );
1: conn[0] = "\000\000\000\000GOLDILOCKS", '\000' <repeats 26 times>, "\364G\336\367\377\177\000\000\000"
(gdb) p &conn[0]
$1 = (char (*)[50]) 0x7fffffffd5c0
(gdb) p &result
$2 = (int *) 0x7fffffffd5bc
(gdb)

Segmentation fault while using my char drivers

I'm trying to write a char driver, named my_module. for every device I want to act in the following way:
if I open the device's file for the first time , I'm Allocating memory
for a struct, which "private_data" field in the device's file will later point to.
If I open the device's file afterwards, I will keep using the same struct that "private_data" points to
the problem: when I open the file for the second time , I have a Segmentation fault. If I reallocate the memory for the struct each time I use "open", there is no error.
what have I done wrong?
/* my_module.c: Example char device module.
*
*/
/* Kernel Programming */
#define MODULE
#define LINUX
#define __KERNEL__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include<linux/slab.h> /* included for the purpose of using kmalloc and kfree */
#include "my_module.h"
#define CAN_READ 1
#define CANT_READ -1
#define CAN_WRITE 1
#define CANT_WRITE -1
#define MY_DEVICE "my_device"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anonymous");
#define BUF_LEN 4096
/* globals */
int my_major = 0; /* will hold the major # of my device driver */
int can_read = CANT_READ;
int can_write = CANT_WRITE;
char * buffp = NULL;
struct file_operations my_fops = {
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
.ioctl = my_ioctl,
.owner = THIS_MODULE
};
typedef struct driver_t {
int can_read;
int can_write;
int curr_index_write_d;
int curr_index_read_d;
char * d_ptr;
} Driver;
Driver * driverCreate( char * buffer, int can_read_arg, int can_write_arg ) {
Driver * driver = (Driver*)kmalloc(sizeof(*driver),GFP_KERNEL);
if(!driver){
return NULL;
}
driver->curr_index_write_d=0;
driver->curr_index_read_d=0;
driver->d_ptr=buffer;
driver->can_read=can_read_arg;
driver->can_write=can_write_arg;
return driver;
}
int init_module(void)
{
//printk(KERN_WARNING "start of module! ");
my_major = register_chrdev(my_major, MY_DEVICE, &my_fops);
if (my_major < 0)
{
//printk(KERN_WARNING "can't get dynamic major\n");
return my_major;
}
//
// do_init();
//
return 0;
}
void cleanup_module(void)
{
//printk(KERN_WARNING "end of module! ");
unregister_chrdev(my_major, MY_DEVICE);
//
// do clean_up();
//
return;
}
int my_open(struct inode *inode, struct file *filp)
{
if(MOD_IN_USE>1) {
return 0;
}
if (filp->f_mode & FMODE_READ)
{
can_read = CAN_READ;
}
if (filp->f_mode & FMODE_WRITE)
{
can_write = CAN_WRITE;
}
char * ptr = kmalloc(BUF_LEN, GFP_KERNEL);
if (!ptr) {
return my_major;
}
Driver * driver = driverCreate(ptr,can_read,can_write);
if (!driver) {
return my_major;
}
filp->private_data = driver;
MOD_INC_USE_COUNT;
return 0;
}
int my_release(struct inode *inode, struct file *filp)
{
/*
if(MOD_IN_USE>1) {
printk(KERN_WARNING "\nclose: MOD IN USE: %d\n", (int)MOD_IN_USE);
MOD_DEC_USE_COUNT;
return 0;
}
printk(KERN_WARNING "\nclose:(suupose to be 1) MOD IN USE: %d\n", (int)MOD_IN_USE);
Driver * d_ptr = (Driver*)(filp->private_data);
char * ptr = d_ptr->d_ptr;
if (filp->f_mode & FMODE_READ)
{
d_ptr->can_read = CANT_READ;
can_read = CANT_READ;
//
// handle read closing
//
}
if (filp->f_mode & FMODE_WRITE)
{
d_ptr->can_write = CANT_WRITE;
can_write = CANT_WRITE;
//
// handle write closing
//
}
if(ptr != NULL) {
kfree(ptr);
kfree(filp->private_data);
filp->private_data=NULL;
printk( KERN_WARNING "Memory is now free ");
}
else {
printk( KERN_WARNING "No memory to free ");
}
*/
return 0;
}
ssize_t my_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
Driver * d_ptr = (Driver*)(filp->private_data);
char * ptr = d_ptr->d_ptr;
int curr_index_write = d_ptr->curr_index_write_d;
int curr_index_read = d_ptr->curr_index_read_d;
if(d_ptr->can_read == CANT_READ) {
return 0;
}
if( curr_index_write - curr_index_read == 0 ) {
return 0;
}
int length = (count >= (curr_index_write - curr_index_read) ?
(curr_index_write - curr_index_read) : count );
copy_to_user((char*)buf,(ptr+curr_index_read),length);
d_ptr->curr_index_read_d = curr_index_write;
return length;
//
// Do read operation.
// Return number of bytes read.
}
ssize_t my_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
Driver * d_ptr = (Driver*)(filp->private_data);
int curr_index_write = d_ptr->curr_index_write_d;
char * ptr = d_ptr->d_ptr;
if(can_write == CANT_WRITE) {
return 0;
}
if( BUF_LEN < curr_index_write + count ) {
return -ENOMEM;
}
copy_from_user((ptr+curr_index_write),(char*)buf,count);
d_ptr->curr_index_write_d = curr_index_write + count;
return count;
//
// Do write operation.
// Return number of bytes written.
}
int my_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
if(filp->private_data==NULL) {
return 0;
}
Driver * d_ptr = (Driver*)(filp->private_data);
switch(cmd)
{
case MY_RESET:
d_ptr->curr_index_write_d = 0;
d_ptr->curr_index_read_d = 0;
//
// handle OP 1.
//
break;
case MY_RESTART:
d_ptr->curr_index_read_d = 0;
//
// handle OP 1.
//
break;
default:
return -ENOTTY;
}
return 0;
}
Instead of this line
driver->d_ptr=buffer;
Try
driver->d_ptr=strdup(buffer);
Remember that d_ptr is a pointer to char. It needs memory allocation first and copy to it. strdup() does the job.

readdir and getdents interfaces -- number of bytes read?

I'm working on Cygwin, which does not implement getdents, nor getdirentries.
The code I'm working on relies on knowing the number of bytes read, which is the return of these calls. All I seem to have is readdir.
Man pages are lacking in Cygwin. Any ideas, or existing documentation, on how to make these interfaces compatible, or how to get the number of bytes read from readdir?
Cygwin's struct dirent, in case it's relevant:
struct dirent
{
uint32_t __d_version; /* Used internally */
ino_t d_ino;
unsigned char d_type;
unsigned char __d_unused1[3];
__uint32_t __d_internal1;
char d_name[NAME_MAX + 1];
};
EDIT
The code that uses getdents is in function readdir (see the link for full file):
static int
mygetdents(int fd, struct dirent *buf, int n) {
return syscall (getdents, fd, (void*) buf, n);
}
long
dirread(int fd, Dir **dp)
{
char *buf;
struct stat st;
int n;
*dp = 0;
if(fstat(fd, &st) < 0)
return -1;
if(st.st_blksize < 8192)
st.st_blksize = 8192;
buf = malloc(st.st_blksize);
if(buf == nil)
return -1;
n = mygetdents(fd, (void*)buf, st.st_blksize);
if(n < 0){
free(buf);
return -1;
}
n = dirpackage(fd, buf, n, dp);
free(buf);
return n;
}
static int
dirpackage(int fd, char *buf, int n, Dir **dp)
{
int oldwd;
char *p, *str, *estr;
int i, nstr, m;
struct dirent *de;
struct stat st, lst;
Dir *d;
n = countde(buf, n);
if(n <= 0)
return n;
if((oldwd = open(".", O_RDONLY)) < 0)
return -1;
if(fchdir(fd) < 0)
return -1;
p = buf;
nstr = 0;
for(i=0; i<n; i++){
de = (struct dirent*)p;
memset(&lst, 0, sizeof lst);
if(de->d_name[0] == 0)
/* nothing */ {}
else if(lstat(de->d_name, &lst) < 0)
de->d_name[0] = 0;
else{
st = lst;
if(S_ISLNK(lst.st_mode))
stat(de->d_name, &st);
nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
}
p += de->d_reclen;
}
d = malloc(sizeof(Dir)*n+nstr);
if(d == nil){
fchdir(oldwd);
close(oldwd);
return -1;
}
str = (char*)&d[n];
estr = str+nstr;
p = buf;
m = 0;
for(i=0; i<n; i++){
de = (struct dirent*)p;
if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
st = lst;
if((lst.st_mode&S_IFMT) == S_IFLNK)
stat(de->d_name, &st);
_p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
}
p += de->d_reclen;
}
fchdir(oldwd);
close(oldwd);
*dp = d;
return m;
}
static int
countde(char *p, int n)
{
char *e;
int m;
struct dirent *de;
e = p+n;
m = 0;
while(p < e){
de = (struct dirent*)p;
if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
break;
if(de->d_name[0]=='.' && de->d_name[1]==0)
de->d_name[0] = 0;
else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
de->d_name[0] = 0;
m++;
p += de->d_reclen;
}
return m;
}
I haven't made sense of dirpackage yet, but I think I may get around that detail if I could get the return of getdents in another way.
From the link you posted to the dirpackage method:
for(i=0; i<n; i++){
de = (struct dirent*)p;
memset(&lst, 0, sizeof lst);
if(de->d_name[0] == 0)
/* nothing */ {}
else if(lstat(de->d_name, &lst) < 0)
de->d_name[0] = 0;
else{
st = lst;
if(S_ISLNK(lst.st_mode))
stat(de->d_name, &st);
nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
}
p += de->d_reclen;
}
Here n comes from:
n = countde(buf, n);
... where the original value of n is supplied from the return of the getdents syscall. The name countde probably stands for "count directory entries".
As you can see from the loop, the return from countde represents the number of entries returned by the getdents call. Each iteration through the loop processes one directory entry (de = (struct dirent*)p;) and then finds the next one (p += de->d_reclen;).
That should be pretty straight-forward to translate to using readdir, since it only ever returns one entry.

Writing improper number of frames using PortAudio?

Running my program, I appear to not be writing the correct amount of frames according to the index.
$ ./test
Now recording!! Please speak into the microphone.
index = 0
Writing to: test.flac
audio.h:
#include <stdint.h>
#include <string.h>
typedef struct
{
uint32_t duration;
uint16_t format_type;
uint16_t number_of_channels;
uint32_t sample_rate;
uint32_t frameIndex; /* Index into sample array. */
uint32_t maxFrameIndex;
char* recordedSamples;
} AudioData;
int recordFLAC(AudioData* data, const char *fileName);
AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration);
capture.c:
#include <stdio.h>
#include <stdlib.h>
#include <portaudio.h>
#include <sndfile.h>
#include "audio.h"
AudioData* initAudioData(uint32_t sample_rate, uint16_t channels, uint32_t duration)
{
AudioData* data = malloc(sizeof(*data));
if (!data) return NULL;
data->duration = duration;
data->format_type = 1;
data->number_of_channels = channels;
data->sample_rate = sample_rate;
data->frameIndex = 0;
data->maxFrameIndex = sample_rate * duration;
data->recordedSamples = malloc(sizeof(data->maxFrameIndex));
if(!data->maxFrameIndex) return NULL;
return data;
}
static int recordCallback(const void *inputBuffer, void *outputBuffer, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
{
AudioData* data = (AudioData*)userData;
const char* buffer_ptr = (const char*)inputBuffer;
char* index_ptr = &data->recordedSamples[data->frameIndex];
(void) outputBuffer;
(void) timeInfo;
(void) statusFlags;
long framesToCalc;
long i;
int finished;
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
if(framesLeft < frameCount){
framesToCalc = framesLeft;
finished = paComplete;
}else{
framesToCalc = frameCount;
finished = paContinue;
}
if(!inputBuffer){
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0;
}
}else{
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = *buffer_ptr++;
}
}
data->frameIndex += framesToCalc;
return finished;
}
int recordFLAC(AudioData* data, const char *fileName)
{
PaStreamParameters inputParameters;
PaStream* stream;
int err = 0;
int totalFrames = data->maxFrameIndex;
int numSamples;
int numBytes;
char max, val;
double average;
numSamples = totalFrames * data->number_of_channels;
numBytes = numSamples;
data->recordedSamples = malloc(numBytes);
if(!data->recordedSamples)
{
printf("Could not allocate record array.\n");
goto done;
}
for(int i = 0; i < numSamples; i++) data->recordedSamples[i] = 0;
if((err = Pa_Initialize())) goto done;
inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
if (inputParameters.device == paNoDevice) {
fprintf(stderr,"Error: No default input device.\n");
goto done;
}
inputParameters.channelCount = data->number_of_channels; /* stereo input */
inputParameters.sampleFormat = data->format_type;
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = NULL;
/* Record some audio. -------------------------------------------- */
err = Pa_OpenStream(&stream, &inputParameters, NULL, data->sample_rate, paFramesPerBufferUnspecified, paClipOff, recordCallback, &data);
if(err) goto done;
if((err = Pa_StartStream(stream))) goto done;
puts("Now recording!! Please speak into the microphone.");
while((err = Pa_IsStreamActive(stream)) == 1)
{
Pa_Sleep(1000);
printf("index = %d\n", data->frameIndex);
}
if( err < 0 ) goto done;
err = Pa_CloseStream(stream);
if(err) goto done;
/* Measure maximum peak amplitude. */
max = 0;
average = 0.0;
for(int i = 0; i < numSamples; i++)
{
val = data->recordedSamples[i];
val = abs(val);
if( val > max )
{
max = val;
}
average += val;
}
average /= (double)numSamples;
done:
Pa_Terminate();
if(err)
{
fprintf(stderr, "An error occured while using the portaudio stream\n");
fprintf(stderr, "Error number: %d\n", err);
fprintf(stderr, "Error message: %s\n", Pa_GetErrorText(err));
err = 1; /* Always return 0 or 1, but no other return codes. */
}
else
{
SF_INFO sfinfo;
sfinfo.channels = 1;
sfinfo.samplerate = data->sample_rate;
sfinfo.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16;
// open to file
printf("Writing to: %s\n", fileName);
SNDFILE * outfile = sf_open(fileName, SFM_WRITE, &sfinfo);
if (!outfile) return -1;
// prepare a 3 second long buffer (sine wave)
const int size = data->sample_rate * 3;
// write the entire buffer to the file
sf_write_raw(outfile, data->recordedSamples, size);
// force write to disk
sf_write_sync(outfile);
// don't forget to close the file
sf_close(outfile);
}
return err;
}
I'm not quite sure where I am going wrong, I know I need to be writing more frames. Any suggestions?
There seems to be something wrong with your assumptions about the sample format. In the callback you are using char * (single bytes) for the sample format, but in your libsndfile call you're opening a 16 bit file with SF_FORMAT_PCM_16.
This is not so good:
data->format_type = 1;
I recommend using one of the symbolic constants in the PortAudio library for sample formatting. Maybe you want a 16 bit one? And if so, you want to be using short* not char* in the PA callback.
Finally, if your channel count is not 1, the copy loops are incorrect:
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0;
}
A "frame" contains data for all channels, so for example, if it's a stereo input your iteration needs to deal with both left and right channels like this:
for(i = 0; i < framesToCalc; i++){
*index_ptr++ = 0; // left
*index_ptr++ = 0; // right
}
Same for the other loops.

Code for writing and reading on a device file from a kernel module?

I have tried the following code many times .
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<asm/uaccess.h>
#include<linux/semaphore.h>
MODULE_LICENSE("DUAL BSD/GPL");
static int dev_open(struct inode *,struct file *);
static int dev_release(struct inode *,struct file *);
ssize_t dev_read(struct file *,char *, size_t ,loff_t *);
ssize_t dev_write(struct file *,const char *,size_t ,loff_t *);
static int major;
int dev_major = 0;
int dev_minor = 0;
struct cdev *cdev;
struct device {
char array[100];
struct semaphore sem;
}chr_arr;
struct file_operations dev_ops = {
.owner = THIS_MODULE,
.read = dev_read,
.write = dev_write,
.open = dev_open,
.release = dev_release
};
ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset)
{
int i;
i=copy_to_user(buf,chr_arr.array,count);
printk(KERN_ALERT"buff:%s",buf);
return i;
}
ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *offset)
{
//printk(KERN_ALERT"\nsorry,byebye");
int j;
//msg_ptr = kmalloc(count,GFP_KERNEL);
//for(j=0;j<count;j++)
if(count>100)
return -1;
j = copy_from_user(chr_arr.array,buf,count);
//printk(KERN_ALERT"msg_ptr:%s",msg_ptr);
return j;
}
static int dev_open(struct inode *inode,struct file *filp)
{
filp->private_data = inode->i_cdev;
if(down_interruptible(&chr_arr.sem))
{
printk(KERN_INFO " could not hold semaphore");
return -1;
}
//printk(KERN_ALERT"ah ha the device is open !now we can go further");
return 0;
}
static int dev_release(struct inode *inode,struct file *filp)
{
up(&chr_arr.sem);
//module_put(THIS_MODULE);
return 0;
}
static int init_device(void)
{
int result;
dev_t dev_no,dev;
result = alloc_chrdev_region(&dev_no,0,1,"chr_dev");
if(result < 0)
{
printk("sorry no major number left");
return result;
}
major = MAJOR(dev_no);
dev = MKDEV(major,0);
cdev = cdev_alloc();
cdev->ops = &dev_ops;
sema_init(&chr_arr.sem,1);
printk("the major number allocated is %d\n",major);
result = cdev_add(cdev,dev,1);
if(result < 0 )
{
printk(KERN_INFO "Unable to allocate cdev");
return result;
}
return 0;
}
static void clean_device(void)
{
cdev_del(cdev);
unregister_chrdev_region(major,1);
}
module_init(init_device);
module_exit(clean_device);
but its giving me the following warning.
CC [M] /home/karan/practice/scrw/scrw1.o
In file included from /usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess.h:571:0,
from /home/karan/practice/scrw/scrw1.c:4:
In function ‘copy_from_user’,inlined from ‘write’ at /home/karan/practice/scrw/scrw1.c:43:6:
/usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess_32.h:212:26: warning: call to ‘copy_from_user_overflow’ declared with attribute warning: copy_from_user() buffer size is not provably correct
Building modules, stage 2.
MODPOST 1 modules
CC /home/karan/practice/scrw/scrw1.mod.o
LD [M] /home/karan/practice/scrw/scrw1.ko
and then when I try to write echo hi > /dev/my_dev the screen freezes after 30 secs or so.
The problem is that you should return the number of bytes read/written in your read/write methods, the return value of copy_{from,to}_user() is 0 if everything goes well. Return e.g. count in your write method if copying succeeds:
unsigned long ret;
printk(KERN_INFO "Inside write \n");
if (count > sizeof(char_arr.array) - 1)
return -EINVAL;
ret = copy_from_user(char_arr.array, buff, count);
if (ret)
return -EFAULT;
char_arr.array[count] = '\0';
return count;
You should also make sure that a terminating '\0' character is appended when you copy to your buffer (if you'd like to deal only with strings). If it is binary data you deal with store its length in your struct as well.
An example read method:
ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset)
{
int len = count >= strlen(chr_arr.array) ? strlen(chr_arr.array) : count;
if (*offset >= strlen(chr_arr.array))
return 0;
if (copy_to_user(buf,chr_arr.array,len))
return -EFAULT;
return len;
}
Edit: messed up example code, fixing it.
Edit2: example read method.

Resources