I am a windows driver programmer, who is also a complete beginner in linux kernel development. im trying out simple linux kernel modules.
I have written a parallel port driver as in the following code and could successfully load this driver.
I have created a char device node using command mknod with same major and minor numbers as in the code. I have tried reading from the file using cat command and i found it was working fine. While i tried writing the same device using command cat in.txt>/dev/parallel_dev the prompt shows a message "killed" and in dmesg, it has shown unable to handle kernel NULL pointer exception.
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h> //kprintf
#include<linux/module.h> //kmalloc
#include<linux/types.h>
#include<linux/fs.h> //fileoperations,register_chrdev
#include<linux/slab.h>
#include<linux/uaccess.h> //copy from/to user
#include<linux/ioport.h> //check_region
#include<linux/interrupt.h>
#include<linux/delay.h>
static int parallel_open(struct inode* p_node, struct file* p_file);
static int parallel_release(struct inode* p_node, struct file* p_file);
static ssize_t parallel_read(struct file* p_file, char* buf, size_t count, loff_t* f_pos);
static ssize_t parallel_write(struct file* p_file, const char* buf, size_t count, loff_t* f_pos);
static irqreturn_t parallel_interrupt(int irq,void* dev);
static const int major_no = 709;
static const char* dev_name = "parallel_tryout";
#define par_base 0x378
int port;
int* parallel_buffer;
struct file_operations fops = {
.read = parallel_read,
.write = parallel_write,
.open = parallel_open,
.release = parallel_release,
};
static int parallel_init(void)
{
int reg_result;
int irq_req_result;
unsigned int irq_num = 7;
printk("Entered init");
printk("Initializing parallelport dev with major %d",major_no);
reg_result = register_chrdev(major_no, dev_name, 0);
if(reg_result < 0 )
{
printk("Error registering char dev: %s",dev_name);
}
parallel_buffer = kmalloc(16,GFP_KERNEL);
if(parallel_buffer==NULL)
{
printk("Error allocating memory for: %s",dev_name);
}
printk("Port registration");
request_region(0x378,1,"parallelport");
if(port)
{
printk("Error allocating port");
}
parallel_buffer = inb(par_base);
if(parallel_buffer != NULL)
{
printk("Allocated buffer");
}
irq_req_result = request_irq(irq_num,parallel_interrupt,IRQF_SHARED,dev_name,parallel_buffer);
return 0;
}
static void parallel_exit(void)
{
unregister_chrdev(major_no, dev_name);
release_region(0x378,1);
}
static int parallel_open(struct inode* p_node, struct file* p_file)
{
printk("parallel driver opened from device: %s",dev_name);
return 0;
}
static int parallel_release(struct inode* p_node, struct file* p_file)
{
printk("Memory driver closed from device: %s",dev_name);
return 0;
}
static ssize_t parallel_read(struct file* p_file, char* buf, size_t count, loff_t* f_pos)
{
copy_to_user(buf,parallel_buffer,1);
printk("Copied data:%s ",buf);
printk("Memory driver read from device: %s",dev_name);
return 0;
}
static ssize_t parallel_write(struct file* p_file, const char* buf, size_t count, loff_t* f_pos)
{
copy_from_user(parallel_buffer,buf,1);
printk("Copied data:%s ",parallel_buffer);
printk("Memory driver written from device: %s",dev_name);
return 0;
}
static irqreturn_t parallel_interrupt(int irq,void* dev)
{
irqreturn_t return_value;
printk("parallel interrupt detected!!!!");
return return_value;
}
module_init(parallel_init);
module_exit(parallel_exit);
what could be the possible reason for this, and thanks in advance.
Related
I have built a custom hardware configuration in Vivado for Xilinx SoC board, and used petalinux to create a custom driver to control the hardware logic. It seems like after running insmod command, the driver is never initialized and the ->probe() function is not called.
I am new to this domain, and wondering if anyone ran into a similar issue and has some pointers on where and what to check in order to see where the issue is. Any advice would be very helpful!
Running the dmesg command after inserting the driver into the kernel:
root#plzwork3:/proc/device-tree/amba_pl#0/simpleMultiplier#a0000000# dmesg
[ 3351.680317] <1>Hello module world.
[ 3351.683735] <1>Module parameters were (0xdeadbeef) and "default"
Device Tree entity created by Vivado:
/ {
amba_pl: amba_pl#0 {
#address-cells = <2>;
#size-cells = <2>;
compatible = "simple-bus";
ranges ;
simpleMultiplier_0: simpleMultiplier#a0000000 {
clock-names = "axiliteregport_aclk";
clocks = <&zynqmp_clk 71>;
compatible = "xlnx,simpleMultiplier-1.0";
reg = <0x0 0xa0000000 0x0 0x10000>;
xlnx,axiliteregport-addr-width = <0x4>;
xlnx,axiliteregport-data-width = <0x20>;
};
};
};
Device driver code snippets:
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
Full device driver code:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/fs.h>
/* Standard module information, edit as appropriate */
MODULE_LICENSE("GPL");
MODULE_AUTHOR
("Xilinx Inc.");
MODULE_DESCRIPTION("simpmod - loadable module template generated by petalinux-create -t modules");
#define DRIVER_NAME "simpmod"
#define CLASS_NAME "CLASS_TUT"
static char ker_buf[100];
static int currLen = 0;
// Parts of the math operation (2,2,+) is 2+2
static int operand_1 = 0;
static int operand_2 = 0;
static int result = 0;
static struct class *driver_class = NULL;
static dev_t first;
static struct cdev c_dev; // Global variable for the character device
static struct device *ourDevice;
// Pointer to the IP registers
volatile unsigned int *regA;
volatile unsigned int *regB;
volatile unsigned int *regC;
// Structure to hold device specific data
struct simpmod_local {
int irq;
unsigned long mem_start;
unsigned long mem_end;
void __iomem *base_addr;
};
// Character callbacks prototype
static int dev_open(struct inode *inod, struct file *fil);
static ssize_t dev_read(struct file *fil, char *buf, size_t len, loff_t *off);
static ssize_t dev_write(struct file *fil, const char *buf, size_t len, loff_t *off);
static int dev_release(struct inode *inod, struct file *fil);
static struct file_operations fops = {
.read=dev_read,
.write=dev_write,
.open=dev_open,
.release=dev_release,
};
static irqreturn_t simpmod_irq(int irq, void *lp){
printk("simpmod interrupt\n");
return IRQ_HANDLED;
}
static int simpmod_probe(struct platform_device *pdev){
struct resource *r_irq; /* Interrupt resources */
struct resource *r_mem; /* IO mem resources */
struct device *dev = &pdev->dev;
static struct simpmod_local *lp = NULL;
int rc = 0;
printk("Device Tree Probing\n");
// Get data of type IORESOURCE_MEM(reg-addr) from the device-tree
// Other types defined here:
// http://lxr.free-electrons.com/source/include/linux/ioport.h#L33
r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r_mem) {
dev_err(dev, "invalid address\n");
return -ENODEV;
}
// Allocate memory (continuous physical)to hold simpmod_local struct
lp = (struct simpmod_local *) kmalloc(sizeof(struct simpmod_local), GFP_KERNEL);
if (!lp) {
printk("Cound not allocate simpmod device\n");
return -ENOMEM;
}
dev_set_drvdata(dev, lp);
// Save data on simpmod_local strucutre
lp->mem_start = r_mem->start;
lp->mem_end = r_mem->end;
// Ask the kernel the memory region defined on the device-tree and
// prevent other drivers to overlap on this region
// This is needed before the ioremap
if (!request_mem_region(lp->mem_start,
lp->mem_end - lp->mem_start + 1,
DRIVER_NAME)) {
dev_err(dev, "Couldn't lock memory region at %p\n",
(void *)lp->mem_start);
rc = -EBUSY;
goto error1;
}
// Get an virtual address from the device physical address with a
// range size: lp->mem_end - lp->mem_start + 1
lp->base_addr = ioremap(lp->mem_start, lp->mem_end - lp->mem_start + 1);
if (!lp->base_addr) {
dev_err(dev, "simpmod: Could not allocate iomem\n");
rc = -EIO;
goto error2;
}
// ****************** NORMAL Device diver *************************
// register a range of char device numbers
if (alloc_chrdev_region(&first, 0, 1, "Leonardo") < 0){
printk(KERN_ALERT "alloc_chrdev_region failed\n");
return -1;
}
// Create class (/sysfs)
driver_class = class_create(THIS_MODULE, CLASS_NAME);
if (driver_class == NULL) {
printk(KERN_ALERT "Create class failed\n");
unregister_chrdev_region(first, 1);
return -1;
}
ourDevice = device_create(driver_class, NULL, first, NULL, "tutDevice");
if ( ourDevice == NULL){
printk(KERN_ALERT "Create device failed\n");
class_destroy(driver_class);
unregister_chrdev_region(first, 1);
return -1;
}
// Create a character device /dev/tutDevice
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, first, 1) == -1){
printk(KERN_ALERT "Create character device failed\n");
device_destroy(driver_class, first);
class_destroy(driver_class);
unregister_chrdev_region(first, 1);
return -1;petalinux-config -c rootfs
}
// Create the attribute file on /sysfs/class/CLASS_TUT/ called
// parCrtl and isBusy
// Get data of type IORESOURCE_IRQ(interrupt) from the device-tree
r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!r_irq) {
printk("no IRQ found\n");
printk("simpmod at 0x%08x mapped to 0x%08x\n",
(unsigned int __force)lp->mem_start,
(unsigned int __force)lp->base_addr);
// Configuring pointers to the IP registers
regA = (unsigned int __force)lp->base_addr + 0x10;
regB = (unsigned int __force)lp->base_addr + 0x18;
regC = (unsigned int __force)lp->base_addr + 0x26;
printk("regA: 0x%08x\n",(unsigned int)regA);
printk("regB: 0x%08x\n",(unsigned int)regB);
printk("regC: 0x%08x\n",(unsigned int)regC);
return 0;
}
lp->irq = r_irq->start;
rc = request_irq(lp->irq, &simpmod_irq, 0, DRIVER_NAME, lp);
if (rc) {
dev_err(dev, "testmodule: Could not allocate interrupt %d.\n",
lp->irq);
goto error3;
}
return 0;
error3:
free_irq(lp->irq, lp);
error2:
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
error1:
kfree(lp);
dev_set_drvdata(dev, NULL);
return rc;
}
static int simpmod_remove(struct platform_device *pdev){
struct device *dev = &pdev->dev;
struct simpmod_local *lp = dev_get_drvdata(dev);
free_irq(lp->irq, lp);
release_mem_region(lp->mem_start, lp->mem_end - lp->mem_start + 1);
kfree(lp);
dev_set_drvdata(dev, NULL);
return 0;
}
// Indicate which type of hardware we handle on this case(simpleAlu-1.0)
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
#else
# define simpmod_of_match
#endif
static struct platform_driver simpmod_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = simpmod_of_match,
},
.probe = simpmod_probe,
.remove = simpmod_remove,
};
static int __init simpmod_init(void)
{
printk("<1>Simple device driver.\n");
printk("Hussam was here, and he init the module\n");
return platform_driver_register(&simpmod_driver);
}
static void __exit simpmod_exit(void)
{
platform_driver_unregister(&simpmod_driver);
printk(KERN_ALERT "Goodbye module world.\n");
}
static int dev_open(struct inode *inod, struct file *fil){
printk(KERN_ALERT "Character device opened\n");
return 0;
}
// Just send to the user a string with the value of result
static ssize_t dev_read(struct file *fil, char *buf, size_t len, loff_t *off){
// Return the result only once (otherwise a simple cat will loop)
// Copy from kernel space to user space
printk(KERN_ALERT "Reading device rx: %d\n",(int)len);
int n = sprintf(ker_buf, "%d\n", *regC);
// Copy back to user the result (to,from,size)
copy_to_user(buf,ker_buf,n);
printk(KERN_ALERT "Returning %s rx: %d\n",ker_buf,n);
return n;
}
// Parse the input stream ex: "50,2,*" to some operand variables.
static ssize_t dev_write(struct file *fil, const char *buf, size_t len, loff_t *off){
// Get data from user space to kernel space
copy_from_user(ker_buf,buf,len);
sscanf (ker_buf,"%d,%d,%c",&operand_1,&operand_2);
ker_buf[len] = 0;
// Change the IP registers to the parsed operands (on rega and regb)
*regA = (unsigned int)operand_1;
*regB = (unsigned int)operand_2;
printk(KERN_ALERT "Receiving math operation <%d %d>\n",operand_1,operand_2);
return len;
}
static int dev_release(struct inode *inod, struct file *fil){
printk(KERN_ALERT "Device closed\n");
return 0;
}
module_init(simpmod_init);
module_exit(simpmod_exit);
the problem is, that the (compatible) names in your device tree does not match with those in your code:
Device Tree
compatible = "simple-bus";
Code:
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
Put your device tree:
compatible = "xlnx,simpleMultiplier-1.0";
Both entries should match!
Now your "probe" function should be called!
BR
Andreas
your of_match table section in the driver code:
// Indicate which type of hardware we handle on this case(simpleAlu-1.0)
#ifdef CONFIG_OF
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
#else
# define simpmod_of_match
#endif
should be like this:
static struct of_device_id simpmod_of_match[] = {
{ .compatible = "xlnx,simpleMultiplier-1.0", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, simpmod_of_match);
and make sure the compatible line strings have to match in the pl.dtsi and of_match table
I created the device file under /dev folder successfully, but writing to that device file makes kernel to throw following error messages.
kernel:[10090.943733] Internal error: : 1b [#3] PREEMPT SMP ARM
kernel:[10091.049020] Process echo (pid: 3728, stack limit = 0xdc40a218)
kernel:[10091.054880] Stack: (0xdc40be60 to 0xdc40c000)
kernel:[10091.059267] be60: c15491c6 00000022 dc5cb14c bf30430c dc40bedc dc40be88 c075312c c074fe5c
kernel:[10091.067488] be80: c0753018 ffffff04 ffff0a00 c140414c c0d407c8 bf30430c c140414c 40cfbcf3
kernel:[10091.075709] bea0: 00852878 ffffff04 ffff0a00 00040952 c01a7404 c140414c 00852878 00852878
Segmentation fault
I know very basic of Linux Device Drivers
can anyone help me regarding this??
I'm attaching the code for this character device driver
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/uaccess.h>
#include<linux/device.h>
MODULE_AUTHOR("RUCHA");
MODULE_DESCRIPTION("Character Driver First test");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1");
static int MajorNum;
static struct class* RetValOfClassRegistration = NULL;
static struct device* RetVal = NULL;
static char message[1024];
static int openDev(struct inode * , struct file *);
static int closeDev(struct inode * , struct file *);
static ssize_t readDev(struct file *, char *, size_t, loff_t *);
static ssize_t writeDev(struct file *, const char *, size_t, loff_t *);
static struct file_operations FileOps = {
.owner = THIS_MODULE,
.open = openDev,
.read = readDev,
.write = writeDev,
.release = closeDev,
};
static int registerCharDev(void){
return register_chrdev(0,"MyDev",&FileOps);
}
static int __init Loaded(void){
// registering device
MajorNum = registerCharDev();
if(MajorNum < 0){
printk("Can not register device\n");
return -1;
}
printk("Driver Loaded with %d \n",MajorNum);
// registering device class
RetValOfClassRegistration = class_create(THIS_MODULE,"MyCharacterDriver");
if(RetValOfClassRegistration < 0){
printk("can not register class for driver number : %d\n",MajorNum);
return 0;
}
// register the driver
RetVal = device_create(RetValOfClassRegistration,NULL,MKDEV(MajorNum,0),NULL,"MyDev");
return 0;
}
static void __exit Removed(void){
device_destroy(RetValOfClassRegistration,MKDEV(MajorNum,0));
class_unregister(RetValOfClassRegistration);
class_destroy(RetValOfClassRegistration);
unregister_chrdev(MajorNum,"MyDev");
printk("Driver Removed\n");
}
module_init(Loaded);
module_exit(Removed);
static int openDev(struct inode *inodep , struct file *filep){
printk("Device is now open to read write operations\n");
return 0;
}
static int closeDev(struct inode *inodep , struct file *filep){
printk("Device Closed\n");
return 0;
}
static ssize_t readDev(struct file *filep, char *c, size_t v, loff_t *lp){
printk("Read From the device\n");
return 0;
}
static ssize_t writeDev(struct file *file, const char __user *buf, size_t count, loff_t *offset)
{
sprintf(message, "%s(%zu letters)", buf, len);
return 0;
}
and the user input is
echo '1' > /dev/MyDev
You can't access a user data pointer (buf) directly. You need to use copy_from_user to copy the data into kernel memory first. Also, use snprintf instead of sprintf to avoid buffer overflows.
Also, compile with debugging enabled, especially CONFIG_DEBUG_INFO, to get more helpful error messages in the kernel log.
I am writing a kernel driver in drivers/char/new_driver.c .
This new driver registers two new devices /dev/device1 and /dev/device2 by calling misc_register() api.
error = misc_register(&device1);
error = misc_register(&device2);
static struct miscdevice device1 = {
MISC_DYNAMIC_MINOR,
"device1",
&device1_fops
};
static struct miscdevice device2 = {
MISC_DYNAMIC_MINOR,
"device2",
&device2_fops
};
When I load the module I see that 2 two devices are getting created properly in /dev/device1 and /dev/device2
But when I try to write/read operation on this device it gives error saying that there is "No such device " .
Any idea what causes this type of error ? Anything missing in the driver code ?
I still believe that this is permission issue. I am attaching the sample code (without any real implementation) skeleton. Please have a look into it.
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
static int sample_open(struct inode *inode, struct file *file)
{
pr_info("Maverick: %s func :\n",__func__);
return 0;
}
static int sample_close(struct inode *inodep, struct file *filp)
{
pr_info("Maverick: %s func :\n",__func__);
return 0;
}
static ssize_t sample_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
pr_info("Maverick: %s func :\n",__func__);
return len; /* Not doing anything with the data */
}
static ssize_t sample_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
pr_info("Maverick: %s func :\n",__func__);
return len; /* Not do anything with the data */
}
static const struct file_operations sample_fops = {
.owner = THIS_MODULE,
.write = sample_write,
.read = sample_read,
.open = sample_open,
.release = sample_close,
};
struct miscdevice sample_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "device1",
.fops = &sample_fops,
};
static int __init misc_init(void)
{
int error;
error = misc_register(&sample_device);
if (error) {
pr_err("can't misc_register :(\n");
return error;
}
pr_info("Maverick: %s func :\n",__func__);
return 0;
}
static void __exit misc_exit(void)
{
misc_deregister(&sample_device);
pr_info("Maverick: %s func :\n",__func__);
}
module_init(misc_init)
module_exit(misc_exit)
MODULE_DESCRIPTION("Sample Misc Driver");
MODULE_AUTHOR("Vinod Maverick <vinodmaverickr007#gmail.com>");
MODULE_LICENSE("GPL");
Then compile the driver:
make
sudo insmod misc_sample.ko
ilab#SSID-iLBPG3:~/vinod/ldd$ echo "hello" > /dev/device1
-bash: /dev/device1: Permission denied
ilab#SSID-iLBPG3:~/vinod/ldd$ sudo su
root#SSID-iLBPG3:/home/ilab/vinod/ldd# echo "hello" > /dev/device1
However I have not any code inside the read/write callback but still you can see the dmesg without any error
root#SSID-iLBPG3:/home/ilab/vinod/ldd# dmesg
[2903599.416005] Maverick: misc_init func :
[2903623.966281] Maverick: sample_open func :
[2903623.966292] Maverick: sample_write func :
[2903623.966295] Maverick: sample_close func :
root#SSID-iLBPG3:/home/ilab/vinod/ldd#
To anyone who still has this problem, I managed to fix it by changing my minor number from a crazy high number (999) to a more reasonable number (71). Here's my resulting miscdevice struct:
static struct miscdevice chrdev = {
.minor = 71,
.name = "tracefunc",
.fops = &chrdev_fops,
.mode = S_IRUGO,
};
I am trying lessons on USB http://www.linuxforu.com/2011/12/data-transfers-to-from-usb-devices/ and stuck with the problem - while reading, usb_bulk_msg returns error 22 - Invalid argument. Write operation succeeds.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#define MIN(a,b) (((a) <= (b)) ? (a) : (b))
#define BULK_EP_OUT 0x01
#define BULK_EP_IN 0x82
#define MAX_PKT_SIZE 512
static struct usb_device *device;
static struct usb_class_driver class;
static unsigned char bulk_buf[MAX_PKT_SIZE];
static int pen_open(struct inode *i, struct file *f)
{
return 0;
}
static int pen_close(struct inode *i, struct file *f)
{
return 0;
}
static ssize_t pen_read(struct file *f, char __user *buf, size_t cnt, loff_t *off)
{
int retval;
int read_cnt;
/* Read the data from the bulk endpoint */
retval = usb_bulk_msg(device, usb_rcvbulkpipe(device, BULK_EP_IN),
bulk_buf, MAX_PKT_SIZE, &read_cnt, 5000);
if (retval)
{
printk(KERN_ERR "Bulk message returned %d\n", retval);
return retval;
}
if (copy_to_user(buf, bulk_buf, MIN(cnt, read_cnt)))
{
return -EFAULT;
}
return MIN(cnt, read_cnt);
}
static ssize_t pen_write(struct file *f, const char __user *buf, size_t cnt, loff_t *off)
{
int retval;
int wrote_cnt = MIN(cnt, MAX_PKT_SIZE);
if (copy_from_user(bulk_buf, buf, MIN(cnt, MAX_PKT_SIZE)))
{
return -EFAULT;
}
/* Write the data into the bulk endpoint */
retval = usb_bulk_msg(device, usb_sndbulkpipe(device, BULK_EP_OUT),
bulk_buf, MIN(cnt, MAX_PKT_SIZE), &wrote_cnt, 5000);
if (retval)
{
printk(KERN_ERR "Bulk message returned %d\n", retval);
return retval;
}
return wrote_cnt;
}
static struct file_operations fops =
{
.open = pen_open,
.release = pen_close,
.read = pen_read,
.write = pen_write,
};
static int pen_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
int retval;
device = interface_to_usbdev(interface);
class.name = "usb/pen%d";
class.fops = &fops;
if ((retval = usb_register_dev(interface, &class)) < 0)
{
/* Something prevented us from registering this driver */
err("Not able to get a minor for this device.");
}
else
{
printk(KERN_INFO "Minor obtained: %d\n", interface->minor);
}
return retval;
}
static void pen_disconnect(struct usb_interface *interface)
{
usb_deregister_dev(interface, &class);
}
/* Table of devices that work with this driver */
static struct usb_device_id pen_table[] =
{
{ USB_DEVICE(0x058F, 0x6387) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, pen_table);
static struct usb_driver pen_driver =
{
.name = "pen_driver",
.probe = pen_probe,
.disconnect = pen_disconnect,
.id_table = pen_table,
};
static int __init pen_init(void)
{
int result;
/* Register this driver with the USB subsystem */
if ((result = usb_register(&pen_driver)))
{
err("usb_register failed. Error number %d", result);
}
return result;
}
static void __exit pen_exit(void)
{
/* Deregister this driver with the USB subsystem */
usb_deregister(&pen_driver);
}
module_init(pen_init);
module_exit(pen_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <email_at_sarika-pugs_dot_com>");
MODULE_DESCRIPTION("USB Pen Device Driver");
There could be many possible reasons for this error but in my case it happened that the BULK_EP address was wrong. I recommend setting up your endpoint addresses in the probe function rather than hard-coding them. Feel free to refer the below code to setup bulk endpoint addresses.
static void
set_bulk_address (
struct my_device *dev,
struct usb_interface *interface)
{
struct usb_endpoint_descriptor *endpoint;
struct usb_host_interface *iface_desc;
int i;
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
/* check for bulk endpoint */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK){
/* bulk in */
if(endpoint->bEndpointAddress & USB_DIR_IN) {
dev->bulk_in_add = endpoint->bEndpointAddress;
dev->bulk_in_size = endpoint->wMaxPacketSize;
dev->bulk_in_buffer = kmalloc(dev->bulk_in_size,
GFP_KERNEL);
if (!dev->bulk_in_buffer)
print("Could not allocate bulk buffer");
}
/* bulk out */
else
dev->bulk_out_add = endpoint->bEndpointAddress;
}
}
}
As you may notice, I have defined my own device struct to hold the endpoint information. Here is my struct definition
struct my_device {
struct usb_device *udev; /* usb device for this device */
struct usb_interface *interface; /* interface for this device */
unsigned char minor; /* minor value */
unsigned char * bulk_in_buffer; /* the buffer to in data */
size_t bulk_in_size; /* the size of the in buffer */
__u8 bulk_in_add; /* bulk in endpoint address */
__u8 bulk_out_add; /* bulk out endpoint address */
struct kref kref; /* module references counter */
};
The error is coming because you have to mention the correct bulk endpoints as per your usb device not the ones given in the example code.
For that you can either check /sys/kernel/debug/usb/devices file or /proc/bus/usb/devices.
In the file check the section containing your device's vendorId and productId and in that section check the E segment for endpoints.
In that segment the one with (I) will be BULK_EP_IN value and the one with (O) will be the value for BULK_EP_OUT.
I want to write a virtual sound card driver that shall be used by the linux system for audio playback and capture. The driver shall use a buffer for audio data read/write. I have written the following basic driver:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sound.h>
#include <linux/sysctl.h>
#include <linux/device.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/gfp.h>
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/err.h>
#include <sound/core.h>
static char* mod_name = "prosip";
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.1111");
MODULE_AUTHOR("DD-DDD");
MODULE_DESCRIPTION("proSip Virtual Sound Card");
//
static int ver_major = 133;
static int ver_minor = 3;
//
static int buffer_size = 0;
static char* buffer;
static int read_count = 0;
/* Declaration of memory.c functions */
int prosip_open(struct inode *inode, struct file *filp);
int prosip_release(struct inode *inode, struct file *filp);
//
ssize_t prosip_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t prosip_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
//
int prosip_ioctl(struct inode *inode,struct file *file,unsigned int ioctl_num,unsigned long ioctl_param);
//
static int __init prosip_init(void);
static void __exit prosip_exit(void);
/* Structure that declares the usual file access functions */
struct file_operations sound_fops =
{
owner:
THIS_MODULE,
read:
prosip_read,
write:
prosip_write,
open:
prosip_open,
release:
prosip_release,
ioctl:
prosip_ioctl
};
/* Declaration of the init and exit functions */
module_init(prosip_init);
module_exit(prosip_exit);
static int __init prosip_init(void)
{
int ret = -1;
buffer_size = 0;
printk("<1>[prosip] Init...!\n");
ret = register_sound_dsp(&sound_fops, ver_minor);
if(ret < 0)
{
printk("<1> [prosip] Registration failure\n");
//
return ret;
}
else
{
ver_minor = ret;
//
printk("<1> [prosip] DSP Registered succesfully with id %d\n", ret);
}
buffer = kmalloc(101, GFP_KERNEL);
if(buffer == 0)
{
printk("<1>[prosip] Failed to allocate buffer !!!\n");
//
return -ENOMEM;
}
//
return 0;
}
static void __exit prosip_exit(void)
{
printk("<1> [prosip] Sound Exit...\n");
unregister_sound_special(ver_minor);
if(buffer)
{
kfree(buffer);
}
}
/* Declaration of memory.c functions */
int prosip_open(struct inode *inode, struct file *filp)
{
printk("<1> [prosip] Sound Open... \n");
try_module_get(THIS_MODULE);
return 0;
}
//
int prosip_release(struct inode *inode, struct file *filp)
{
printk("<1> [MySound] Sound Release... \n");
module_put(THIS_MODULE);
return 0;
}
//
ssize_t prosip_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
printk("<1> [prosip] Sound read...\n");
printk("<1> [prosip] Writing Count: %d\n", count);
if(buffer == 0)
{
printk("<1> NULL buffer!!! Unable to read");
return 0;
}
//
count = buffer_size;
if(read_count == 0)
{
read_count = buffer_size;
}
else
{
read_count = 0;
}
copy_to_user(buf, buffer, buffer_size);
printk("<1> [prosip] Buffer: %s, buf: %s, Count: %d\n", buffer, buf, count);
return read_count;
}
//
ssize_t prosip_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
printk("<1> [prosip] Sound write...!\n");
printk("<1> [prosip] Writing Count: %d\n", count);
//
if(buffer == 0)
{
printk("<1> NULL buffer!!! Unable to write");
return 0;
}
copy_from_user(buffer, buf, count);
buffer[count] = 0;
buffer_size = count;
printk("<1> [MySound] Writing Buffer: %s, Count: %d\n", buffer, count);
return count;
}
/*
* This function is called whenever a process tries to do an ioctl on our
* device file.
*
*/
int prosip_ioctl(struct inode *inode,
struct file *file,
unsigned int ioctl_num,
unsigned long ioctl_param)
{
//
return 0;
}
insmoding this module creates a driver at /dev/dsp. Also it is found in /sys/devices/virtual/sound/dsp/, so it is recognised by the system as a virtual audio driver.
I am not yet able to choose this device for playback and capture from applications. What else do I need to do to make this driver enumerated by audio applications?
Well /dev/dsp was the device node used for a sound card under the old OSS sound system in linux but these days pretty much everything will default to looking for devices based on the newer ALSA sound system.
Some software still supports OSS but you may well need to give it special options, or change the configuration, to tell it to use OSS instead of ALSA.
ALSA devices are found under /dev/snd and aren't normally accessed directly, as they are more complicated than the old OSS devices. Instead libasound is normally used to interact with them.