trem wrote: > Hi > > Here is the second part of the tutorial serie about rtdm. I've just > added rt-task and semaphore. It's still a very very simple example.
Thanks again for your contribution. I have a few comments below. > > Now, I don't know how to continue, have you got any idea of > "topic/subject" that could help people to understand xenomai ? I think it would be good to dive into IRQ handling as this is part of most drivers. Have a look at irqbench, specifically the UART part of it, and the 16550A serial driver. Maybe you can try to create some topics around a basic null-modem link between a Xenomai box and some other PC. That would give you an IRQ source, a data source (the transmitted characters), and enough food for things like synchronisation (mutexes, spinlocks). Don't reimplement the full 16550A driver, only pick simple aspects. > > regards, > Philippe > > > ------------------------------------------------------------------------ > ... > Index: tut02-skeleton-drv.c > =================================================================== > --- tut02-skeleton-drv.c (révision 0) > +++ tut02-skeleton-drv.c (révision 0) > @@ -0,0 +1,245 @@ > +/*************************************************************************** > + * Copyright (C) 2007 by trem (Philippe Reynes) * > + * [EMAIL PROTECTED] * > + * * > + * This program is free software; you can redistribute it and/or modify * > + * it under the terms of the GNU General Public License as published by * > + * the Free Software Foundation; either version 2 of the License, or * > + * (at your option) any later version. * > + * * > + * This program is distributed in the hope that it will be useful, * > + * but WITHOUT ANY WARRANTY; without even the implied warranty of * > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * > + * GNU General Public License for more details. * > + * * > + * You should have received a copy of the GNU General Public License * > + * along with this program; if not, write to the * > + * Free Software Foundation, Inc., * > + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * > + ***************************************************************************/ > + > +/** > + * This kernel driver demonstrates how an RTDM device can be set up. This sounds familiar, like the first example. Doesn't this emphasis a new, different topic? > + * > + * It is a simple device, only 4 operation are provided: > + * - open: start device usage > + * - close: ends device usage > + * - write: store transfered data in an internal buffer (realtime context) > + * - read: return previously stored data and erase buffer (realtime > context) > + * > + */ > + > +#include <linux/module.h> > +#include <rtdm/rtdm_driver.h> > + > +MODULE_LICENSE("GPL"); > +MODULE_AUTHOR("trem"); > + > +#define SIZE_MAX 1024 > +#define DEVICE_NAME "tut02-skeleton-drv01" > +#define SOME_SUB_CLASS 4711 > + > +/** > + * The structure of the buffer > + * > + */ > +typedef struct buffer_s { > + int size; > + char data[SIZE_MAX]; > +} buffer_t; > + > +/** > + * The global buffer > + * > + */ > +buffer_t buffer; > + > +/** > + * The global semaphore > + * > + */ > +rtdm_sem_t sem; Having plain global variables doesn't scale well. That actually makes me think of further topcis for tutorials: o Handling multiple devices with one driver o Making use of device context buffers (rtdm_device::context_size) > + > +/** > + * Open the device > + * > + * This function is called when the device shall be opened. > + * > + */ > +static int simple_rtdm_open_nrt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, int oflags) > +{ > + return 0; > +} > + > +/** > + * Open the device > + * > + * This function is called when the device shall be opened in > realtime-context. > + * > + */ > +static int simple_rtdm_open_rt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, int oflags) > +{ > + return 0; > +} Don't register separate handlers for the same operation if they are identical. > + > +/** > + * Close the device > + * > + * This function is called when the device shall be closed. > + * > + */ > +static int simple_rtdm_close_nrt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info) > +{ > + return 0; > +} > + > +/** > + * Close the device > + * > + * This function is called when the device shall be closed in > realtime-context. > + * > + */ > +static int simple_rtdm_close_rt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info) > +{ > + return 0; > +} Same here. > + > +/** > + * Read from the device > + * > + * This function is called when the device is read in non-realtime context. > + * > + */ > +static ssize_t simple_rtdm_read_nrt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, void *buf, > + size_t nbyte) > +{ > + rtdm_printk("DEBUG : read is not implemented in non-realtime > context\n"); > + return 0; Don't do this. If there is no nrt handler registered, Xenomai will nicely switch a shadowed caller into RT mode (when required) and call simple_rtdm_read_rt instead. With this handler registered, nothing useful happens. Rather demonstrate context-sensitive handlers by doing different things with them (but that's advanced stuff anyway). > +} > + > +/** > + * Read from the device > + * > + * This function is called when the device is read in realtime context. > + * > + */ > +static ssize_t simple_rtdm_read_rt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, void *buf, > + size_t nbyte) > +{ > + int size; > + > + /* take the semaphore */ > + rtdm_sem_down(&sem); > + > + /* read the kernel buffer and sent it to user space */ > + size = (buffer.size > nbyte) ? nbyte : buffer.size; > + if (rtdm_safe_copy_to_user(user_info, buf, buffer.data, size)) > + rtdm_printk("ERROR : can't copy data from driver\n"); Send the error code to the user instead of dumping it to the log. The user will then be able to react on it. > + > + /* clean the kernel buffer */ > + buffer.size = 0; > + > + return size; > +} > + > +/** > + * Write in the device > + * > + * This function is called when the device is written in non-realtime > context. > + * > + */ > +static ssize_t simple_rtdm_write_nrt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, > + const void *buf, size_t nbyte) > +{ > + rtdm_printk("DEBUG : write is not implemented in non-realtime > context\n"); > + return 0; > +} See above. > + > +/** > + * Write in the device > + * > + * This function is called when the device is written in realtime context. > + * > + */ > +static ssize_t simple_rtdm_write_rt(struct rtdm_dev_context *context, > + rtdm_user_info_t * user_info, > + const void *buf, size_t nbyte) > +{ > + /* release the semaphore */ > + rtdm_sem_up(&sem); Oops, that creates a race: Data will be written to the buffer AFTER you signal some reader that there is data available... > + > + /* write the user buffer in the kernel buffer */ > + buffer.size = (nbyte > SIZE_MAX) ? SIZE_MAX : nbyte; > + if (rtdm_safe_copy_from_user(user_info, buffer.data, buf, buffer.size)) > + rtdm_printk("ERROR : can't copy data to driver\n"); > + > + return nbyte; > +} > + > +/** > + * This structure describe the simple RTDM device > + * > + */ > +static struct rtdm_device device = { > + .struct_version = RTDM_DEVICE_STRUCT_VER, > + > + .device_flags = RTDM_NAMED_DEVICE, > + .context_size = 0, > + .device_name = DEVICE_NAME, > + > + .open_nrt = simple_rtdm_open_nrt, > + .open_rt = simple_rtdm_open_rt, > + > + .ops = { > + .close_nrt = simple_rtdm_close_nrt, > + .close_rt = simple_rtdm_close_rt, > + .read_nrt = simple_rtdm_read_nrt, > + .read_rt = simple_rtdm_read_rt, > + .write_nrt = simple_rtdm_write_nrt, > + .write_rt = simple_rtdm_write_rt, > + }, > + > + .device_class = RTDM_CLASS_EXPERIMENTAL, > + .device_sub_class = SOME_SUB_CLASS, > + .profile_version = 1, > + .driver_name = "SimpleRTDM", > + .driver_version = RTDM_DRIVER_VER(0, 1, 2), > + .peripheral_name = "Simple RTDM example", > + .provider_name = "trem", > + .proc_name = device.device_name, > +}; > + > +/** > + * This function is called when the module is loaded > + * > + * It simply registers the RTDM device. > + * > + */ > +int __init simple_rtdm_init(void) > +{ > + buffer.size = 0; /* clear the buffer */ > + rtdm_sem_init(&sem, 0); /* init the global semaphore */ > + > + return rtdm_dev_register(&device); > +} > + > +/** > + * This function is called when the module is unloaded > + * > + * It unregister the RTDM device, polling at 1000 ms for pending users. > + * > + */ > +void __exit simple_rtdm_exit(void) > +{ > + rtdm_dev_unregister(&device, 1000); > +} > + > +module_init(simple_rtdm_init); > +module_exit(simple_rtdm_exit); > > Modification de propriétés sur tut02-skeleton-drv.c > ___________________________________________________________________ > Nom : svn:eol-style > + native > > Index: Makefile > =================================================================== > --- Makefile (révision 2484) > +++ Makefile (copie de travail) > @@ -1,13 +1,13 @@ > ###### CONFIGURATION ###### > > ### List of applications to be build > -APPLICATIONS = tut01-skeleton-app > +APPLICATIONS = tut01-skeleton-app tut02-skeleton-app > > ### Note: to override the search path for the xeno-config script, use "make > XENO=..." > > > ### List of modules to be build > -MODULES = heartbeat-x86 tut01-skeleton-drv > +MODULES = heartbeat-x86 tut01-skeleton-drv tut02-skeleton-drv > > ### Note: to override the kernel source path, use "make KSRC=..." > > @@ -86,6 +86,6 @@ > > clean:: > $(RM) $(CLEANMOD) *.o *.ko *.mod.c Module*.symvers > - $(RM) -R .tmp* > + $(RM) -R *~ .tmp* This last hunk looks unrelated. Jan
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Xenomai-core mailing list Xenomai-core@gna.org https://mail.gna.org/listinfo/xenomai-core