pa3gsb / Radioberry-2.x

Ham Radio hat for Raspberry PI
417 stars 88 forks source link

Build for 64 bit kernel #13

Closed johnsop2 closed 2 years ago

johnsop2 commented 2 years ago

Here are some changes that allow the device driver to build for a 64bit kernel

ifndef RADIOBERRY_IOCTL_H

define RADIOBERRY_IOCTL_H

include <linux/types.h>

include <linux/ioctl.h>

define RADIOBERRY_MAGIC ('x')

define RADIOBERRY_IOC_COMMAND _IOW(RADIOBERRY_MAGIC, 1, __u8)

struct rb_info_arg_t { int major, minor;

int fpga;

int version;

int rb_command;
int command;
int command_data;

} ;

endif

/* This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to http://unlicense.org/

sudo cp radioberry.ko /lib/modules/$(uname -r)/kernel/drivers/sdr */

include <linux/init.h>

include <linux/module.h>

include <linux/kernel.h>

include <linux/cdev.h>

include <linux/device.h>

include <linux/slab.h>

include <linux/fs.h>

include <linux/errno.h>

include <linux/types.h>

include <linux/proc_fs.h>

include <linux/fcntl.h>

include <linux/io.h>

include <linux/ioport.h>

include <linux/uaccess.h>

include <linux/kthread.h>

include <linux/sched.h>

include <linux/delay.h>

include <linux/firmware.h>

include <linux/circ_buf.h>

include <linux/wait.h>

include <linux/spinlock.h>

include <linux/err.h>

include <linux/gpio.h>

include <linux/gpio/consumer.h>

include <linux/of.h>

include <linux/platform_device.h>

include <linux/property.h>

include <linux/interrupt.h>

include "radioberry_rpi.h"

include "radioberry_ioctl.h"

include "radioberry_gateware.h"

include "radioberry_firmware.h"

define VERSION "9"

static DEFINE_MUTEX(radioberry_mutex); static wait_queue_head_t rx_sample_queue;

define DEVICE_NAME "radioberry"

define DRIVER_NAME "radioberry"

define CLASS_NAME "radioberry"

static int majorNumber;
static struct class radioberryCharClass = NULL; static struct device radioberryCharDevice = NULL;

define SAMPLE_BYTES 512

static int _nrx = 1;

static unsigned int irqNumber; static unsigned int gpioRxSamplesiPin = 25;

static irq_handler_t radioberry_irq_handler(unsigned int irq, void dev_id, struct pt_regs regs){ wake_up_interruptible(&rx_sample_queue); return (irq_handler_t) IRQ_HANDLED;
}

static void firmware_load(char *firmware, int size) { printk(KERN_INFO "inside %s function \n", FUNCTION);

u8 *buf = kmalloc(size + 1, GFP_KERNEL);
memcpy(buf, firmware, size);
buf[size] = '\0';

printk(KERN_INFO "Radioberry gateware file size: %d\n", size);

initialize_gateware();
prepare_gateware_loading();
int b = 0;
for (b = 0; b < size; b++) {
   upload_gateware_byte(buf[b]);
}
activate_gateware();

kfree(buf);

}

static void loading_radioberry_gateware(struct device *dev) { printk(KERN_INFO "inside %s function \n", FUNCTION);

const struct firmware *fw_entry;
if (request_firmware(&fw_entry, "radioberry.rbf", dev) != 0 ) {
       printk(KERN_ERR "gateware radioberry.rbf: Firmware not available\n");
       return;
}

firmware_load(fw_entry->data, fw_entry->size);

release_firmware(fw_entry);

}

static ssize_t radioberry_read(struct file flip, char buf, size_t count, loff_t pos) { unsigned char rx_stream[SAMPLE_BYTES]={};
wait_event_interruptible(rx_sample_queue, (((
rpi_read_io) >> 25) & 1) != 0); count = rxStream(_nrx, rx_stream);
if (copy_to_user((char *)buf, &rx_stream, count)) return -EFAULT; return count;
}

static ssize_t radioberry_write(struct file flip, const char buf, size_t count, loff_t *pos) {

unsigned char tx_stream[4];

if (count > 0) { if (copy_from_user(&tx_stream, buf, sizeof(tx_stream))) { return -EFAULT; } return write_iq_sample(tx_stream); } return 0; }

static int radioberry_open(struct inode inode, struct file filep) {

printk(KERN_INFO "inside %s function \n", __FUNCTION__);

if(!mutex_trylock(&radioberry_mutex)){                                            
      printk(KERN_ALERT "Radioberry Char: Device in use by another process");
      return -EBUSY;
}   
int *minor = (int *)kmalloc(sizeof(int), GFP_KERNEL);
int major = MAJOR(inode->i_rdev);
*minor = MINOR(inode->i_rdev);
filep->private_data = (void *)minor;

return 0;

}

static int radioberry_release(struct inode inode, struct file filep) {

printk(KERN_INFO "inside %s function \n", __FUNCTION__);

kfree(filep->private_data);
mutex_unlock(&radioberry_mutex); 

return 0;

}

static long radioberry_ioctl(struct file *fp, unsigned int cmd, unsigned long arg){

//printk(KERN_INFO "inside %s function \n", __FUNCTION__);

unsigned char data[6];
int lnrx = _nrx;

int rc;
struct rb_info_arg_t *rb_info= kmalloc(sizeof(struct rb_info_arg_t), GFP_DMA);

struct rb_info_arg_t rb_info_ret;

switch(cmd){
    case RADIOBERRY_IOC_COMMAND:

        rc = copy_from_user(rb_info, (void *)arg, sizeof(struct rb_info_arg_t));

        data[0] = ( rb_info->rb_command           & 0xFF); //MSB  
        data[1] = ( rb_info->command              & 0xFF);
        data[2] = ((rb_info->command_data >> 24)  & 0xFF);
        data[3] = ((rb_info->command_data >> 16)  & 0xFF);
        data[4] = ((rb_info->command_data >>  8)  & 0xFF);
        data[5] = ( rb_info->command_data         & 0xFF);

        //printk(KERN_INFO "Command kernel %2X - %2X - %2X - %2X - %2X - %2X \n", data[0], data[1], data[2], data[3], data[4], data[5]);
        if ((data[1] & 0xFE)  == 0x00) lnrx = ((data[5] & 0x38) >> 3) + 1;

        // tell the gateware the command.
        spiXfer(data, data, 6);

        _nrx = lnrx;

        // give feedback to firmware.
        rb_info_ret.rb_command = data[0]; // return the radioberry status information.
        rb_info_ret.major = data[4];
        rb_info_ret.minor = data[5];

        rb_info_ret.fpga = data[3] & 0x03; 
        rb_info_ret.version = 9; 

        if (copy_to_user((struct rb_info_arg_t *)arg, &rb_info_ret, sizeof(struct rb_info_arg_t))) return -EACCES;

        break;

    default:
        return -ENOTTY;
}

return 0;

}

static struct file_operations radioberry_fops = { .owner = THIS_MODULE, .open = radioberry_open, .release = radioberry_release, .write = radioberry_write, .read = radioberry_read, .unlocked_ioctl = radioberry_ioctl };

static int radioberry_probe(struct platform_device pdev) { printk(KERN_INFO "inside %s function \n", FUNCTION); struct device dev = &pdev->dev;
return 0; }

static int radioberry_remove(struct platform_device *pdev) { printk(KERN_INFO "inside %s function \n", FUNCTION); return 0; }

static const struct of_device_id of_radioberry_match[] = { {.compatible = "sdr,radioberry", }, {/end of list /}, };

MODULE_DEVICE_TABLE(of, of_radioberry_match);

static struct platform_driver radioberry_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(of_radioberry_match), }, .probe = radioberry_probe, .remove = radioberry_remove, };

static int __init radioberry_init(void) { int retval; size_t size;

printk(KERN_INFO "inside %s function \n", __FUNCTION__);
printk(KERN_INFO "%s loading...\n", DRIVER_NAME);

int result = platform_driver_register(&radioberry_driver);
printk(KERN_INFO "platform driver registered %d \n", result);

// Dynamically allocate a major number for the device
majorNumber = register_chrdev(0, DEVICE_NAME, &radioberry_fops);
if (majorNumber<0){
  printk(KERN_ALERT "Radioberry driver failed to register a major number\n");
  return majorNumber;
}
printk(KERN_INFO "Radioberry: registered correctly with major number %d\n", majorNumber);

// Register the device class radioberryCharClass = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(radioberryCharClass)){
unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_ALERT "Failed to register device class\n"); return PTR_ERR(radioberryCharClass);
} printk(KERN_INFO "Radioberry: device class registered correctly\n");

// Register the device driver radioberryCharDevice = device_create(radioberryCharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(radioberryCharDevice)){
class_destroy(radioberryCharClass);
unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_ALERT "Failed to create the device\n"); return PTR_ERR(radioberryCharDevice); } printk(KERN_INFO "Radioberry char: device class created correctly\n");

mutex_init(&radioberry_mutex);
init_waitqueue_head(&rx_sample_queue);

//configure irq.
gpio_request(gpioRxSamplesiPin, "sysfs");       
gpio_direction_input(gpioRxSamplesiPin);        
gpio_export(gpioRxSamplesiPin, false);  

printk(KERN_INFO "Radioberry: The rx sample state is currently: %d\n", gpio_get_value(gpioRxSamplesiPin));

// GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
irqNumber = gpio_to_irq(gpioRxSamplesiPin);
printk(KERN_INFO "Radioberry: The rx samples pin is mapped to IRQ: %d\n", irqNumber);

// This next call requests an interrupt line
result = request_irq(irqNumber,             
                    (irq_handler_t) radioberry_irq_handler, 
                    IRQF_TRIGGER_RISING,   // Interrupt on rising edge  RQF_TRIGGER_RISING
                    "radioberry_rx_irq",    // Used in /proc/interrupts to identify the owner
                    NULL);                 

printk(KERN_INFO "Radioberry: The interrupt request result is: %d\n", result);  

initialize_rpi();
loading_radioberry_gateware(radioberryCharDevice);
initialize_firmware();

return result;

}

static void __exit radioberry_exit(void) { int i; dev_t devno; dev_t devno_top;

printk(KERN_INFO "inside %s function \n", __FUNCTION__);

free_irq(irqNumber, NULL);
gpio_unexport(gpioRxSamplesiPin); 

platform_driver_unregister(&radioberry_driver);

device_destroy(radioberryCharClass, MKDEV(majorNumber, 0));     
class_unregister(radioberryCharClass);                        
class_destroy(radioberryCharClass);                             
unregister_chrdev(majorNumber, DEVICE_NAME); 

mutex_destroy(&radioberry_mutex); 

deinitialize_rpi();

printk(KERN_INFO "Radioberry: Module removed!\n");  

}

module_init(radioberry_init); module_exit(radioberry_exit);

/*

pa3gsb commented 2 years ago

Tnx. Available in beta release. I missed this issue completely.. i will forward this to other mailbox.