I have read many posts about this same topic, but I am unable to find out what is exactly wrong with my sysfs implementation in my kernel module. I am trying to make a userspace program block on a poll untill the value changes in a sysfs file. Most people seem to not get blocking, I seem to not be able to get out of my blocking. Here is the relevent code:
kernel module:
static int sysfs_test = 88;
static ssize_t test_interrupts_show(struct device* dev, struct device_attribute* attr, const char* buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", sysfs_test);
}
static ssize_t test_interrupts_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count)
{
kstrtol(buf, 10, &sysfs_test);
return count;
}
static DEVICE_ATTR(interrupts, S_IWUSR | S_IRUGO, test_interrupts_show, test_interrupts_store);
static int __init test_init(void)
{
int result;
if(dev_major)
{
dev = MKDEV(dev_major, dev_minor);
result = register_chrdev_region(dev, NUM_DEVICES, name);
} else {
result = alloc_chrdev_region(&dev, dev_minor, NUM_DEVICES, name);
dev_major = MAJOR(dev);
dev_minor = MINOR(dev);
}
if(result < 0) {
printk(KERN_WARNING "%s: can't get major %d\n", name, dev_major);
return -1;
}
printk(KERN_NOTICE "%s: Major = %d, Minor = %d\n", name, dev_major, dev_minor);
// Register as character device
test_cdev = cdev_alloc();
cdev_init(cajun_cdev, &test_fops); // Initialize cdev structure
test_cdev->owner = THIS_MODULE; // Add owner
result = cdev_add(test_cdev, dev,1); // Tell kernel about our device
if(result)
{
printk(KERN_NOTICE "Error %d adding cdev\n", result);
goto OUT2;
}
// This stuff relates to sysfs:
ctest_class = class_create(THIS_MODULE, NAME);
if(IS_ERR(test_class))
{
printk(KERN_ALERT "Failed to register device class\n");
goto OUT2;
}
test_device = device_create(test_class, NULL, dev, NULL, NAME);
if(IS_ERR(test_device))
{
printk(KERN_ALERT "Failed to create device\n");
goto OUT3;
}
result = device_create_file(test_device, &dev_attr_interrupts);
if (result < 0)
{
printk(KERN_ALERT "failed\n");
}
OUT3:
class_unregister(test_class);
class_destroy(test_class);
OUT2:
cdev_del(test_cdev);
OUT1:
unregister_chrdev_region(dev, NUM_DEVICES);
return -1;
}
Relevent userspace code:
char interrupts_path[] = "/sys/class/test_module/test_module/interrupts";
int main()
{
struct pollfd fds;
fds.fd = open(interrupts_path, O_RDWR | O_SYNC);
char dummy_buff[1];
read(fds.fd, dummy_buff, 1);
lseek(fds.fd, 0, SEEK_SET);
fds.events = POLLPRI;
printf("Polling for interrupt\n");
poll(&fds,1,-1);
printf("Interrupt occured\n");
return 0;
}
I run my userspace code in the background (./test &) and then I echo a new value into the sysfs file for interrupts. I am hopping for my userspace program to unblock and return when the value changes. What am I doing wrong here?
edit:
struct file_operations test_fops = {
.owner = THIS_MODULE,
.llseek = test_llseek,
.read = test_read,
.write = test_write,
.unlocked_ioctl = test_ioctl,
.open = test_open,
.release = test_release
};
Related
I'm trying to use GPT to measuring frequency on a gpio. After some research on the google and Linux's documentation, unfortunately I couldn't see any compatible GPT driver in kernel. I found a patch on google and applied it. But I have a getting clock error now. There is a function which It gets the clock but it's never executing.
P.S : I prepared a platform driver to use exported functions (e.g. mxc_request_input_capture) in timer-imx-gpt.c.
My dts nodes
/*These nodes are child node if aips1*/
gpt1: gpt#302d0000 {
compatible = "fsl,imx8mm-gpt";
reg = <0x302d0000 0x10000>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MM_CLK_GPT1>,
<&clk IMX8MM_CLK_GPT1_ROOT>,
<&clk IMX8MM_CLK_GPT_3M>;
clock-names = "ipg", "per", "osc_per";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpt_input_capture0>;
status = "okay";
};
iomuxc: pinctrl#30330000 {
compatible = "fsl,imx8mm-iomuxc";
reg = <0x30330000 0x10000>;
pinctrl_gpt_input_capture0: gptinputcapture0grp {
fsl,pins = <
MX8MM_IOMUXC_SAI3_RXFS_GPT1_CAPTURE1 0xd6 /*0x00000000*/
>;
};
};
request gpt input capture func (in timer-imx-gpt.c)
int mxc_request_input_capture(unsigned int chan, mxc_icap_handler_t handler,
unsigned long capflags, void *dev_id)
{
struct imx_timer *imxtm;
struct icap_channel *ic;
unsigned long flags;
u64 start_cycles;
int ret = 0;
u32 mode;
/* we only care about rising and falling flags */
capflags &= (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
if (chan > 1 || !handler || !capflags)
return -EINVAL;
printk("mxc_request_input_capture 1\n");
ic = &icap_channel_arr[chan];
imxtm = ic->imxtm;
printk("mxc_request_input_capture 2\n");
if (!imxtm->gpt->gpt_ic_enable)
return -ENODEV; //THIS ERROR CODE RETURN
printk("mxc_request_input_capture 3\n");
spin_lock_irqsave(&icap_lock, flags);
if (ic->handler) {
ret = -EBUSY;
goto out;
}
printk("mxc_request_input_capture 4\n");
ic->handler = handler;
ic->dev_id = dev_id;
switch (capflags) {
case IRQF_TRIGGER_RISING:
mode = V2_IM_RISING;
break;
case IRQF_TRIGGER_FALLING:
mode = V2_IM_FALLING;
break;
default:
mode = V2_IM_BOTH;
break;
}
printk("mxc_request_input_capture 4\n");
/* ack any pending input capture interrupt before enabling */
imxtm->gpt->gpt_ic_irq_acknowledge(ic);
/*
* initialize the cyclecounter. The input capture is capturing
* from the mxc clocksource, so it has the same mask/shift/mult.
*/
memset(&ic->cc, 0, sizeof(ic->cc));
ic->cc.read = gpt_ic_read;
ic->cc.mask = clocksource_mxc.mask;
ic->cc.shift = clocksource_mxc.shift;
ic->cc.mult = clocksource_mxc.mult;
printk("mxc_request_input_capture 5\n");
/* initialize a timecounter for the input capture */
start_cycles = mxc_read_sched_clock();
timecounter_init(&ic->tc, &ic->cc, ktime_get_ns());
printk("mxc_request_input_capture 6\n");
/*
* timecounter_init() read the last captured timer count, but
* that's not the start cycle counter, so update it with the
* real start cycles.
*/
ic->tc.cycle_last = start_cycles;
imxtm->gpt->gpt_ic_enable(ic, mode);
imxtm->gpt->gpt_ic_irq_enable(ic);
printk("mxc_request_input_capture 7\n");
out:
spin_unlock_irqrestore(&icap_lock, flags);
printk("mxc_request_input_capture 8\n");
return ret;
}
EXPORT_SYMBOL_GPL(mxc_request_input_capture);
I realized that imxtm->gpt->gpt_ic_enable variable seems NULL. imxtm structure gets filled in the end of static int __init _mxc_timer_init function. But the function returns error before filling the struct. The error is happening checking the clock. The function which related to getting clock is mxc_timer_init_dt but it never executes.
log:
root:~# dmesg | grep gpt
[ 0.000174] gpt imx6dl_timer_init_dt HEAD
[ 0.000240] gpt _mxc_timer_init
[ 0.000244] gpt imxtm->type 3
[ 0.000249] gpt imxtm->type GPT_TYPE_IMX6DL
[ 0.000252] imx-gpt is NOT null
[ 0.000260] gpt GPT_TYPE_IMX6DL 3
[ 0.000263] gpt mxc_timer_init_dt error -517
[ 16.837810] mxc-timer 302d0000.gpt: GPT Timer Probe Function head
[ 16.843920] mxc-timer 302d0000.gpt: GPT Timer Probe Function end
It start with executing imx6dl_timer_init_dt. mxc_timer_init_dt function must be execute after imx6dl_timer_init_dt to get the clock but it is not executing. Due to failing on getting clock, I am not able to use the gpt module.
some parts of timer-imx-gpt.c
static int __init _mxc_timer_init(struct imx_timer *imxtm)
{
struct icap_channel *ic;
int i, ret;
printk(KERN_INFO "gpt _mxc_timer_init\n");
printk(KERN_INFO "gpt imxtm->type %d \n", imxtm->type);
switch (imxtm->type) {
case GPT_TYPE_IMX1:
imxtm->gpt = &imx1_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX1 \n");
break;
case GPT_TYPE_IMX21:
imxtm->gpt = &imx21_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX21 \n");
break;
case GPT_TYPE_IMX31:
imxtm->gpt = &imx31_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX31 \n");
break;
case GPT_TYPE_IMX6DL:
imxtm->gpt = &imx6dl_gpt_data;
printk(KERN_INFO "gpt imxtm->type GPT_TYPE_IMX6DL \n");
break;
default:
printk(KERN_INFO "gpt imxtm->type DEFAULT \n");
return -EINVAL;
}
imxtm->gpt = &imx6dl_gpt_data;
if(!imxtm->gpt)
printk(KERN_INFO "imx-gpt is null");
printk(KERN_INFO "imx-gpt is NOT null");
if (IS_ERR(imxtm->clk_per)) {
pr_err("i.MX timer: unable to get clk\n"); //I SAW THIS LOG IN LINUX LOGS
return PTR_ERR(imxtm->clk_per); //Function return error at this line
}
printk(KERN_INFO "gpt clk_per success\n");
if (!IS_ERR(imxtm->clk_ipg))
clk_prepare_enable(imxtm->clk_ipg);
printk(KERN_INFO "gpt clk_ipg success\n");
clk_prepare_enable(imxtm->clk_per);
printk(KERN_INFO "gpt clk_prepare_enable\n");
/*
* Initialise to a known state (all timers off, and timing reset)
*/
writel_relaxed(0, imxtm->base + MXC_TCTL);
writel_relaxed(0, imxtm->base + MXC_TPRER); /* see datasheet note */
imxtm->gpt->gpt_oc_setup_tctl(imxtm);
/* init and register the timer to the framework */
ret = mxc_clocksource_init(imxtm);
if (ret)
return ret;
ret = mxc_clockevent_init(imxtm);
if (ret)
return ret;
/*Filling the imx structure. But never reach here*/
for (i = 0; i < 2; i++) {
ic = &icap_channel_arr[i];
ic->imxtm = imxtm;
}
printk(KERN_INFO, "_mxc_timer_init RETURN SUCCESS\n");
return 0;
}
void __init mxc_timer_init(unsigned long pbase, int irq, enum imx_gpt_type type)
{
struct imx_timer *imxtm;
printk(KERN_INFO, "gpt mxc_timer_init HEAD\n");
imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
BUG_ON(!imxtm);
imxtm->clk_per = clk_get_sys("imx-gpt.0", "per");
imxtm->clk_ipg = clk_get_sys("imx-gpt.0", "ipg");
imxtm->base = ioremap(pbase, SZ_4K);
BUG_ON(!imxtm->base);
imxtm->type = type;
imxtm->irq = irq;
_mxc_timer_init(imxtm);
}
/*
* a platform driver is needed in order to acquire pinmux
* for input capture pins. The probe call is also useful
* for setting up the input capture channel structures.
*/
static int mxc_timer_probe(struct platform_device *pdev)
{
struct icap_channel *ic;
int i;
dev_info(&pdev->dev, "GPT Timer Probe Function head\n");
/* setup the input capture channels */
for (i = 0; i < 2; i++) {
ic = &icap_channel_arr[i];
ic->chan = i;
if (i == 0) {
ic->cnt_reg = V2_TCAP1;
ic->irqen_bit = V2_IR_IF1;
ic->status_bit = V2_TSTAT_IF1;
ic->mode_bit = V2_TCTL_IM1_BIT;
} else {
ic->cnt_reg = V2_TCAP2;
ic->irqen_bit = V2_IR_IF2;
ic->status_bit = V2_TSTAT_IF2;
ic->mode_bit = V2_TCTL_IM2_BIT;
}
}
dev_info(&pdev->dev, "GPT Timer Probe Function end\n");
return 0;
}
static int mxc_timer_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id timer_of_match[] = {
{ .compatible = "fsl,imx1-gpt" },
{ .compatible = "fsl,imx21-gpt" },
{ .compatible = "fsl,imx27-gpt" },
{ .compatible = "fsl,imx31-gpt" },
{ .compatible = "fsl,imx25-gpt" },
{ .compatible = "fsl,imx50-gpt" },
{ .compatible = "fsl,imx51-gpt" },
{ .compatible = "fsl,imx53-gpt" },
{ .compatible = "fsl,imx6q-gpt" },
{ .compatible = "fsl,imx6dl-gpt" },
{ .compatible = "fsl,imx6sl-gpt" },
{ .compatible = "fsl,imx6sx-gpt" },
{ .compatible = "fsl,imx8mm-gpt" },
{ },
};
MODULE_DEVICE_TABLE(of, timer_of_match);
static struct platform_driver mxc_timer_pdrv = {
.probe = mxc_timer_probe,
.remove = mxc_timer_remove,
.driver = {
.name = "mxc-timer",
.owner = THIS_MODULE,
.of_match_table = timer_of_match,
},
};
module_platform_driver(mxc_timer_pdrv);
static int __init mxc_timer_init_dt(struct device_node *np, enum imx_gpt_type type)
{
struct imx_timer *imxtm;
static int initialized;
int ret;
printk(KERN_INFO, "gpt mxc_timer_init_dt head\n");
/* Support one instance only */
if (initialized)
return 0;
imxtm = kzalloc(sizeof(*imxtm), GFP_KERNEL);
if (!imxtm)
return -ENOMEM;
imxtm->base = of_iomap(np, 0);
if (!imxtm->base)
return -ENXIO;
imxtm->irq = irq_of_parse_and_map(np, 0);
if (imxtm->irq <= 0)
return -EINVAL;
imxtm->clk_ipg = of_clk_get_by_name(np, "ipg");
/* Try osc_per first, and fall back to per otherwise */
imxtm->clk_per = of_clk_get_by_name(np, "osc_per");
if (IS_ERR(imxtm->clk_per))
imxtm->clk_per = of_clk_get_by_name(np, "per");
imxtm->type = type;
printk(KERN_INFO, "gpt mxc_timer_init_dt line 883\n");
ret = _mxc_timer_init(imxtm);
if (ret)
return ret;
initialized = 1;
printk(KERN_INFO, "gpt mxc_timer_init_dt end\n");
return 0;
}
static int __init imx1_timer_init_dt(struct device_node *np)
{
return mxc_timer_init_dt(np, GPT_TYPE_IMX1);
}
static int __init imx21_timer_init_dt(struct device_node *np)
{
return mxc_timer_init_dt(np, GPT_TYPE_IMX21);
}
static int __init imx31_timer_init_dt(struct device_node *np)
{
enum imx_gpt_type type = GPT_TYPE_IMX31;
printk(KERN_INFO "gpt imx31_timer_init_dt HEAD");
/*
* We were using the same compatible string for i.MX6Q/D and i.MX6DL/S
* GPT device, while they actually have different programming model.
* This is a workaround to keep the existing i.MX6DL/S DTBs continue
* working with the new kernel.
*/
if (of_machine_is_compatible("fsl,imx6dl"))
type = GPT_TYPE_IMX6DL;
return mxc_timer_init_dt(np, type);
}
static int __init imx6dl_timer_init_dt(struct device_node *np)
{
printk(KERN_INFO "gpt imx6dl_timer_init_dt HEAD");
return mxc_timer_init_dt(np, GPT_TYPE_IMX6DL); //This function must execute to get clock
}
TIMER_OF_DECLARE(imx1_timer, "fsl,imx1-gpt", imx1_timer_init_dt);
TIMER_OF_DECLARE(imx21_timer, "fsl,imx21-gpt", imx21_timer_init_dt);
TIMER_OF_DECLARE(imx27_timer, "fsl,imx27-gpt", imx21_timer_init_dt);
TIMER_OF_DECLARE(imx31_timer, "fsl,imx31-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx25_timer, "fsl,imx25-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx50_timer, "fsl,imx50-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx51_timer, "fsl,imx51-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx53_timer, "fsl,imx53-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx6q_timer, "fsl,imx6q-gpt", imx31_timer_init_dt);
TIMER_OF_DECLARE(imx6dl_timer, "fsl,imx6dl-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx6sl_timer, "fsl,imx6sl-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx6sx_timer, "fsl,imx6sx-gpt", imx6dl_timer_init_dt);
TIMER_OF_DECLARE(imx8mm_timer, "fsl,imx8mm-gpt", imx6dl_timer_init_dt); //This line added after applying patch
I will be very grateful for your help
This is my first time writing a Linux kernel driver. After looking for examples online, I started to write my driver. The driver is getting initialized but the ->probe() function is not revoked. I have attached below my C code and the relevant device tree node code snippets.
Can you please help and let me know what changes should I make?
DTS file:
ubv#96002000 {
compatible = "ubv";
no-map;
reg = <0 0x96002000 0 0x0002000>;
};
Driver C code:
static int ubv_probe(struct platform_device *pdev)
{
printk (KERN_ALERT "%s\n", __FUNCTION__);
pr_info("---------------%s\n", __func__);
return 0;
}
static int ubv_remove(struct platform_device *pdev)
{
pr_info("------------------- %s\n", __func__);
return 0;
}
static struct of_device_id ubv_match_table[] = {
{ .compatible = "ubv" },
{}
};
static struct platform_device_id ubv_plat_device_ids[] = {
{ .name = "ubv" },
{}
};
static struct platform_driver ubv_platform_driver = {
.probe = ubv_probe,
.remove = ubv_remove,
.id_table = ubv_plat_device_ids,
.driver = {
.name = "ubv",
.owner = THIS_MODULE,
.of_match_table = ubv_match_table,
},
};
static int __init ubv_init(void)
{
int ret;
printk (KERN_ALERT "%s\n", __FUNCTION__);
ret = platform_driver_probe(&ubv_platform_driver, ubv_probe);
printk (KERN_ALERT "ret = %d\n", ret);
pr_info("ret = %d\n", ret);
return ret;
}
static void __exit ubv_exit(void)
{
platform_driver_unregister(&ubv_platform_driver);
}
module_init(ubv_init);
module_exit(ubv_exit);
In linux kernel if we have a pointer to "struct gendisk" of a disk, then how can we read a known sector number from the disk.
These functions helped me. I used submit_bio and submitted a bio to the disk. The major and minor shall be assumed as input to read_sector_thread_func
static struct bio * my_mpage_alloc(struct block_device *bdev,
sector_t first_sector, int nr_vecs,
gfp_t gfp_flags)
{
struct bio *bio;
bio = my_bio_alloc(gfp_flags, nr_vecs);
if (bio == NULL && (current->flags & PF_MEMALLOC)) {
while (!bio && (nr_vecs /= 2))
bio = my_bio_alloc(gfp_flags, nr_vecs);
}
if (bio) {
//bio->bi_bdev = bdev;
bio->bi_iter.bi_sector = first_sector;
}
return bio;
}
static void src_endio(struct bio *bio)
{
if (bio->bi_private) {
complete(bio->bi_private);
}
return;
}
static int read_sector_thread_func(void *data)
{
struct block_device *r_bdev = NULL;
struct bio *r_bio = NULL;
struct page *page = NULL;
int part = NULL;
int len = 0;
struct gendisk * disk = NULL;
unsigned char * addr;
u64 first_sector_num = 0;
disk = get_gendisk(MKDEV(global_dev_major, global_dev_minor), &part);
DECLARE_COMPLETION_ONSTACK(r_wait);
page = alloc_pages(GFP_ATOMIC, 0);
printk("%d : %s ", __LINE__, __func__);
r_bio = my_mpage_alloc(r_bdev, first_sector_num, 1, GFP_ATOMIC);
if(r_bio==NULL)
{
printk("bio is NULL");
return;
}
bio_add_page(r_bio, page, 512, 0);
r_bio->bi_private = &r_wait;
r_bio->bi_end_io = src_endio;
r_bio->bi_disk = disk;
bio_associate_blkg(r_bio);
bio_get(r_bio);
bio_set_op_attrs(r_bio, REQ_OP_READ, 0);
submit_bio(r_bio);
wait_for_completion_io(&r_wait);
bio_put(r_bio);
return 0;
}
I have written a simple GPIO sysfs driver. However, my driver is crashing when I call rmmod. I don't know what I am missing. I am suspecting that my probe() function is causing this issue. I am using kernel 4.19 version. Here is my long code:
struct of_device_id gpio_sysfs_dt_match[] = {
{ .compatible = "org,bone-gpio-sysfs" },
{ } // NULL terminated
};
ssize_t direction_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return 0;
}
ssize_t direction_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
return 0;
}
ssize_t value_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return 0;
}
ssize_t value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
return 0;
}
ssize_t label_show(struct device *dev, struct device_attribute *attr, char *buf)
{
return 0;
}
static DEVICE_ATTR_RW(direction);
static DEVICE_ATTR_RW(value);
static DEVICE_ATTR_RO(label);
static struct attribute *gpio_attrs[] = {
&dev_attr_direction.attr,
&dev_attr_value.attr,
&dev_attr_label.attr,
NULL
};
static struct attribute_group gpio_group = {
.attrs = gpio_attrs,
};
const struct attribute_group *gpio_attr_groups[] =
{
&gpio_group,
NULL
};
int gpio_sysfs_platform_driver_probe (struct platform_device *pDev)
{
struct device_node *parent = pDev->dev.of_node;
struct device_node *child;
struct gpiodev_private_data *dev_data;
struct device dev = pDev->dev;
const char *name;
int i = 0;
int ret;
gpiodrv_data.total_devices = of_get_child_count(parent);
if (!gpiodrv_data.total_devices) {
dev_err(&dev, "Error - No devices found\r\n");
return -EINVAL;
}
dev_info(&dev, "child count = %d\r\n", gpiodrv_data.total_devices);
gpiodrv_data.dev_sysfs = devm_kzalloc(&pDev->dev, sizeof(struct device *) * gpiodrv_data.total_devices, GFP_KERNEL);
for_each_available_child_of_node(parent, child) {
dev_data = devm_kzalloc(&dev, sizeof(struct gpiodev_private_data),GFP_KERNEL);
if (!dev_data) {
pr_err("No memory \r\n");
return -ENOMEM;
}
if (of_property_read_string(child, "label", &name)) {
pr_err("Missing label \r\n");
snprintf(dev_data->label,sizeof(dev_data->label), "unknown-gpio-%d",i);
} else {
strcpy(dev_data->label, name);
dev_info(&dev,"GPIO label = %s\n",dev_data->label);
}
dev_data->desc = devm_fwnode_get_gpiod_from_child(&dev,"bone",&child->fwnode, GPIOD_ASIS, dev_data->label);
if (IS_ERR(dev_data->desc)) {
ret = PTR_ERR(dev_data->desc);
if(ret == -ENONET) {
dev_err(&dev, "get gpiod failed - no entry found\r\n");
}
return ret;
}
/** gpio/gpio.txt **/
ret = gpiod_direction_output(dev_data->desc, 0);
if(ret) {
dev_err(&dev,"Err setting gpio direction failed = %d\r\n",i);
return ret;
}
gpiodrv_data.dev_sysfs[i] = device_create_with_groups(gpiodrv_data.class_gpio, &dev, 0, dev_data, gpio_attr_groups, dev_data->label);
if(IS_ERR(gpiodrv_data.dev_sysfs[i])) {
ret = PTR_ERR(gpiodrv_data.dev_sysfs[i]);
dev_err(&dev, "Error creating device with groups \r\n");
return ret;
}
i++;
}
return 0;
}
int gpio_sysfs_driver_remove(struct platform_device *pDev)
{
int i = 0;
dev_info(&pDev->dev, "Removing gpio syfs driver\r\n");
for (i = 0; i < gpiodrv_data.total_devices; i++) {
device_unregister(gpiodrv_data.dev_sysfs[i]);
}
return 0;
}
struct platform_driver gpiosysfs_platform_driver = {
.probe = gpio_sysfs_platform_driver_probe,
.remove = gpio_sysfs_driver_remove,
.driver = {
.name = "bone-gpio-sysfs",
. of_match_table = of_match_ptr(gpio_sysfs_dt_match),
},
};
/**Entry Point of the Kernel Module **/
/** Called when the module is inserted -insmod **/
static int __init gpio_sysfs_init(void)
{
int ret;
gpiodrv_data.class_gpio = class_create(THIS_MODULE, "bone_gpios");
ret = platform_driver_register(&gpiosysfs_platform_driver);
return ret;
}
/** Called when the module is removed - rmmod**/
static void __exit gpio_sysfs_exit(void)
{
platform_driver_unregister(&gpiosysfs_platform_driver);
class_destroy(gpiodrv_data.class_gpio);
pr_info("module unloaded\n");
}
The problem is seen when I call rmmod of my driver. When I do this, I see a kernel crash - pointing to the platform driver unregister. What am I doing wrong here? If I comment out probe then I don't see this problem. Perhaps, some problem is introduced inside probe. As you can see I am using managed resource API so I guess, I don't have to call kfree() since I am using dev_kzalloc().
I'm developing with a PowerPC 405 embedded in a Virtex4 FPGA with Linux kernel 2.6.33.
Up until now, I've been writing drivers for platform devices implemented in the FPGA in the form of kernel loadable modules. The devices are registered using the flat Open Firmware Device Tree file. To create a device file, I use the OF functions to get the device node, and then register a new miscdevice which then automatically registers a minor device number and creates the device file for me. This also creates a device that is embedded in the miscdevice (i.e. miscdevice.this_device)
The problem is now I need to perform DMA operations. I tried to call the dma_alloc_coherent() function using the miscdevice.this_device, but this device isn't associated with any bus and always returns an error. I did some digging around and it turns out that the struct of_device also has a struct device embedded in it (i.e. of_device.dev). When I tried using this with dma_alloc_coherent(), it worked just fine.
So now I have two different struct device structures, one to manage my character device file, and one to manage the underlying Open Firmware system calls, the bus and DMA transactions. These devices are not associated with each other in the sysfs of course.
My question is, is it possible to somehow request that a device file be created for the device structure I get from the OF layer and not create a new device with the Misc Device API? That way everything will be associated with a single device structure.
I think your fix about dma_alloc_coherent() is correct.
But I don't think it's not right to use the device structure embedded in structure of_device to replace the miscdevice you created. The of_device is description of objects in Open Firmware database. And according to Linux device driver model, device structure is embedded in various device objects in Linux Kernel. And I think you registe miscdevice as one character device, there should be file_operations structure associated.
In one word, they are different views, and they can not replace each other.
I wrote some experimental dma driver using miscdevice.this_device for raspberry pi
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/miscdevice.h>
#include "gpio.h"
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include "DMA.h"
#include <linux/of_irq.h>
static int my_open(struct inode *i, struct file *f)
{
printk(KERN_INFO "Driver: open() %d\n", current->pid);
return 0;
}
static int my_close(struct inode *i, struct file *f)
{
printk(KERN_INFO "Driver: close()\n");
return 0;
}
static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Driver: read()\n");
return 0;
}
char databuf[100];
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
if(copy_from_user(databuf, buf, 100) != 0) return 0;
printk("Data from the user: %s\n", databuf);
return len;
}
static struct file_operations sample_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write
};
struct miscdevice sample_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ledButton",
.fops = &sample_fops,
.mode = 0666,
};
//static struct dmadata_s *cpu_addr;
//dma_addr_t dma_addr;
struct dma_cb *virt_cb;
dma_addr_t phys_cb;
uint32_t *virt_src;
dma_addr_t phys_src;
uint32_t *virt_dst;
dma_addr_t phys_dst;
static irqreturn_t dma_irq_fn(int irq, void *dev_id)
{
printk("destAddr %u\n", *virt_dst);
dma_regs->CS.INT = 1;
return IRQ_HANDLED;
}
static struct device *dev;
int IRQ_DMA0;
static int __init ofcd_init(void) /* Constructor */
{
int error, mret;
struct device_node * np = NULL;
error = misc_register(&sample_device);
if (error) {
pr_err("can't misc_register :(\n");
return error;
}
dev = sample_device.this_device;
dev->coherent_dma_mask = ~0;
dev->dma_mask = &dev->coherent_dma_mask;
// dev_set_name(dev, "mydmadev");
// cpu_addr = (struct dmadata_s*)kmalloc(sizeof(struct dmadata_s), GFP_KERNEL | GFP_DMA);
//dma_addr = dma_map_single(dev, cpu_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
virt_cb = dma_alloc_coherent(dev, 32, &phys_cb, GFP_KERNEL | GFP_DMA);
if(virt_cb == 0 || phys_cb == 0){
printk("DMA cb error\n");
}
virt_src = dma_alloc_coherent(dev, 4, &phys_src, GFP_KERNEL | GFP_DMA);
if(virt_src == 0 || phys_src == 0){
printk("DMA src error\n");
}
virt_dst = dma_alloc_coherent(dev, 4, &phys_dst, GFP_KERNEL | GFP_DMA);
if(virt_dst == 0 || phys_dst == 0){
printk("DMA dst error\n");
}
memset(virt_cb, 0, sizeof(*virt_cb));
dma_regs = (struct dma_ch *)ioremap(DMA_BASE, sizeof(struct dma_ch));
// strcpy(cpu_addr->srcAddr, "DMA0");
*virt_src = 200;
virt_cb->TI.SRC_INC = 1;
virt_cb->TI.DEST_INC = 1;
virt_cb->TI.INTEN = 1;
virt_cb->SOURCE_AD = (uint32_t)phys_src;
virt_cb->DEST_AD = (uint32_t)phys_dst;
virt_cb->TXFR_LEN = 4;
virt_cb->reserved[0] = 0;
virt_cb->reserved[1] = 0;
printk("srcAddr %u\n", *virt_src);
printk("destAddr %u\n", *virt_dst);
//dma_regs->CS = (DMA_CS_t){.RESET = 1, .END = 1};
dma_regs->CS.RESET = 1;
udelay(10);
// dma_regs->CS = (DMA_CS_t){.END = 1, .INT = 1};
dma_regs->CS.INT = 1;
dma_regs->CS.END = 1;
dma_regs->CONBLK_AD = (uint32_t)phys_cb;
//dma_regs->DEBUG = (DMA_DEBUG_t){.READ_LAST_NOT_SET_ERROR = 1, .FIFO_ERROR = 1, .READ_ERROR = 1};
dma_regs->DEBUG.READ_LAST_NOT_SET_ERROR = 1;
dma_regs->DEBUG.FIFO_ERROR = 1;
dma_regs->DEBUG.READ_ERROR =1;
udelay(10);
// dma_regs->CS = (DMA_CS_t){.RESET = 1, .PRIORITY = 8, .PANIC_PRIORITY = 8, .ACTIVE = 1};
dma_regs->CS.RESET = 1;
udelay(10);
dma_regs->CS.PRIORITY = 8;
dma_regs->CS.PANIC_PRIORITY = 8;
dma_regs->CS.ACTIVE = 1;
if(dma_regs->CS.ERROR) printk("ERROR %d %d\n", dma_regs->CS.ACTIVE, dma_regs->CS.PANIC_PRIORITY);
//np = of_find_compatible_node(NULL,NULL,"brcm,bcm2835-system-timer");
np = of_find_node_by_path("/soc/dma#7e007000");
if (np == NULL){
printk("Error node not found\n");
}
// printk("node name %s\n", np->name);
IRQ_DMA0 = irq_of_parse_and_map(np, 0);
if (IRQ_DMA0 <= 0) {
printk("Can't parse IRQ\n");
}
mret = request_irq(IRQ_DMA0, dma_irq_fn, IRQF_SHARED, "dma", &dma_irq_fn);
if (mret < 0) printk(KERN_ALERT "%s: dma request_irg failed with %d\n", __func__, mret);
return 0;
}
static void __exit ofcd_exit(void) /* Destructor */
{
free_irq( IRQ_DMA0, &dma_irq_fn );
//dma_unmap_single(dev, dma_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
//kfree(cpu_addr);
dma_free_coherent(dev, 32, virt_cb, phys_cb);
dma_free_coherent(dev, 4, virt_src, phys_src);
dma_free_coherent(dev, 4, virt_dst, phys_dst);
iounmap(dma_regs);
// device_unregister(dev);
misc_deregister(&sample_device);
printk(KERN_INFO "Module unregistered\n");
}
module_init(ofcd_init);
module_exit(ofcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MBajor>");
MODULE_DESCRIPTION("PiCNC driver");
MODULE_VERSION("0.1");
I hope this help.