I've modified a Linux kernel sound driver to use a new virtual address instead of a physical address when receiving data. When the driver is called on, it reports that the data is 0. I'm looking for any input or feedback on what I may be missing in my process and implementation. If my descriptions below are too vague to give proper feedback, I am happy to expand and provide more details.
I have a physical register at address 0xc0056014. The hardware register is readable and is correctly initialized in the device tree and Linux kernel(4.4.71). The register holds audio data input from a microphone.
The bits in the physical register are not mapped correctly for playback. This causes audio playback to be filled with white-noise and hissing. I've made a user-space program that will take a raw audio sample and remap the data bits to new raw/wav sample where playback quality is as expected.
My goal is to have this data remapping done in the kernel space. Example data in physical register: 0x4000f965 Example data remapped : 0xf9654000
In the kernel sound driver written for the hardware's audio interface, I've done the following:
- Initialized a new virtual address with
- Started a thread.
- In thread, mapped physical register with
Code:
__iomem *regs = ioremap(0xc0056014, 4);
- Read the register values into temp buffers & remap the 32bits.
- Write remap value to virtual address with
Code:
memcpy(dst_addr, src_addr, data_size);
- Lastly, outside of thread where driver was setting address of physical register, I changed to the virtual address.
Code:
dma->peri_addr = dst_addr;
I'm able to do kernel prints that read the values in my virtual address. The kernel prints show correct values in virtual address, but when calling on the kernel sound driver by use of alsa recording tools, the audio data is being reported as 0.
The kernel reports no errors or warnings and I'm a little stumped at what I'm missing or what to do next. Any pointers, tips, feedback, or questions is welcome!
Cheers.
Driver setting address:
Code:
if (phy_base == 0xC0056000 && dma == &par->capt)
{
void *p;
size_t data_size;
data_size = sizeof(unsigned long);
p = vzalloc(data_size);
void *dst_addr = (void *)(p);
printk(KERN_INFO "Virtual Address is : 0x%p\n", p);
char our_thread[8]="thread1";
thread1 = kthread_create(thread_fn,dst_addr,our_thread);
if((thread1))
{
printk(KERN_INFO "Hit thread1");
wake_up_process(thread1);
}
dma->peri_addr = dst_addr;
printk(KERN_INFO "snd i2s1: %s dma peri addr is 0x%p and virtual addr is 0x%p\n", STREAM_STR(i), (void *)dma->peri_addr, p);
}
Thread:
Code:
int thread_fn(void *dst_addr) {
printk(KERN_INFO "Hit inside thread1\n");
size_t data_size;
data_size = sizeof(unsigned long);
int k = 0;
while (1) {
//printk(KERN_INFO "Virtual Address is : 0x%p\n", p);
unsigned long read_result;
void __iomem *regs = ioremap(0xc0056014, 4);
read_result = *((unsigned long *) regs);
uint32_t sample = read_result;
uint32_t sample1, sample1buf1, sample1buf2, sample1buf3, sample1buf4;
sample1buf1 = (sample >> (8*0)) & 0xff;
sample1buf2 = (sample >> (8*1)) & 0xff;
sample1buf3 = (sample >> (8*2)) & 0xff;
sample1buf4 = (sample >> (8*3)) & 0xff;
/* Shift bytes from s16le format bit order to s32le format bit order
[ L | R ] [ L]
[ L | R ] [ R]
MSB MSB MSB
[99 f9 | 00 40] -> [00 40 99 f9]
[cf f9 | 00 40] -> [00 40 cf f9]
[12 34 | 56 78] -> [56 78 12 34]
*/
sample1buf1 = sample1buf1 << 16;
sample1buf2 = sample1buf2 << 24;
sample1buf4 = sample1buf4 << 8;
sample1 = sample1 & 0x00000000;
sample1 = sample1 | sample1buf3;
sample1 = sample1 | sample1buf4;
sample1 = sample1 | sample1buf1;
sample1 = sample1 | sample1buf2;
sample = sample1;
void *src_addr;
src_addr = &sample;
memcpy(dst_addr, src_addr, data_size);
iounmap(regs);
}
return 0;
}