All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai] Hilscher driver for cifX boards
@ 2013-02-07 14:53 Stéphane LOS
  2013-02-07 16:11 ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-07 14:53 UTC (permalink / raw)
  To: xenomai

Hello Sirs,

Hilscher is offering a Linux driver based on UIO for cifX boards.

In my understanding, down to 1ms cycle time, a PREEMPT RT solution 
should be enough.

The cifX boards can manage with bus cycle times down to 250µs like with 
EtherCAT or Sercos III firmwares.

So it seems in that cases that using Xenomai would be the way to go.
I suppose that it would be needed to modify or change the existing 
driver but I can't figure out how things (Xenomai / RTDM / UIO) fit 
together.

UIO is the kernel module that allows the mapping of the board memory to 
user space.

The cifX driver uses the libpciaccess to pick up the board and retrieve 
some board information from UIO before the mapping.
Then it uses pthread and rt functions when accessing the board.

Since UIO and libpciaccess are only used during the initialization, is 
it a problem for a Xenomai application ?

We have setup a Xenomai system and tried to compile the user land 
library with Xenomai options and flags and it seems we have been successful.
The driver should be using the POSIX skin of Xenomai if we have been lucky.

I can't see why we would need RTDM. Any hint please ?

I am an absolute beginner in the Xenomai arena, don't throw me to the 
lions...

-- 
Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-07 14:53 [Xenomai] Hilscher driver for cifX boards Stéphane LOS
@ 2013-02-07 16:11 ` Gilles Chanteperdrix
  2013-02-08  9:07   ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-02-07 16:11 UTC (permalink / raw)
  To: Stéphane LOS; +Cc: xenomai

On 02/07/2013 03:53 PM, Stéphane LOS wrote:

> Hello Sirs,
> 
> Hilscher is offering a Linux driver based on UIO for cifX boards.
> 
> In my understanding, down to 1ms cycle time, a PREEMPT RT solution 
> should be enough.
> 
> The cifX boards can manage with bus cycle times down to 250µs like with 
> EtherCAT or Sercos III firmwares.
> 
> So it seems in that cases that using Xenomai would be the way to go.
> I suppose that it would be needed to modify or change the existing 
> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit 
> together.
> 
> UIO is the kernel module that allows the mapping of the board memory to 
> user space.
> 
> The cifX driver uses the libpciaccess to pick up the board and retrieve 
> some board information from UIO before the mapping.
> Then it uses pthread and rt functions when accessing the board.
> 
> Since UIO and libpciaccess are only used during the initialization, is 
> it a problem for a Xenomai application ?
> 
> We have setup a Xenomai system and tried to compile the user land 
> library with Xenomai options and flags and it seems we have been successful.
> The driver should be using the POSIX skin of Xenomai if we have been lucky.
> 
> I can't see why we would need RTDM. Any hint please ?
> 
> I am an absolute beginner in the Xenomai arena, don't throw me to the 
> lions...
> 


If UIO is used to register an interrupt handler for instance, the
interrupt handler will not be called in real-time context when used with
Xenomai, so, you would have to use the (deprecated) native or posix skin
services to register a user-space interrupt handler, or more likely
write an RTDM driver. On the other hand, if what you need is simply
accessing the board registers through MMIO, then you do not need RTDM.

While accessing registers from user-space may be tempting, there is a
risk of ending up with an application where the driver code is not
clearly separated. Writing a driver separated from the application is
preferable, as it provides a sane isolation between the two. If you
change the hardware, you just have to rewrite a driver which follows the
same profile, if you want to write another application using the same
driver, you can keep the driver.

-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-07 16:11 ` Gilles Chanteperdrix
@ 2013-02-08  9:07   ` Stéphane LOS
  2013-02-08  9:18     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-08  9:07 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>
>> Hello Sirs,
>>
>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>
>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>> should be enough.
>>
>> The cifX boards can manage with bus cycle times down to 250µs like with
>> EtherCAT or Sercos III firmwares.
>>
>> So it seems in that cases that using Xenomai would be the way to go.
>> I suppose that it would be needed to modify or change the existing
>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>> together.
>>
>> UIO is the kernel module that allows the mapping of the board memory to
>> user space.
>>
>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>> some board information from UIO before the mapping.
>> Then it uses pthread and rt functions when accessing the board.
>>
>> Since UIO and libpciaccess are only used during the initialization, is
>> it a problem for a Xenomai application ?
>>
>> We have setup a Xenomai system and tried to compile the user land
>> library with Xenomai options and flags and it seems we have been successful.
>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>
>> I can't see why we would need RTDM. Any hint please ?
>>
>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>> lions...
>>
>
> If UIO is used to register an interrupt handler for instance, the
> interrupt handler will not be called in real-time context when used with
> Xenomai, so, you would have to use the (deprecated) native or posix skin
> services to register a user-space interrupt handler, or more likely
> write an RTDM driver. On the other hand, if what you need is simply
> accessing the board registers through MMIO, then you do not need RTDM.
>
> While accessing registers from user-space may be tempting, there is a
> risk of ending up with an application where the driver code is not
> clearly separated. Writing a driver separated from the application is
> preferable, as it provides a sane isolation between the two. If you
> change the hardware, you just have to rewrite a driver which follows the
> same profile, if you want to write another application using the same
> driver, you can keep the driver.
>

Thank you for your kind support Gilles.

The cifX Device Driver is Hilscher's library to deal with cifX boards 
and is available for the major OSes.
Additionally it is available to anybody as source code, the cifX Driver 
Toolkit when one has to create a driver for his own OS.

This driver library accesses the board interface which is a Dual Port 
Memory.

So the user application shall use this layer and gets independence from 
the target OS.

I understand that we should create an RTDM driver instead of a UIO 
driver and adapt the user library so that it uses the RTDM driver.

Am I right ?

I have seen also the Xenomai Solo project and the upcoming Xenomai 3 
that would be using vanilla kernel with PREEMPT RT.

When this happens, would our RTDM based cifX driver still be an option 
or would the UIO based driver suffice ?

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-08  9:07   ` Stéphane LOS
@ 2013-02-08  9:18     ` Gilles Chanteperdrix
  2013-02-08 11:28       ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-02-08  9:18 UTC (permalink / raw)
  To: Stéphane LOS; +Cc: xenomai

On 02/08/2013 10:07 AM, Stéphane LOS wrote:

> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>
>>> Hello Sirs,
>>>
>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>
>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>> should be enough.
>>>
>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>> EtherCAT or Sercos III firmwares.
>>>
>>> So it seems in that cases that using Xenomai would be the way to go.
>>> I suppose that it would be needed to modify or change the existing
>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>> together.
>>>
>>> UIO is the kernel module that allows the mapping of the board memory to
>>> user space.
>>>
>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>> some board information from UIO before the mapping.
>>> Then it uses pthread and rt functions when accessing the board.
>>>
>>> Since UIO and libpciaccess are only used during the initialization, is
>>> it a problem for a Xenomai application ?
>>>
>>> We have setup a Xenomai system and tried to compile the user land
>>> library with Xenomai options and flags and it seems we have been successful.
>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>
>>> I can't see why we would need RTDM. Any hint please ?
>>>
>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>> lions...
>>>
>>
>> If UIO is used to register an interrupt handler for instance, the
>> interrupt handler will not be called in real-time context when used with
>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>> services to register a user-space interrupt handler, or more likely
>> write an RTDM driver. On the other hand, if what you need is simply
>> accessing the board registers through MMIO, then you do not need RTDM.
>>
>> While accessing registers from user-space may be tempting, there is a
>> risk of ending up with an application where the driver code is not
>> clearly separated. Writing a driver separated from the application is
>> preferable, as it provides a sane isolation between the two. If you
>> change the hardware, you just have to rewrite a driver which follows the
>> same profile, if you want to write another application using the same
>> driver, you can keep the driver.
>>
> 
> Thank you for your kind support Gilles.
> 
> The cifX Device Driver is Hilscher's library to deal with cifX boards 
> and is available for the major OSes.
> Additionally it is available to anybody as source code, the cifX Driver 
> Toolkit when one has to create a driver for his own OS.
> 
> This driver library accesses the board interface which is a Dual Port 
> Memory.
> 
> So the user application shall use this layer and gets independence from 
> the target OS.
> 
> I understand that we should create an RTDM driver instead of a UIO 
> driver and adapt the user library so that it uses the RTDM driver.

> 
> Am I right ?


I tried to explain why it may be better to create an RTDM driver, but in
this case this may not be the best option. The answer to your question
depends on what you have to do to implement the driver. As I said, if
you simply have to access MMIO registers, user-space may be fine, if you
have to handle interrupts kernel-space (so, RTDM) is preferable.

-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-08  9:18     ` Gilles Chanteperdrix
@ 2013-02-08 11:28       ` Jan Kiszka
  2013-02-08 11:35         ` Gilles Chanteperdrix
       [not found]         ` <5114FD7B.20902@hilscher.com>
  0 siblings, 2 replies; 57+ messages in thread
From: Jan Kiszka @ 2013-02-08 11:28 UTC (permalink / raw)
  To: Gilles Chanteperdrix, Stéphane LOS; +Cc: xenomai

On 2013-02-08 10:18, Gilles Chanteperdrix wrote:
> On 02/08/2013 10:07 AM, Stéphane LOS wrote:
> 
>> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>>
>>>> Hello Sirs,
>>>>
>>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>>
>>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>>> should be enough.
>>>>
>>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>>> EtherCAT or Sercos III firmwares.
>>>>
>>>> So it seems in that cases that using Xenomai would be the way to go.
>>>> I suppose that it would be needed to modify or change the existing
>>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>>> together.
>>>>
>>>> UIO is the kernel module that allows the mapping of the board memory to
>>>> user space.
>>>>
>>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>>> some board information from UIO before the mapping.
>>>> Then it uses pthread and rt functions when accessing the board.
>>>>
>>>> Since UIO and libpciaccess are only used during the initialization, is
>>>> it a problem for a Xenomai application ?
>>>>
>>>> We have setup a Xenomai system and tried to compile the user land
>>>> library with Xenomai options and flags and it seems we have been successful.
>>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>>
>>>> I can't see why we would need RTDM. Any hint please ?
>>>>
>>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>>> lions...
>>>>
>>>
>>> If UIO is used to register an interrupt handler for instance, the
>>> interrupt handler will not be called in real-time context when used with
>>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>>> services to register a user-space interrupt handler, or more likely
>>> write an RTDM driver. On the other hand, if what you need is simply
>>> accessing the board registers through MMIO, then you do not need RTDM.
>>>
>>> While accessing registers from user-space may be tempting, there is a
>>> risk of ending up with an application where the driver code is not
>>> clearly separated. Writing a driver separated from the application is
>>> preferable, as it provides a sane isolation between the two. If you
>>> change the hardware, you just have to rewrite a driver which follows the
>>> same profile, if you want to write another application using the same
>>> driver, you can keep the driver.
>>>
>>
>> Thank you for your kind support Gilles.
>>
>> The cifX Device Driver is Hilscher's library to deal with cifX boards 
>> and is available for the major OSes.
>> Additionally it is available to anybody as source code, the cifX Driver 
>> Toolkit when one has to create a driver for his own OS.
>>
>> This driver library accesses the board interface which is a Dual Port 
>> Memory.
>>
>> So the user application shall use this layer and gets independence from 
>> the target OS.
>>
>> I understand that we should create an RTDM driver instead of a UIO 
>> driver and adapt the user library so that it uses the RTDM driver.
> 
>>
>> Am I right ?
> 
> 
> I tried to explain why it may be better to create an RTDM driver, but in
> this case this may not be the best option. The answer to your question
> depends on what you have to do to implement the driver. As I said, if
> you simply have to access MMIO registers, user-space may be fine, if you
> have to handle interrupts kernel-space (so, RTDM) is preferable.

Are we talking about linux/drivers/uio/uio_cif.c here? That one
obviously has interrupt support.

If your customers may want to use Xenomai 3 with I-pipe instead of
Preempt-RT underneath (both options will exist), RTDM will still be
required for interrupt handling. If you like to, you could propose such
a driver for Xenomai integration. That would ensure it will come with
future releases.

I also wonder if it didn't make sense for us to provide an UIO-like
infrastructure for such use cases (single-user device drivers with IRQ
event channel needs).

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-08 11:28       ` Jan Kiszka
@ 2013-02-08 11:35         ` Gilles Chanteperdrix
  2013-02-08 11:46           ` Jan Kiszka
       [not found]         ` <5114FD7B.20902@hilscher.com>
  1 sibling, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-02-08 11:35 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

On 02/08/2013 12:28 PM, Jan Kiszka wrote:

> On 2013-02-08 10:18, Gilles Chanteperdrix wrote:
>> On 02/08/2013 10:07 AM, Stéphane LOS wrote:
>>
>>> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>>>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>>>
>>>>> Hello Sirs,
>>>>>
>>>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>>>
>>>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>>>> should be enough.
>>>>>
>>>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>>>> EtherCAT or Sercos III firmwares.
>>>>>
>>>>> So it seems in that cases that using Xenomai would be the way to go.
>>>>> I suppose that it would be needed to modify or change the existing
>>>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>>>> together.
>>>>>
>>>>> UIO is the kernel module that allows the mapping of the board memory to
>>>>> user space.
>>>>>
>>>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>>>> some board information from UIO before the mapping.
>>>>> Then it uses pthread and rt functions when accessing the board.
>>>>>
>>>>> Since UIO and libpciaccess are only used during the initialization, is
>>>>> it a problem for a Xenomai application ?
>>>>>
>>>>> We have setup a Xenomai system and tried to compile the user land
>>>>> library with Xenomai options and flags and it seems we have been successful.
>>>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>>>
>>>>> I can't see why we would need RTDM. Any hint please ?
>>>>>
>>>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>>>> lions...
>>>>>
>>>>
>>>> If UIO is used to register an interrupt handler for instance, the
>>>> interrupt handler will not be called in real-time context when used with
>>>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>>>> services to register a user-space interrupt handler, or more likely
>>>> write an RTDM driver. On the other hand, if what you need is simply
>>>> accessing the board registers through MMIO, then you do not need RTDM.
>>>>
>>>> While accessing registers from user-space may be tempting, there is a
>>>> risk of ending up with an application where the driver code is not
>>>> clearly separated. Writing a driver separated from the application is
>>>> preferable, as it provides a sane isolation between the two. If you
>>>> change the hardware, you just have to rewrite a driver which follows the
>>>> same profile, if you want to write another application using the same
>>>> driver, you can keep the driver.
>>>>
>>>
>>> Thank you for your kind support Gilles.
>>>
>>> The cifX Device Driver is Hilscher's library to deal with cifX boards 
>>> and is available for the major OSes.
>>> Additionally it is available to anybody as source code, the cifX Driver 
>>> Toolkit when one has to create a driver for his own OS.
>>>
>>> This driver library accesses the board interface which is a Dual Port 
>>> Memory.
>>>
>>> So the user application shall use this layer and gets independence from 
>>> the target OS.
>>>
>>> I understand that we should create an RTDM driver instead of a UIO 
>>> driver and adapt the user library so that it uses the RTDM driver.
>>
>>>
>>> Am I right ?
>>
>>
>> I tried to explain why it may be better to create an RTDM driver, but in
>> this case this may not be the best option. The answer to your question
>> depends on what you have to do to implement the driver. As I said, if
>> you simply have to access MMIO registers, user-space may be fine, if you
>> have to handle interrupts kernel-space (so, RTDM) is preferable.
> 
> Are we talking about linux/drivers/uio/uio_cif.c here? That one
> obviously has interrupt support.
> 
> If your customers may want to use Xenomai 3 with I-pipe instead of
> Preempt-RT underneath (both options will exist), RTDM will still be
> required for interrupt handling. If you like to, you could propose such
> a driver for Xenomai integration. That would ensure it will come with
> future releases.
> 
> I also wonder if it didn't make sense for us to provide an UIO-like
> infrastructure for such use cases (single-user device drivers with IRQ
> event channel needs).


The native and posix skin provide support for interrupts in user-space...


-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-08 11:35         ` Gilles Chanteperdrix
@ 2013-02-08 11:46           ` Jan Kiszka
  0 siblings, 0 replies; 57+ messages in thread
From: Jan Kiszka @ 2013-02-08 11:46 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

On 2013-02-08 12:35, Gilles Chanteperdrix wrote:
> On 02/08/2013 12:28 PM, Jan Kiszka wrote:
> 
>> On 2013-02-08 10:18, Gilles Chanteperdrix wrote:
>>> On 02/08/2013 10:07 AM, Stéphane LOS wrote:
>>>
>>>> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>>>>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>>>>
>>>>>> Hello Sirs,
>>>>>>
>>>>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>>>>
>>>>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>>>>> should be enough.
>>>>>>
>>>>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>>>>> EtherCAT or Sercos III firmwares.
>>>>>>
>>>>>> So it seems in that cases that using Xenomai would be the way to go.
>>>>>> I suppose that it would be needed to modify or change the existing
>>>>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>>>>> together.
>>>>>>
>>>>>> UIO is the kernel module that allows the mapping of the board memory to
>>>>>> user space.
>>>>>>
>>>>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>>>>> some board information from UIO before the mapping.
>>>>>> Then it uses pthread and rt functions when accessing the board.
>>>>>>
>>>>>> Since UIO and libpciaccess are only used during the initialization, is
>>>>>> it a problem for a Xenomai application ?
>>>>>>
>>>>>> We have setup a Xenomai system and tried to compile the user land
>>>>>> library with Xenomai options and flags and it seems we have been successful.
>>>>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>>>>
>>>>>> I can't see why we would need RTDM. Any hint please ?
>>>>>>
>>>>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>>>>> lions...
>>>>>>
>>>>>
>>>>> If UIO is used to register an interrupt handler for instance, the
>>>>> interrupt handler will not be called in real-time context when used with
>>>>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>>>>> services to register a user-space interrupt handler, or more likely
>>>>> write an RTDM driver. On the other hand, if what you need is simply
>>>>> accessing the board registers through MMIO, then you do not need RTDM.
>>>>>
>>>>> While accessing registers from user-space may be tempting, there is a
>>>>> risk of ending up with an application where the driver code is not
>>>>> clearly separated. Writing a driver separated from the application is
>>>>> preferable, as it provides a sane isolation between the two. If you
>>>>> change the hardware, you just have to rewrite a driver which follows the
>>>>> same profile, if you want to write another application using the same
>>>>> driver, you can keep the driver.
>>>>>
>>>>
>>>> Thank you for your kind support Gilles.
>>>>
>>>> The cifX Device Driver is Hilscher's library to deal with cifX boards 
>>>> and is available for the major OSes.
>>>> Additionally it is available to anybody as source code, the cifX Driver 
>>>> Toolkit when one has to create a driver for his own OS.
>>>>
>>>> This driver library accesses the board interface which is a Dual Port 
>>>> Memory.
>>>>
>>>> So the user application shall use this layer and gets independence from 
>>>> the target OS.
>>>>
>>>> I understand that we should create an RTDM driver instead of a UIO 
>>>> driver and adapt the user library so that it uses the RTDM driver.
>>>
>>>>
>>>> Am I right ?
>>>
>>>
>>> I tried to explain why it may be better to create an RTDM driver, but in
>>> this case this may not be the best option. The answer to your question
>>> depends on what you have to do to implement the driver. As I said, if
>>> you simply have to access MMIO registers, user-space may be fine, if you
>>> have to handle interrupts kernel-space (so, RTDM) is preferable.
>>
>> Are we talking about linux/drivers/uio/uio_cif.c here? That one
>> obviously has interrupt support.
>>
>> If your customers may want to use Xenomai 3 with I-pipe instead of
>> Preempt-RT underneath (both options will exist), RTDM will still be
>> required for interrupt handling. If you like to, you could propose such
>> a driver for Xenomai integration. That would ensure it will come with
>> future releases.
>>
>> I also wonder if it didn't make sense for us to provide an UIO-like
>> infrastructure for such use cases (single-user device drivers with IRQ
>> event channel needs).
> 
> 
> The native and posix skin provide support for interrupts in user-space...

That's deprecated, and UIO is more than this.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
       [not found]         ` <5114FD7B.20902@hilscher.com>
@ 2013-02-08 13:40           ` Jan Kiszka
  2013-02-08 14:33             ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-08 13:40 UTC (permalink / raw)
  To: Stéphane LOS; +Cc: Xenomai

[re-adding the list]

On 2013-02-08 14:28, Stéphane LOS wrote:
> Le 08/02/2013 12:28, Jan Kiszka a écrit :
>> On 2013-02-08 10:18, Gilles Chanteperdrix wrote:
>>> On 02/08/2013 10:07 AM, Stéphane LOS wrote:
>>>
>>>> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>>>>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>>>>
>>>>>> Hello Sirs,
>>>>>>
>>>>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>>>>
>>>>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>>>>> should be enough.
>>>>>>
>>>>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>>>>> EtherCAT or Sercos III firmwares.
>>>>>>
>>>>>> So it seems in that cases that using Xenomai would be the way to go.
>>>>>> I suppose that it would be needed to modify or change the existing
>>>>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>>>>> together.
>>>>>>
>>>>>> UIO is the kernel module that allows the mapping of the board memory to
>>>>>> user space.
>>>>>>
>>>>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>>>>> some board information from UIO before the mapping.
>>>>>> Then it uses pthread and rt functions when accessing the board.
>>>>>>
>>>>>> Since UIO and libpciaccess are only used during the initialization, is
>>>>>> it a problem for a Xenomai application ?
>>>>>>
>>>>>> We have setup a Xenomai system and tried to compile the user land
>>>>>> library with Xenomai options and flags and it seems we have been successful.
>>>>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>>>>
>>>>>> I can't see why we would need RTDM. Any hint please ?
>>>>>>
>>>>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>>>>> lions...
>>>>>>
>>>>> If UIO is used to register an interrupt handler for instance, the
>>>>> interrupt handler will not be called in real-time context when used with
>>>>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>>>>> services to register a user-space interrupt handler, or more likely
>>>>> write an RTDM driver. On the other hand, if what you need is simply
>>>>> accessing the board registers through MMIO, then you do not need RTDM.
>>>>>
>>>>> While accessing registers from user-space may be tempting, there is a
>>>>> risk of ending up with an application where the driver code is not
>>>>> clearly separated. Writing a driver separated from the application is
>>>>> preferable, as it provides a sane isolation between the two. If you
>>>>> change the hardware, you just have to rewrite a driver which follows the
>>>>> same profile, if you want to write another application using the same
>>>>> driver, you can keep the driver.
>>>>>
>>>> Thank you for your kind support Gilles.
>>>>
>>>> The cifX Device Driver is Hilscher's library to deal with cifX boards
>>>> and is available for the major OSes.
>>>> Additionally it is available to anybody as source code, the cifX Driver
>>>> Toolkit when one has to create a driver for his own OS.
>>>>
>>>> This driver library accesses the board interface which is a Dual Port
>>>> Memory.
>>>>
>>>> So the user application shall use this layer and gets independence from
>>>> the target OS.
>>>>
>>>> I understand that we should create an RTDM driver instead of a UIO
>>>> driver and adapt the user library so that it uses the RTDM driver.
>>>> Am I right ?
>>>
>>> I tried to explain why it may be better to create an RTDM driver, but in
>>> this case this may not be the best option. The answer to your question
>>> depends on what you have to do to implement the driver. As I said, if
>>> you simply have to access MMIO registers, user-space may be fine, if you
>>> have to handle interrupts kernel-space (so, RTDM) is preferable.
>> Are we talking about linux/drivers/uio/uio_cif.c here? That one
>> obviously has interrupt support.
>>
>> If your customers may want to use Xenomai 3 with I-pipe instead of
>> Preempt-RT underneath (both options will exist), RTDM will still be
>> required for interrupt handling. If you like to, you could propose such
>> a driver for Xenomai integration. That would ensure it will come with
>> future releases.
>>
>> I also wonder if it didn't make sense for us to provide an UIO-like
>> infrastructure for such use cases (single-user device drivers with IRQ
>> event channel needs).
>>
>> Jan
>>
> 
> I am talking about the new products based on the netX chip :
> http://lxr.free-electrons.com/source/drivers/uio/uio_netx.c

Ah, I see. Structurally similar, though.

> 
> I have been through :
> http://www.xenomai.org/index.php/Xenomai:Roadmap#Toward_Xenomai_3
> 
> Looks like we should create an RTDM driver and build our Xenomai 
> specific libcifx on top of it.
> 
> Since the kernel now includes by default the UIO stuff, the board will 
> likely be detected twice, once by UIO and second by the RTDM driver.
> Is it a problem ?
> Should the user of the RTDM driver disable UIO / netX in the kernel ?

It's not problem to have multiple drivers registered for the same IDs.
You can always rebind them via sysfs or black-list one of them in the
local modprobe configuration.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-08 13:40           ` Jan Kiszka
@ 2013-02-08 14:33             ` Stéphane LOS
  0 siblings, 0 replies; 57+ messages in thread
From: Stéphane LOS @ 2013-02-08 14:33 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Xenomai

Le 08/02/2013 14:40, Jan Kiszka a écrit :
> [re-adding the list]
>
> On 2013-02-08 14:28, Stéphane LOS wrote:
>> Le 08/02/2013 12:28, Jan Kiszka a écrit :
>>> On 2013-02-08 10:18, Gilles Chanteperdrix wrote:
>>>> On 02/08/2013 10:07 AM, Stéphane LOS wrote:
>>>>
>>>>> Le 07/02/2013 17:11, Gilles Chanteperdrix a écrit :
>>>>>> On 02/07/2013 03:53 PM, Stéphane LOS wrote:
>>>>>>
>>>>>>> Hello Sirs,
>>>>>>>
>>>>>>> Hilscher is offering a Linux driver based on UIO for cifX boards.
>>>>>>>
>>>>>>> In my understanding, down to 1ms cycle time, a PREEMPT RT solution
>>>>>>> should be enough.
>>>>>>>
>>>>>>> The cifX boards can manage with bus cycle times down to 250µs like with
>>>>>>> EtherCAT or Sercos III firmwares.
>>>>>>>
>>>>>>> So it seems in that cases that using Xenomai would be the way to go.
>>>>>>> I suppose that it would be needed to modify or change the existing
>>>>>>> driver but I can't figure out how things (Xenomai / RTDM / UIO) fit
>>>>>>> together.
>>>>>>>
>>>>>>> UIO is the kernel module that allows the mapping of the board memory to
>>>>>>> user space.
>>>>>>>
>>>>>>> The cifX driver uses the libpciaccess to pick up the board and retrieve
>>>>>>> some board information from UIO before the mapping.
>>>>>>> Then it uses pthread and rt functions when accessing the board.
>>>>>>>
>>>>>>> Since UIO and libpciaccess are only used during the initialization, is
>>>>>>> it a problem for a Xenomai application ?
>>>>>>>
>>>>>>> We have setup a Xenomai system and tried to compile the user land
>>>>>>> library with Xenomai options and flags and it seems we have been successful.
>>>>>>> The driver should be using the POSIX skin of Xenomai if we have been lucky.
>>>>>>>
>>>>>>> I can't see why we would need RTDM. Any hint please ?
>>>>>>>
>>>>>>> I am an absolute beginner in the Xenomai arena, don't throw me to the
>>>>>>> lions...
>>>>>>>
>>>>>> If UIO is used to register an interrupt handler for instance, the
>>>>>> interrupt handler will not be called in real-time context when used with
>>>>>> Xenomai, so, you would have to use the (deprecated) native or posix skin
>>>>>> services to register a user-space interrupt handler, or more likely
>>>>>> write an RTDM driver. On the other hand, if what you need is simply
>>>>>> accessing the board registers through MMIO, then you do not need RTDM.
>>>>>>
>>>>>> While accessing registers from user-space may be tempting, there is a
>>>>>> risk of ending up with an application where the driver code is not
>>>>>> clearly separated. Writing a driver separated from the application is
>>>>>> preferable, as it provides a sane isolation between the two. If you
>>>>>> change the hardware, you just have to rewrite a driver which follows the
>>>>>> same profile, if you want to write another application using the same
>>>>>> driver, you can keep the driver.
>>>>>>
>>>>> Thank you for your kind support Gilles.
>>>>>
>>>>> The cifX Device Driver is Hilscher's library to deal with cifX boards
>>>>> and is available for the major OSes.
>>>>> Additionally it is available to anybody as source code, the cifX Driver
>>>>> Toolkit when one has to create a driver for his own OS.
>>>>>
>>>>> This driver library accesses the board interface which is a Dual Port
>>>>> Memory.
>>>>>
>>>>> So the user application shall use this layer and gets independence from
>>>>> the target OS.
>>>>>
>>>>> I understand that we should create an RTDM driver instead of a UIO
>>>>> driver and adapt the user library so that it uses the RTDM driver.
>>>>> Am I right ?
>>>> I tried to explain why it may be better to create an RTDM driver, but in
>>>> this case this may not be the best option. The answer to your question
>>>> depends on what you have to do to implement the driver. As I said, if
>>>> you simply have to access MMIO registers, user-space may be fine, if you
>>>> have to handle interrupts kernel-space (so, RTDM) is preferable.
>>> Are we talking about linux/drivers/uio/uio_cif.c here? That one
>>> obviously has interrupt support.
>>>
>>> If your customers may want to use Xenomai 3 with I-pipe instead of
>>> Preempt-RT underneath (both options will exist), RTDM will still be
>>> required for interrupt handling. If you like to, you could propose such
>>> a driver for Xenomai integration. That would ensure it will come with
>>> future releases.
>>>
>>> I also wonder if it didn't make sense for us to provide an UIO-like
>>> infrastructure for such use cases (single-user device drivers with IRQ
>>> event channel needs).
>>>
>>> Jan
>>>
>> I am talking about the new products based on the netX chip :
>> http://lxr.free-electrons.com/source/drivers/uio/uio_netx.c
> Ah, I see. Structurally similar, though.
>
>> I have been through :
>> http://www.xenomai.org/index.php/Xenomai:Roadmap#Toward_Xenomai_3
>>
>> Looks like we should create an RTDM driver and build our Xenomai
>> specific libcifx on top of it.
>>
>> Since the kernel now includes by default the UIO stuff, the board will
>> likely be detected twice, once by UIO and second by the RTDM driver.
>> Is it a problem ?
>> Should the user of the RTDM driver disable UIO / netX in the kernel ?
> It's not problem to have multiple drivers registered for the same IDs.
> You can always rebind them via sysfs or black-list one of them in the
> local modprobe configuration.
>
> Jan
>
Sorry for not posting to the list, wrong button pushed.

Thank you and Gilles for your answer.

I bet there will be more questions. Have a nice week end.

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~




^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-18 10:02                                                                 ` Jerome Poncin
@ 2013-03-19 13:42                                                                   ` Jerome Poncin
  0 siblings, 0 replies; 57+ messages in thread
From: Jerome Poncin @ 2013-03-19 13:42 UTC (permalink / raw)
  To: xenomai

Le 18/03/2013 11:02, Jerome Poncin a écrit :
> Le 15/03/2013 14:24, Jan Kiszka a écrit :
>> On 2013-03-15 14:04, Jerome Poncin wrote:
>>> Hello Jan,
>>>
>>> Yes you're right. I have 1 thread for test (main) application and the
>>> driver create one or two thread if IRQ or polling is enable.
>>> The driver thread are loop waiting event with delay.
>>> At Driver start it take few second to download firmware and 
>>> configuration.
>>> My question is why it's a problem to have a real time that that run few
>>> second.
>>> If this task have the bigger priority, it's normal to not release hand
>>> and to not sleep, I'm right or not ?
>> Linux is not capable (yet) of handling the case that an online CPU is
>> 100% occupied. Sooner or later, the whole (Linux) system will lock up,
>> also the timekeeping can be negatively affected. That's nothing Xenomai
>> can change.
>>
>> Therefore, every real-time task has to behave properly, sleep on
>> asynchronous external events or suspend itself for a certain while when
>> there is nothing to do. In good real-time designs, that is usually no
>> problem, specifically if the number of tasks is moderate and the
>> workload is clear. I've seen less obvious problems in large
>> applications, but those were typically bugs as well.
>>
>> Jan
>>
> Hello Jan,
>
> I investigated my problem and the problem come from some lock on thread.
> I think my thread management is not correct... I
> Is there an example in posix with multiple thread management ?
>
> Thank you for your help,
>
> Jerome
Hello,

I corrected my problem with thread management running with posix skin. 
Now I have all thread that run in Real Time with IRQ.
I send you my last version of patch to see if kernel driver is correct 
for you, and can be integrated to the main line.

Thank you for your help,

Jerome
-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
+#endif
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..cae04aa
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,854 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.h>
+
+#include <rtdm/rtdm_driver.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+#define RTCIFX_GET_MEM_INFO				0x00
+#define RTCIFX_MMAP						0x01
+#define RTCIFX_MUNMAP					0x02
+#define RTCIFX_REQUEST_IRQ				0x03
+#define RTCIFX_FREE_IRQ					0x04
+#define RTCIFX_ENABLE_IRQ				0x05
+#define RTCIFX_DISABLE_IRQ				0x06
+#define RTCIFX_WAIT_IRQ					0x07
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	rtdm_event_t irq_event;
+	rtdm_nrtsig_t irq_nrtsig;
+	bool irq_sig;
+	struct ext_io_info *priv;
+};
+
+struct ext_io_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	uint32_t virt_addr;
+	uint32_t length;
+};
+
+static struct io_info *cifx_get_device_data(struct rtdm_device *info);
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info);
+
+static int cifx_set_plx_timing(struct ext_io_info *ext_info);
+static int cifx_get_plx_timing(struct ext_io_info *ext_info);
+static int cifx_get_dpm_mode(struct ext_io_info *ext_info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static int cifx_pci_ioctl_nrt(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info,
+			      unsigned int request, void *arg);
+static int cifx_pci_ioctl_rt(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info,
+			     unsigned int request, void *arg);
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+static inline int cifx_handler(rtdm_irq_t *irq);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.ioctl_rt = cifx_pci_ioctl_rt,
+		.ioctl_nrt = cifx_pci_ioctl_nrt,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX, 0, 0}, {
+	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA}, {
+	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM}, {
+	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH}, {
+	0,}
+};
+
+/* cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_rtdm_device_to_device_data
+ *	Get device_data structure
+ */
+static struct io_info *cifx_get_device_data(struct rtdm_device *info)
+{
+	return info->device_data;
+}
+
+/*
+ *	cifx_rtdm_device_to_private
+ *	Get ext_io_info structure
+ */
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
+{
+	return ((struct io_info *)info->device_data)->priv;
+}
+
+/*
+ * cifx_handler
+ * cifx interrupt handler
+ */
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info = rtdm_irq_get_arg(irq, void);
+	struct io_info *device_data = info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == 0)
+	    || (device_data->irq_enable == 0)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		if (device_data->irq_registered == 1)
+			rtdm_event_signal(&device_data->irq_event);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+/*
+ *	cifx_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_set_plx_timing(struct ext_io_info *ext_info)
+{
+	uint32_t __iomem *plx_timing;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = ext_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_get_plx_timing(struct ext_io_info *ext_info)
+{
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	switch (ext_info->dpm_mode) {
+	case 8:
+		ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_get_dpm_mode(struct ext_io_info *ext_info)
+{
+	uint32_t __iomem *plx_gpio;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_ioctl_nrt
+ * ioctl
+ */
+static int cifx_pci_ioctl_nrt(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info,
+			      unsigned int request, void *arg)
+{
+	int ret = 0;
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct io_map_mem map_mem;
+
+	switch (request) {
+	case RTCIFX_GET_MEM_INFO:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg,
+					     device_data->mem,
+					     (2 * sizeof(uint32_t)));
+		break;
+
+	case RTCIFX_MMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Map physical on virtual memory */
+		ret = rtdm_iomap_to_user(user_info,
+					 map_mem.phys_addr,
+					 map_mem.length,
+					 (PROT_READ | PROT_WRITE),
+					 (void **)&map_mem.virt_addr,
+					 NULL, NULL);
+		if (ret != 0)
+			break;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg, &map_mem, sizeof(map_mem));
+		break;
+
+	case RTCIFX_MUNMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Unap virtual memory */
+		ret = rtdm_munmap(user_info,
+				  (void *)map_mem.virt_addr, map_mem.length);
+		break;
+
+	case RTCIFX_REQUEST_IRQ:
+		if (device_data->irq_registered == 0) {
+			ret = rtdm_irq_request(&device_data->irq_handle,
+					       device_data->irq,
+					       cifx_handler,
+					       RTDM_IRQTYPE_SHARED,
+					       info->device_name, (void *)info);
+
+			if (ret == 0) {
+				rtdm_event_init(&device_data->irq_event, 0);
+
+				device_data->irq_registered = 1;
+			}
+		}
+		break;
+
+	case RTCIFX_FREE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_free(&device_data->irq_handle);
+
+			if (ret == 0) {
+				device_data->irq_registered = 0;
+
+				rtdm_event_destroy(&device_data->irq_event);
+			}
+		}
+		break;
+
+	case RTCIFX_ENABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_enable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 1;
+		}
+		break;
+
+	case RTCIFX_DISABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_disable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 0;
+		}
+		break;
+
+	case RTCIFX_WAIT_IRQ:
+		if (device_data->irq_enable == 1)
+			ret = -EPERM;
+		else
+			ret = -EAGAIN;
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * cifx_pci_ioctl_rt
+ * ioctl
+ */
+static int cifx_pci_ioctl_rt(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info,
+			     unsigned int request, void *arg)
+{
+	int ret = 0;
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct io_map_mem map_mem;
+
+	switch (request) {
+	case RTCIFX_GET_MEM_INFO:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg,
+					     device_data->mem,
+					     (2 * sizeof(uint32_t)));
+		break;
+
+	case RTCIFX_MMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Map physical on virtual memory */
+		ret = rtdm_iomap_to_user(user_info,
+					 map_mem.phys_addr,
+					 map_mem.length,
+					 (PROT_READ | PROT_WRITE),
+					 (void **)&map_mem.virt_addr,
+					 NULL, NULL);
+		if (ret != 0)
+			break;
+
+		ret = rtdm_safe_copy_to_user(user_info,
+					     arg, &map_mem, sizeof(map_mem));
+		break;
+
+	case RTCIFX_MUNMAP:
+		if (arg == NULL)
+			return -EINVAL;
+
+		ret = rtdm_safe_copy_from_user(user_info,
+					       &map_mem, arg, sizeof(map_mem));
+		if (ret != 0)
+			break;
+
+		/* Unap virtual memory */
+		ret = rtdm_munmap(user_info,
+				  (void *)map_mem.virt_addr, map_mem.length);
+		break;
+
+	case RTCIFX_REQUEST_IRQ:
+		if (device_data->irq_registered == 0) {
+			ret = rtdm_irq_request(&device_data->irq_handle,
+					       device_data->irq,
+					       cifx_handler,
+					       RTDM_IRQTYPE_SHARED,
+					       info->device_name, (void *)info);
+
+			if (ret == 0) {
+				rtdm_event_init(&device_data->irq_event, 0);
+
+				device_data->irq_registered = 1;
+			}
+		}
+		break;
+
+	case RTCIFX_FREE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_free(&device_data->irq_handle);
+
+			if (ret == 0) {
+				device_data->irq_registered = 0;
+
+				rtdm_event_destroy(&device_data->irq_event);
+			}
+		}
+		break;
+
+	case RTCIFX_ENABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_enable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 1;
+		}
+		break;
+
+	case RTCIFX_DISABLE_IRQ:
+		if (device_data->irq_registered == 1) {
+			ret = rtdm_irq_disable(&device_data->irq_handle);
+
+			if (ret == 0)
+				device_data->irq_enable = 0;
+		}
+		break;
+
+	case RTCIFX_WAIT_IRQ:
+		if (device_data->irq_enable == 1) {
+			/* default Timeout 500 ms */
+			ret = rtdm_event_timedwait(&device_data->irq_event,
+						   (500 * 1000 * 1000), NULL);
+		} else {
+			ret = -EAGAIN;
+		}
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info *device_data = NULL;
+	int32_t bar;
+	int32_t ret = -ENODEV;
+
+	/* Allocate device driver structure */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	ret = pci_enable_device(dev);
+	if (ret != 0)
+		goto out_free;
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0)
+		goto out_disable;
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf(info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = kmalloc(sizeof(*device_data), GFP_KERNEL);
+
+	if (device_data == NULL) {
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(*device_data));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
+
+	if (device_data->mem[DPM_INDEX].addr == 0)
+		goto out_release;
+
+	device_data->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (device_data->mem[DPM_INDEX].internal_addr == 0)
+		goto out_release;
+
+	dev_info(&dev->dev, "DPM at %08X\n", device_data->mem[DPM_INDEX].addr);
+	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
+	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	device_data->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (device_data->mem[EXT_MEM_INDEX].addr != 0) {
+		device_data->mem[EXT_MEM_INDEX].internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
+			goto out_unmap;
+
+		dev_info(&dev->dev,
+			 "extended memory at %08X\n",
+			 device_data->mem[EXT_MEM_INDEX].addr);
+		device_data->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+			  + DPM_HOST_INT_EN0);
+		device_data->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct ext_io_info *ext_info;
+
+		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);
+
+		if (ext_info == NULL) {
+			ret = -ENOMEM;
+			goto out_unmap;
+		}
+
+		device_data->priv = ext_info;
+
+		/* set PXA PLX Timings */
+		ext_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (ext_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_get_dpm_mode(ext_info))
+			goto out_unmap_plx;
+		if (cifx_get_plx_timing(ext_info))
+			goto out_unmap_plx;
+		if (cifx_set_plx_timing(ext_info))
+			goto out_unmap_plx;
+	} else {
+		struct ext_io_info *ext_info;
+
+		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);
+
+		if (ext_info == NULL) {
+			ret = -ENOMEM;
+			goto out_free_pxa;
+		}
+
+		ext_info->plx = NULL;
+		ext_info->plx_timing = 0;
+		ext_info->dpm_mode = 0;
+		device_data->priv = ext_info;
+	}
+
+	/* Initialize irq data */
+	device_data->irq = dev->irq;
+	device_data->irq_enable = 0;
+	device_data->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct ext_io_info *ext_info = device_data->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct ext_io_info *)ext_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+out_unmap_plx:
+	iounmap((device_data->priv)->plx);
+
+out_free_pxa:
+	kfree(device_data->priv);
+
+out_unmap:
+	iounmap(device_data->mem[DPM_INDEX].internal_addr);
+	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+out_release:
+	pci_release_regions(dev);
+
+out_disable:
+	pci_disable_device(dev);
+
+out_free:
+	if (info->device_data != NULL)
+		kfree(info->device_data);
+
+	kfree(info);
+
+	return ret;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct ext_io_info *ext_info = cifx_get_private(info);
+
+	if (cifx_num > 0) {
+		if (info->device_data == NULL)
+			return;
+
+		if (ext_info != NULL) {
+			/* Disable all interrupts */
+			iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+				  + DPM_HOST_INT_EN0);
+
+			if (ext_info->plx != NULL)
+				iounmap((void *)ext_info->plx);
+
+			kfree((void *)ext_info);
+		}
+
+		/* Unregister device driver */
+		rtdm_dev_unregister(info, 1000);
+
+		pci_release_regions(dev);
+		pci_disable_device(dev);
+		pci_set_drvdata(dev, NULL);
+
+		/* Unmap memory */
+		iounmap(device_data->mem[DPM_INDEX].internal_addr);
+		if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+			iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+		/* Release structure memory allocation */
+		kfree(info->device_data);
+		kfree(info);
+
+		cifx_num--;
+	}
+}
+
+static int __init cifx_pci_init(void)
+{
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-15 13:24                                                               ` Jan Kiszka
@ 2013-03-18 10:02                                                                 ` Jerome Poncin
  2013-03-19 13:42                                                                   ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-18 10:02 UTC (permalink / raw)
  To: xenomai

Le 15/03/2013 14:24, Jan Kiszka a écrit :
> On 2013-03-15 14:04, Jerome Poncin wrote:
>> Hello Jan,
>>
>> Yes you're right. I have 1 thread for test (main) application and the
>> driver create one or two thread if IRQ or polling is enable.
>> The driver thread are loop waiting event with delay.
>> At Driver start it take few second to download firmware and configuration.
>> My question is why it's a problem to have a real time that that run few
>> second.
>> If this task have the bigger priority, it's normal to not release hand
>> and to not sleep, I'm right or not ?
> Linux is not capable (yet) of handling the case that an online CPU is
> 100% occupied. Sooner or later, the whole (Linux) system will lock up,
> also the timekeeping can be negatively affected. That's nothing Xenomai
> can change.
>
> Therefore, every real-time task has to behave properly, sleep on
> asynchronous external events or suspend itself for a certain while when
> there is nothing to do. In good real-time designs, that is usually no
> problem, specifically if the number of tasks is moderate and the
> workload is clear. I've seen less obvious problems in large
> applications, but those were typically bugs as well.
>
> Jan
>
Hello Jan,

I investigated my problem and the problem come from some lock on thread.
I think my thread management is not correct... I
Is there an example in posix with multiple thread management ?

Thank you for your help,

Jerome


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-15 13:04                                                             ` Jerome Poncin
@ 2013-03-15 13:24                                                               ` Jan Kiszka
  2013-03-18 10:02                                                                 ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-03-15 13:24 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-03-15 14:04, Jerome Poncin wrote:
> Hello Jan,
> 
> Yes you're right. I have 1 thread for test (main) application and the
> driver create one or two thread if IRQ or polling is enable.
> The driver thread are loop waiting event with delay.
> At Driver start it take few second to download firmware and configuration.
> My question is why it's a problem to have a real time that that run few
> second.
> If this task have the bigger priority, it's normal to not release hand
> and to not sleep, I'm right or not ?

Linux is not capable (yet) of handling the case that an online CPU is
100% occupied. Sooner or later, the whole (Linux) system will lock up,
also the timekeeping can be negatively affected. That's nothing Xenomai
can change.

Therefore, every real-time task has to behave properly, sleep on
asynchronous external events or suspend itself for a certain while when
there is nothing to do. In good real-time designs, that is usually no
problem, specifically if the number of tasks is moderate and the
workload is clear. I've seen less obvious problems in large
applications, but those were typically bugs as well.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-15 11:07                                                           ` Jan Kiszka
@ 2013-03-15 13:04                                                             ` Jerome Poncin
  2013-03-15 13:24                                                               ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-15 13:04 UTC (permalink / raw)
  To: xenomai

Le 15/03/2013 12:07, Jan Kiszka a écrit :
> On 2013-03-15 10:09, Jerome Poncin wrote:
>> Le 13/03/2013 12:08, Jerome Poncin a écrit :
>>> Le 12/03/2013 20:38, Gilles Chanteperdrix a écrit :
>>>> On 03/12/2013 04:27 PM, Jerome Poncin wrote:
>>>>
>>>>> Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
>>>>>> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>>>>>>
>>>>>>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>>>>>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>>>>>>
>>>>>>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>>>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>>>>>>> something like "MMAP" and another one with MUNMAP in its name
>>>>>>>>>>>> - that's
>>>>>>>>>>>> the purpose of this service, no?
>>>>>>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>>>>>>> parameters for an mmap, why not adding an "mmap" method to
>>>>>>>>>>> RTDM drivers?
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>> Hello,
>>>>>>>>>>
>>>>>>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>>>>>>
>>>>>>>>>> Could you say me if it's correct now ?
>>>>>>>>>>
>>>>>>>>>> Jan, you're right, It's possible to use Xenomai with UIO
>>>>>>>>>> driver, but I
>>>>>>>>>> would like to use more real time possibilities of Xenomai in
>>>>>>>>>> future
>>>>>>>>>> (like IRQ).
>>>>>>>>>> My first goal is to have a code compliant.
>>>>>>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>>>>>>> crash after IRQ registration.
>>>>>>>>>>
>>>>>>>>>> Thank you for your help,
>>>>>>>>>>
>>>>>>>>>> Jerome
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> Hello,
>>>>>>>>>
>>>>>>>>> I have good news because, I arrived to validated driver with IRQ
>>>>>>>>> support. I changed position of cifx on my motherboard in my PC
>>>>>>>>> and the
>>>>>>>>> IRQ affected is not shared ;-) !
>>>>>>>>>
>>>>>>>>> I have now a question about IRQ. What is the good method to
>>>>>>>>> signal to
>>>>>>>>> user-land that there is an IRQ. Is there an example ?
>>>>>>>> Almost every "read" call is an example... ;-)
>>>>>>>>
>>>>>>> Hello,
>>>>>>>
>>>>>>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>>>>>>> time and Non real time for RTDM driver function.
>>>>>>> My driver should run in the two mode. When I compile my User Space
>>>>>>> Shared library that call Xenomai Kernel driver,
>>>>>>> I saw that library call every time Non real time function and no real
>>>>>>> time function...
>>>>>>> I use a shared library with posix skin with makefile in attached
>>>>>>> file. I
>>>>>>> read explanation for static library with posix skin :
>>>>>>>
>>>>>>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>>>>>>
>>>>>>>
>>>>>>> What must I do with shared library for using rt mode ?
>>>>>> Use the LDLIBS variable when linking the library?
>>>>>>
>>>>> Gilles,
>>>>>
>>>>> you're right ;-), I didn't use LDLIBS for linking the library,
>>>>> therefore
>>>>> I corrected this.
>>>>>
>>>>> Now I have this as link line for my library :
>>>>>
>>>>> gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib
>>>>> -I/usr/xenomai/include/include/xenomai
>>>>> -I/usr/xenomai/include/include/xenomai/compat
>>>>> -I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit
>>>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>>>> -lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o
>>>>> .//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o
>>>>> .//cifXInit.o
>>>>> .//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o
>>>>> .//USER_xenomai.o
>>>>>
>>>>> and this for the application :
>>>>>
>>>>> gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT
>>>>> -D__XENO__ -I/usr/xenomai/include/posix -I../libcifx
>>>>> -I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath
>>>>> -Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c
>>>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>>>> -lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o
>>>>> cifx_xenomai_sample
>>>>>
>>>>> with
>>>>>
>>>>> mlockall(MCL_CURRENT | MCL_FUTURE);
>>>>>
>>>>>
>>>>> first line in main
>>>>>
>>>>> I have a new log :
>>>>>
>>>>> [ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low)
>>>>> -> IRQ 16
>>>>> [ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
>>>>> [ 4700.073654] cifx 0000:04:01.0: registered CifX card
>>>>> [ 4734.146888] NRT mode
>>>>> [ 4751.104009] rt
>>>>> [ 4751.388002] Xenomai: Posix: destroying mutex f8419600.
>>>>>
>>>>> But as you see It seems I'm always in Non Real Time mode...
>>>> I do not see anything, as I do not see the sources for either your
>>>> driver or application.
>>>>
>>>>> Do you have an idea about my problem ?
>>>>>
>>>>> The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is
>>>>> normal ?
>>>> It depends if you consider normal leaving an application with a mutex
>>>> created but not destroyed.
>>> Hello Gilles,
>>>
>>> First, I checked mutex Creation and Destroy and all is correct all
>>> created are destroyed... I will continue to investigate, it's very
>>> strange !
>>> Secondly, I read that if a program use file or stdio library "causes
>>> switches to secondary mode".
>>> In my shared library, I have read file and fprintf at start
>>> (initialization), therefore I think that's why the library run in NRT
>>> mode.
>>> But is possible to switch in RT mode after, or must I do two thread ?
>>>
>>> thank you for your help,
>>>
>>> Jerome
>> Hello,
>>
>> I found why I have the log :
>>
>> Xenomai: Posix: destroying mutex f8419600.
>>
>> My application seems stop by the watchdog :
>>
>> Temps UCT limite expiré (core dumped)
>>
>> I tried to disable Xenomai watchdog without success, and I try to
>> increase "ulimit" without success too.
>>
>> How to disable CPU time watchdog for real time mode ?
> The problem is not the watchdog but some bug in your application or
> driver. It causes a real-time task to run for multiple seconds without
> sleeping. That is what the watchdog triggers. Check what is causing this
> endless loop and resolve it.
>
> Jan
>
Hello Jan,

Yes you're right. I have 1 thread for test (main) application and the 
driver create one or two thread if IRQ or polling is enable.
The driver thread are loop waiting event with delay.
At Driver start it take few second to download firmware and configuration.
My question is why it's a problem to have a real time that that run few 
second.
If this task have the bigger priority, it's normal to not release hand 
and to not sleep, I'm right or not ?

Thank you for your help,

Jerome







^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-15  9:09                                                         ` Jerome Poncin
@ 2013-03-15 11:07                                                           ` Jan Kiszka
  2013-03-15 13:04                                                             ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-03-15 11:07 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-03-15 10:09, Jerome Poncin wrote:
> Le 13/03/2013 12:08, Jerome Poncin a écrit :
>> Le 12/03/2013 20:38, Gilles Chanteperdrix a écrit :
>>> On 03/12/2013 04:27 PM, Jerome Poncin wrote:
>>>
>>>> Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
>>>>> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>>>>>
>>>>>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>>>>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>>>>>
>>>>>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>>>>>
>>>>>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>>>>>> something like "MMAP" and another one with MUNMAP in its name
>>>>>>>>>>> - that's
>>>>>>>>>>> the purpose of this service, no?
>>>>>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>>>>>> parameters for an mmap, why not adding an "mmap" method to
>>>>>>>>>> RTDM drivers?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>> Hello,
>>>>>>>>>
>>>>>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>>>>>
>>>>>>>>> Could you say me if it's correct now ?
>>>>>>>>>
>>>>>>>>> Jan, you're right, It's possible to use Xenomai with UIO
>>>>>>>>> driver, but I
>>>>>>>>> would like to use more real time possibilities of Xenomai in
>>>>>>>>> future
>>>>>>>>> (like IRQ).
>>>>>>>>> My first goal is to have a code compliant.
>>>>>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>>>>>> crash after IRQ registration.
>>>>>>>>>
>>>>>>>>> Thank you for your help,
>>>>>>>>>
>>>>>>>>> Jerome
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Hello,
>>>>>>>>
>>>>>>>> I have good news because, I arrived to validated driver with IRQ
>>>>>>>> support. I changed position of cifx on my motherboard in my PC
>>>>>>>> and the
>>>>>>>> IRQ affected is not shared ;-) !
>>>>>>>>
>>>>>>>> I have now a question about IRQ. What is the good method to
>>>>>>>> signal to
>>>>>>>> user-land that there is an IRQ. Is there an example ?
>>>>>>> Almost every "read" call is an example... ;-)
>>>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>>>>>> time and Non real time for RTDM driver function.
>>>>>> My driver should run in the two mode. When I compile my User Space
>>>>>> Shared library that call Xenomai Kernel driver,
>>>>>> I saw that library call every time Non real time function and no real
>>>>>> time function...
>>>>>> I use a shared library with posix skin with makefile in attached
>>>>>> file. I
>>>>>> read explanation for static library with posix skin :
>>>>>>
>>>>>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>>>>>
>>>>>>
>>>>>> What must I do with shared library for using rt mode ?
>>>>> Use the LDLIBS variable when linking the library?
>>>>>
>>>> Gilles,
>>>>
>>>> you're right ;-), I didn't use LDLIBS for linking the library,
>>>> therefore
>>>> I corrected this.
>>>>
>>>> Now I have this as link line for my library :
>>>>
>>>> gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib
>>>> -I/usr/xenomai/include/include/xenomai
>>>> -I/usr/xenomai/include/include/xenomai/compat
>>>> -I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit
>>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>>> -lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o
>>>> .//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o
>>>> .//cifXInit.o
>>>> .//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o
>>>> .//USER_xenomai.o
>>>>
>>>> and this for the application :
>>>>
>>>> gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT
>>>> -D__XENO__ -I/usr/xenomai/include/posix -I../libcifx
>>>> -I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath
>>>> -Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c
>>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>>> -lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o
>>>> cifx_xenomai_sample
>>>>
>>>> with
>>>>
>>>> mlockall(MCL_CURRENT | MCL_FUTURE);
>>>>
>>>>
>>>> first line in main
>>>>
>>>> I have a new log :
>>>>
>>>> [ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low)
>>>> -> IRQ 16
>>>> [ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
>>>> [ 4700.073654] cifx 0000:04:01.0: registered CifX card
>>>> [ 4734.146888] NRT mode
>>>> [ 4751.104009] rt
>>>> [ 4751.388002] Xenomai: Posix: destroying mutex f8419600.
>>>>
>>>> But as you see It seems I'm always in Non Real Time mode...
>>> I do not see anything, as I do not see the sources for either your
>>> driver or application.
>>>
>>>> Do you have an idea about my problem ?
>>>>
>>>> The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is
>>>> normal ?
>>> It depends if you consider normal leaving an application with a mutex
>>> created but not destroyed.
>> Hello Gilles,
>>
>> First, I checked mutex Creation and Destroy and all is correct all
>> created are destroyed... I will continue to investigate, it's very
>> strange !
>> Secondly, I read that if a program use file or stdio library "causes
>> switches to secondary mode".
>> In my shared library, I have read file and fprintf at start
>> (initialization), therefore I think that's why the library run in NRT
>> mode.
>> But is possible to switch in RT mode after, or must I do two thread ?
>>
>> thank you for your help,
>>
>> Jerome
> Hello,
> 
> I found why I have the log :
> 
> Xenomai: Posix: destroying mutex f8419600.
> 
> My application seems stop by the watchdog :
> 
> Temps UCT limite expiré (core dumped)
> 
> I tried to disable Xenomai watchdog without success, and I try to
> increase "ulimit" without success too.
> 
> How to disable CPU time watchdog for real time mode ?

The problem is not the watchdog but some bug in your application or
driver. It causes a real-time task to run for multiple seconds without
sleeping. That is what the watchdog triggers. Check what is causing this
endless loop and resolve it.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-13 11:08                                                       ` Jerome Poncin
@ 2013-03-15  9:09                                                         ` Jerome Poncin
  2013-03-15 11:07                                                           ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-15  9:09 UTC (permalink / raw)
  To: xenomai

Le 13/03/2013 12:08, Jerome Poncin a écrit :
> Le 12/03/2013 20:38, Gilles Chanteperdrix a écrit :
>> On 03/12/2013 04:27 PM, Jerome Poncin wrote:
>>
>>> Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
>>>> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>>>>
>>>>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>>>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>>>>
>>>>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>>>>
>>>>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>>>>>>> the purpose of this service, no?
>>>>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>>>>>>
>>>>>>>>>
>>>>>>>> Hello,
>>>>>>>>
>>>>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>>>>
>>>>>>>> Could you say me if it's correct now ?
>>>>>>>>
>>>>>>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>>>>>>> would like to use more real time possibilities of Xenomai in future
>>>>>>>> (like IRQ).
>>>>>>>> My first goal is to have a code compliant.
>>>>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>>>>> crash after IRQ registration.
>>>>>>>>
>>>>>>>> Thank you for your help,
>>>>>>>>
>>>>>>>> Jerome
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>> Hello,
>>>>>>>
>>>>>>> I have good news because, I arrived to validated driver with IRQ
>>>>>>> support. I changed position of cifx on my motherboard in my PC and the
>>>>>>> IRQ affected is not shared ;-) !
>>>>>>>
>>>>>>> I have now a question about IRQ. What is the good method to signal to
>>>>>>> user-land that there is an IRQ. Is there an example ?
>>>>>> Almost every "read" call is an example... ;-)
>>>>>>
>>>>> Hello,
>>>>>
>>>>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>>>>> time and Non real time for RTDM driver function.
>>>>> My driver should run in the two mode. When I compile my User Space
>>>>> Shared library that call Xenomai Kernel driver,
>>>>> I saw that library call every time Non real time function and no real
>>>>> time function...
>>>>> I use a shared library with posix skin with makefile in attached file. I
>>>>> read explanation for static library with posix skin :
>>>>>
>>>>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>>>>
>>>>> What must I do with shared library for using rt mode ?
>>>> Use the LDLIBS variable when linking the library?
>>>>
>>> Gilles,
>>>
>>> you're right ;-), I didn't use LDLIBS for linking the library, therefore
>>> I corrected this.
>>>
>>> Now I have this as link line for my library :
>>>
>>> gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib
>>> -I/usr/xenomai/include/include/xenomai
>>> -I/usr/xenomai/include/include/xenomai/compat
>>> -I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit
>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>> -lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o
>>> .//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o .//cifXInit.o
>>> .//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o
>>> .//USER_xenomai.o
>>>
>>> and this for the application :
>>>
>>> gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT
>>> -D__XENO__ -I/usr/xenomai/include/posix -I../libcifx
>>> -I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath
>>> -Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c
>>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>>> -lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o cifx_xenomai_sample
>>>
>>> with
>>>
>>> mlockall(MCL_CURRENT | MCL_FUTURE);
>>>
>>>
>>> first line in main
>>>
>>> I have a new log :
>>>
>>> [ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
>>> [ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
>>> [ 4700.073654] cifx 0000:04:01.0: registered CifX card
>>> [ 4734.146888] NRT mode
>>> [ 4751.104009] rt
>>> [ 4751.388002] Xenomai: Posix: destroying mutex f8419600.
>>>
>>> But as you see It seems I'm always in Non Real Time mode...
>> I do not see anything, as I do not see the sources for either your
>> driver or application.
>>
>>> Do you have an idea about my problem ?
>>>
>>> The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is normal ?
>> It depends if you consider normal leaving an application with a mutex
>> created but not destroyed.
> Hello Gilles,
>
> First, I checked mutex Creation and Destroy and all is correct all 
> created are destroyed... I will continue to investigate, it's very 
> strange !
> Secondly, I read that if a program use file or stdio library "causes 
> switches to secondary mode".
> In my shared library, I have read file and fprintf at start 
> (initialization), therefore I think that's why the library run in NRT 
> mode.
> But is possible to switch in RT mode after, or must I do two thread ?
>
> thank you for your help,
>
> Jerome
Hello,

I found why I have the log :

Xenomai: Posix: destroying mutex f8419600.

My application seems stop by the watchdog :

Temps UCT limite expiré (core dumped)

I tried to disable Xenomai watchdog without success, and I try to 
increase "ulimit" without success too.

How to disable CPU time watchdog for real time mode ?

Thank your or your help,

Jerome






^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-12 19:38                                                     ` Gilles Chanteperdrix
@ 2013-03-13 11:08                                                       ` Jerome Poncin
  2013-03-15  9:09                                                         ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-13 11:08 UTC (permalink / raw)
  To: xenomai

Le 12/03/2013 20:38, Gilles Chanteperdrix a écrit :
> On 03/12/2013 04:27 PM, Jerome Poncin wrote:
>
>> Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
>>> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>>>
>>>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>>>
>>>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>>>
>>>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>>>>>> the purpose of this service, no?
>>>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>>>>>
>>>>>>>>
>>>>>>> Hello,
>>>>>>>
>>>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>>>
>>>>>>> Could you say me if it's correct now ?
>>>>>>>
>>>>>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>>>>>> would like to use more real time possibilities of Xenomai in future
>>>>>>> (like IRQ).
>>>>>>> My first goal is to have a code compliant.
>>>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>>>> crash after IRQ registration.
>>>>>>>
>>>>>>> Thank you for your help,
>>>>>>>
>>>>>>> Jerome
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> I have good news because, I arrived to validated driver with IRQ
>>>>>> support. I changed position of cifx on my motherboard in my PC and the
>>>>>> IRQ affected is not shared ;-) !
>>>>>>
>>>>>> I have now a question about IRQ. What is the good method to signal to
>>>>>> user-land that there is an IRQ. Is there an example ?
>>>>> Almost every "read" call is an example... ;-)
>>>>>
>>>> Hello,
>>>>
>>>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>>>> time and Non real time for RTDM driver function.
>>>> My driver should run in the two mode. When I compile my User Space
>>>> Shared library that call Xenomai Kernel driver,
>>>> I saw that library call every time Non real time function and no real
>>>> time function...
>>>> I use a shared library with posix skin with makefile in attached file. I
>>>> read explanation for static library with posix skin :
>>>>
>>>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>>>
>>>> What must I do with shared library for using rt mode ?
>>> Use the LDLIBS variable when linking the library?
>>>
>> Gilles,
>>
>> you're right ;-), I didn't use LDLIBS for linking the library, therefore
>> I corrected this.
>>
>> Now I have this as link line for my library :
>>
>> gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib
>> -I/usr/xenomai/include/include/xenomai
>> -I/usr/xenomai/include/include/xenomai/compat
>> -I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit
>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>> -lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o
>> .//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o .//cifXInit.o
>> .//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o
>> .//USER_xenomai.o
>>
>> and this for the application :
>>
>> gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT
>> -D__XENO__ -I/usr/xenomai/include/posix -I../libcifx
>> -I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath
>> -Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c
>> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt
>> -lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o cifx_xenomai_sample
>>
>> with
>>
>> mlockall(MCL_CURRENT | MCL_FUTURE);
>>
>>
>> first line in main
>>
>> I have a new log :
>>
>> [ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
>> [ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
>> [ 4700.073654] cifx 0000:04:01.0: registered CifX card
>> [ 4734.146888] NRT mode
>> [ 4751.104009] rt
>> [ 4751.388002] Xenomai: Posix: destroying mutex f8419600.
>>
>> But as you see It seems I'm always in Non Real Time mode...
>
> I do not see anything, as I do not see the sources for either your
> driver or application.
>
>> Do you have an idea about my problem ?
>>
>> The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is normal ?
>
> It depends if you consider normal leaving an application with a mutex
> created but not destroyed.
Hello Gilles,

First, I checked mutex Creation and Destroy and all is correct all 
created are destroyed... I will continue to investigate, it's very strange !
Secondly, I read that if a program use file or stdio library "causes 
switches to secondary mode".
In my shared library, I have read file and fprintf at start 
(initialization), therefore I think that's why the library run in NRT mode.
But is possible to switch in RT mode after, or must I do two thread ?

thank you for your help,

Jerome

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-12 15:27                                                   ` Jerome Poncin
@ 2013-03-12 19:38                                                     ` Gilles Chanteperdrix
  2013-03-13 11:08                                                       ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-12 19:38 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/12/2013 04:27 PM, Jerome Poncin wrote:

> Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
>> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>>
>>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>>
>>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>>
>>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>>>>> the purpose of this service, no?
>>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>>>>
>>>>>>>
>>>>>> Hello,
>>>>>>
>>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>>
>>>>>> Could you say me if it's correct now ?
>>>>>>
>>>>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>>>>> would like to use more real time possibilities of Xenomai in future
>>>>>> (like IRQ).
>>>>>> My first goal is to have a code compliant.
>>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>>> crash after IRQ registration.
>>>>>>
>>>>>> Thank you for your help,
>>>>>>
>>>>>> Jerome
>>>>>>
>>>>>>
>>>>>>
>>>>> Hello,
>>>>>
>>>>> I have good news because, I arrived to validated driver with IRQ
>>>>> support. I changed position of cifx on my motherboard in my PC and the
>>>>> IRQ affected is not shared ;-) !
>>>>>
>>>>> I have now a question about IRQ. What is the good method to signal to
>>>>> user-land that there is an IRQ. Is there an example ?
>>>> Almost every "read" call is an example... ;-)
>>>>
>>> Hello,
>>>
>>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>>> time and Non real time for RTDM driver function.
>>> My driver should run in the two mode. When I compile my User Space
>>> Shared library that call Xenomai Kernel driver,
>>> I saw that library call every time Non real time function and no real
>>> time function...
>>> I use a shared library with posix skin with makefile in attached file. I
>>> read explanation for static library with posix skin :
>>>
>>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>>
>>> What must I do with shared library for using rt mode ?
>>
>> Use the LDLIBS variable when linking the library?
>>
> Gilles,
> 
> you're right ;-), I didn't use LDLIBS for linking the library, therefore 
> I corrected this.
> 
> Now I have this as link line for my library :
> 
> gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib 
> -I/usr/xenomai/include/include/xenomai 
> -I/usr/xenomai/include/include/xenomai/compat 
> -I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit 
> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt 
> -lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o 
> .//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o .//cifXInit.o 
> .//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o 
> .//USER_xenomai.o
> 
> and this for the application :
> 
> gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT 
> -D__XENO__ -I/usr/xenomai/include/posix -I../libcifx 
> -I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath 
> -Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c 
> -Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt 
> -lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o cifx_xenomai_sample
> 
> with
> 
> mlockall(MCL_CURRENT | MCL_FUTURE);
> 
> 
> first line in main
> 
> I have a new log :
> 
> [ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
> [ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
> [ 4700.073654] cifx 0000:04:01.0: registered CifX card
> [ 4734.146888] NRT mode
> [ 4751.104009] rt
> [ 4751.388002] Xenomai: Posix: destroying mutex f8419600.
> 
> But as you see It seems I'm always in Non Real Time mode...


I do not see anything, as I do not see the sources for either your
driver or application.

> 
> Do you have an idea about my problem ?
> 

> The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is normal ?


It depends if you consider normal leaving an application with a mutex
created but not destroyed.

-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-12 12:21                                                 ` Gilles Chanteperdrix
@ 2013-03-12 15:27                                                   ` Jerome Poncin
  2013-03-12 19:38                                                     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-12 15:27 UTC (permalink / raw)
  To: xenomai

Le 12/03/2013 13:21, Gilles Chanteperdrix a écrit :
> On 03/12/2013 10:10 AM, Jerome Poncin wrote:
>
>> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>>
>>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>>
>>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>>>> the purpose of this service, no?
>>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>>>
>>>>>>
>>>>> Hello,
>>>>>
>>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>>
>>>>> Could you say me if it's correct now ?
>>>>>
>>>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>>>> would like to use more real time possibilities of Xenomai in future
>>>>> (like IRQ).
>>>>> My first goal is to have a code compliant.
>>>>> I added IRQ, and my next step will be to understand why the kernel
>>>>> crash after IRQ registration.
>>>>>
>>>>> Thank you for your help,
>>>>>
>>>>> Jerome
>>>>>
>>>>>
>>>>>
>>>> Hello,
>>>>
>>>> I have good news because, I arrived to validated driver with IRQ
>>>> support. I changed position of cifx on my motherboard in my PC and the
>>>> IRQ affected is not shared ;-) !
>>>>
>>>> I have now a question about IRQ. What is the good method to signal to
>>>> user-land that there is an IRQ. Is there an example ?
>>> Almost every "read" call is an example... ;-)
>>>
>> Hello,
>>
>> I'm finishing my driver with IRQ. I saw that there is two mode, Real
>> time and Non real time for RTDM driver function.
>> My driver should run in the two mode. When I compile my User Space
>> Shared library that call Xenomai Kernel driver,
>> I saw that library call every time Non real time function and no real
>> time function...
>> I use a shared library with posix skin with makefile in attached file. I
>> read explanation for static library with posix skin :
>>
>> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
>>
>> What must I do with shared library for using rt mode ?
>
> Use the LDLIBS variable when linking the library?
>
Gilles,

you're right ;-), I didn't use LDLIBS for linking the library, therefore 
I corrected this.

Now I have this as link line for my library :

gcc -shared -Xlinker -rpath -Xlinker /usr/xenomai/lib 
-I/usr/xenomai/include/include/xenomai 
-I/usr/xenomai/include/include/xenomai/compat 
-I/usr/xenomai/include/include/xenomai/posix -I./ -I.//Toolkit 
-Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt 
-lxenomai -lpthread -lrt -o libcifx.so .//cifXDownload.o 
.//cifXEndianess.o .//cifXFunctions.o .//cifXHWFunctions.o .//cifXInit.o 
.//cifXInterrupt.o .//md5.o   .//cifx_xenomai.o .//OS_xenomai.o 
.//USER_xenomai.o

and this for the application :

gcc -DCONSUMER -I/usr/xenomai/include -D_GNU_SOURCE -D_REENTRANT 
-D__XENO__ -I/usr/xenomai/include/posix -I../libcifx 
-I../libcifx/Toolkit -O2   -lcifx -lpciaccess -lrtdm -Xlinker -rpath 
-Xlinker /usr/xenomai/lib  cifx_xenomai_sample.c 
-Wl,@/usr/xenomai/lib/posix.wrappers -L/usr/xenomai/lib -lpthread_rt 
-lxenomai -lpthread -lrt -lcifx -lpciaccess -lrtdm -o cifx_xenomai_sample

with

mlockall(MCL_CURRENT | MCL_FUTURE);


first line in main

I have a new log :

[ 4700.073616] cifx 0000:04:01.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 4700.073643] cifx 0000:04:01.0: DPM at FEBF0000
[ 4700.073654] cifx 0000:04:01.0: registered CifX card
[ 4734.146888] NRT mode
[ 4751.104009] rt
[ 4751.388002] Xenomai: Posix: destroying mutex f8419600.

But as you see It seems I'm always in Non Real Time mode...

Do you have an idea about my problem ?

The log "rt" and " Xenomai: Posix: destroying mutex f8419600." is normal ?

Thank you for your help,

Jerome


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-12  9:10                                               ` Jerome Poncin
@ 2013-03-12 12:21                                                 ` Gilles Chanteperdrix
  2013-03-12 15:27                                                   ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-12 12:21 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/12/2013 10:10 AM, Jerome Poncin wrote:

> Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
>> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>>
>>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>>
>>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>>> the purpose of this service, no?
>>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>>
>>>>>
>>>> Hello,
>>>>
>>>> I  re factored my code with all your remarks (I think and I hope).
>>>>
>>>> Could you say me if it's correct now ?
>>>>
>>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>>> would like to use more real time possibilities of Xenomai in future
>>>> (like IRQ).
>>>> My first goal is to have a code compliant.
>>>> I added IRQ, and my next step will be to understand why the kernel
>>>> crash after IRQ registration.
>>>>
>>>> Thank you for your help,
>>>>
>>>> Jerome
>>>>
>>>>
>>>>
>>> Hello,
>>>
>>> I have good news because, I arrived to validated driver with IRQ
>>> support. I changed position of cifx on my motherboard in my PC and the
>>> IRQ affected is not shared ;-) !
>>>
>>> I have now a question about IRQ. What is the good method to signal to
>>> user-land that there is an IRQ. Is there an example ?
>>
>> Almost every "read" call is an example... ;-)
>>
> Hello,
> 
> I'm finishing my driver with IRQ. I saw that there is two mode, Real 
> time and Non real time for RTDM driver function.
> My driver should run in the two mode. When I compile my User Space 
> Shared library that call Xenomai Kernel driver,
> I saw that library call every time Non real time function and no real 
> time function...
> I use a shared library with posix skin with makefile in attached file. I 
> read explanation for static library with posix skin :
> 
> http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai
> 
> What must I do with shared library for using rt mode ?


Use the LDLIBS variable when linking the library?

-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-08 12:22                                             ` Gilles Chanteperdrix
@ 2013-03-12  9:10                                               ` Jerome Poncin
  2013-03-12 12:21                                                 ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-12  9:10 UTC (permalink / raw)
  To: xenomai

Le 08/03/2013 13:22, Gilles Chanteperdrix a écrit :
> On 03/08/2013 11:17 AM, Jerome Poncin wrote:
>
>> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>>
>>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>>> the purpose of this service, no?
>>>> A lot of drivers probably have to reinvent a way to pass all the
>>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>>
>>>>
>>> Hello,
>>>
>>> I  re factored my code with all your remarks (I think and I hope).
>>>
>>> Could you say me if it's correct now ?
>>>
>>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I
>>> would like to use more real time possibilities of Xenomai in future
>>> (like IRQ).
>>> My first goal is to have a code compliant.
>>> I added IRQ, and my next step will be to understand why the kernel
>>> crash after IRQ registration.
>>>
>>> Thank you for your help,
>>>
>>> Jerome
>>>
>>>
>>>
>> Hello,
>>
>> I have good news because, I arrived to validated driver with IRQ
>> support. I changed position of cifx on my motherboard in my PC and the
>> IRQ affected is not shared ;-) !
>>
>> I have now a question about IRQ. What is the good method to signal to
>> user-land that there is an IRQ. Is there an example ?
>
> Almost every "read" call is an example... ;-)
>
Hello,

I'm finishing my driver with IRQ. I saw that there is two mode, Real 
time and Non real time for RTDM driver function.
My driver should run in the two mode. When I compile my User Space 
Shared library that call Xenomai Kernel driver,
I saw that library call every time Non real time function and no real 
time function...
I use a shared library with posix skin with makefile in attached file. I 
read explanation for static library with posix skin :

http://www.xenomai.org/index.php/Porting_POSIX_applications_to_Xenomai

What must I do with shared library for using rt mode ?

Jerome



-------------- next part --------------
# ------------------------------------------------------------------------------
# line below should not be changed
# ------------------------------------------------------------------------------
### Default Xenomai installation path
XENO ?= /usr/xenomai

XENOCONFIG=$(shell PATH=$(XENO):$(XENO)/bin:$(PATH) which xeno-config 2>/dev/null)

### Sanity check
ifeq ($(XENOCONFIG),)
all::
	@echo ">>> Invoke make like this: \"make XENO=/path/to/xeno-config\" <<<"
	@echo
endif


CC=$(shell $(XENOCONFIG) --cc)

CFLAGS=-DCONSUMER $(shell $(XENOCONFIG) --skin=posix --cflags) $(MY_CFLAGS)

LDFLAGS=$(MY_LDFLAGS)
LDLIBS=$(shell $(XENOCONFIG) --skin=posix --ldflags)

# This includes the library path of given Xenomai into the binary to make live
# easier for beginners if Xenomai's libs are not in any default search path.
LDFLAGS+=-Xlinker -rpath -Xlinker $(shell $(XENOCONFIG) --libdir)

KSRC ?= /usr/xenomai/include
LSRC ?= ./
TKSRC ?= ./Toolkit

INCLUDE := -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/compat -I$(KSRC)/include/xenomai/posix -I$(LSRC) -I$(LSRC)/Toolkit

EXTRA_CFLAGS := -Wall -fpic -O2 # -DVERBOSE
EXTRA_LDFLAGS := -L/usr/xenomai/lib -shared

all: 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXDownload.c
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXEndianess.c
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXFunctions.c
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXHWFunctions.c
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXInit.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/cifXInterrupt.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(TKSRC)/md5.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(LSRC)/cifx_xenomai.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(LSRC)/OS_xenomai.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_CFLAGS) -c $(LSRC)/USER_xenomai.c 
	$(CC) $(CFLAGS) $(INCLUDE) $(EXTRA_LDFLAGS) -o libcifx.so $(LSRC)/cifXDownload.o $(LSRC)/cifXEndianess.o $(LSRC)/cifXFunctions.o $(LSRC)/cifXHWFunctions.o $(LSRC)/cifXInit.o $(LSRC)/cifXInterrupt.o $(LSRC)/md5.o   $(LSRC)/cifx_xenomai.o $(LSRC)/OS_xenomai.o $(LSRC)/USER_xenomai.o $(EXTRA_LDFLAGS)

clean:
	rm -f *.o *.so

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-08 10:17                                           ` Jerome Poncin
@ 2013-03-08 12:22                                             ` Gilles Chanteperdrix
  2013-03-12  9:10                                               ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-08 12:22 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/08/2013 11:17 AM, Jerome Poncin wrote:

> Le 07/03/2013 16:33, Jerome Poncin a écrit :
>> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>>
>>>> Also here: Do not misuse write(), define an IOCTL that contains
>>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>>> the purpose of this service, no?
>>>
>>> A lot of drivers probably have to reinvent a way to pass all the
>>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>>
>>>
>> Hello,
>>
>> I  re factored my code with all your remarks (I think and I hope).
>>
>> Could you say me if it's correct now ?
>>
>> Jan, you're right, It's possible to use Xenomai with UIO driver, but I 
>> would like to use more real time possibilities of Xenomai in future 
>> (like IRQ).
>> My first goal is to have a code compliant.
>> I added IRQ, and my next step will be to understand why the kernel 
>> crash after IRQ registration.
>>
>> Thank you for your help,
>>
>> Jerome
>>
>>
>>
> Hello,
> 
> I have good news because, I arrived to validated driver with IRQ 
> support. I changed position of cifx on my motherboard in my PC and the 
> IRQ affected is not shared ;-) !
> 
> I have now a question about IRQ. What is the good method to signal to 
> user-land that there is an IRQ. Is there an example ?


Almost every "read" call is an example... ;-)

-- 
                                                                Gilles.



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-07 15:33                                         ` Jerome Poncin
@ 2013-03-08 10:17                                           ` Jerome Poncin
  2013-03-08 12:22                                             ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-08 10:17 UTC (permalink / raw)
  Cc: xenomai

Le 07/03/2013 16:33, Jerome Poncin a écrit :
> Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
>> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>>
>>> Also here: Do not misuse write(), define an IOCTL that contains
>>> something like "MMAP" and another one with MUNMAP in its name - that's
>>> the purpose of this service, no?
>>
>> A lot of drivers probably have to reinvent a way to pass all the
>> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>>
>>
> Hello,
>
> I  re factored my code with all your remarks (I think and I hope).
>
> Could you say me if it's correct now ?
>
> Jan, you're right, It's possible to use Xenomai with UIO driver, but I 
> would like to use more real time possibilities of Xenomai in future 
> (like IRQ).
> My first goal is to have a code compliant.
> I added IRQ, and my next step will be to understand why the kernel 
> crash after IRQ registration.
>
> Thank you for your help,
>
> Jerome
>
>
>
Hello,

I have good news because, I arrived to validated driver with IRQ 
support. I changed position of cifx on my motherboard in my PC and the 
IRQ affected is not shared ;-) !

I have now a question about IRQ. What is the good method to signal to 
user-land that there is an IRQ. Is there an example ?

Thank you for your help,

Jerome

-- 

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44






^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 21:05                                       ` Gilles Chanteperdrix
@ 2013-03-07 15:33                                         ` Jerome Poncin
  2013-03-08 10:17                                           ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-07 15:33 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: Jan Kiszka, xenomai

Le 06/03/2013 22:05, Gilles Chanteperdrix a écrit :
> On 03/06/2013 04:28 PM, Jan Kiszka wrote:
>
>> Also here: Do not misuse write(), define an IOCTL that contains
>> something like "MMAP" and another one with MUNMAP in its name - that's
>> the purpose of this service, no?
>
> A lot of drivers probably have to reinvent a way to pass all the
> parameters for an mmap, why not adding an "mmap" method to RTDM drivers?
>
>
Hello,

I  re factored my code with all your remarks (I think and I hope).

Could you say me if it's correct now ?

Jan, you're right, It's possible to use Xenomai with UIO driver, but I 
would like to use more real time possibilities of Xenomai in future 
(like IRQ).
My first goal is to have a code compliant.
I added IRQ, and my next step will be to understand why the kernel crash 
after IRQ registration.

Thank you for your help,

Jerome



-------------- next part --------------
/*
 * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
 *
 * Xenomai 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.
 *
 * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/mman.h>

#include <asm-generic/xenomai/pci_ids.h>

#include <rtdm/rtdm_driver.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

#define RTCIFX_GET_MEM_INFO				0x00
#define RTCIFX_MMAP					0x01
#define RTCIFX_MUNMAP					0x02
#define RTCIFX_REQUEST_IRQ				0x03
#define RTCIFX_FREE_IRQ					0x04
#define RTCIFX_ENABLE_IRQ				0x05
#define RTCIFX_DISABLE_IRQ				0x06

#define DPM_HOST_INT_EN0                0xfff0
#define DPM_HOST_INT_STAT0              0xffe0
#define PLX_GPIO_OFFSET                 0x15
#define PLX_TIMING_OFFSET               0x0a

#define DPM_HOST_INT_MASK               0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN          0x80000000
#define PLX_GPIO_DATA0_MASK             0x00000004
#define PLX_GPIO_DATA1_MASK             0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122

/* Number of bar */
/* points to the DPM -> netX, netPLC, netJACK */
#define DPM_BAR                         0
/* points to the optional extended memory     */
#define EXT_MEM_BAR                     1
/* points to the DPM -> netXPLX               */
#define PLX_DPM_BAR                     2
/* timing config register                     */
#define PXA_PLX_BAR                     0

/* Index of io_info structure's memory array */
/* first mapping describes DPM              */
#define DPM_INDEX                       0
/* second mapping describes extended memory */
#define EXT_MEM_INDEX                   1

#define MAX_MAPS                        2

#define MEM_PHYS                        1

#define DRIVER_NAME                     "rtdm_cifx"
#define PERIPHERAL_NAME                 "cifx"
#define PROVIDER_NAME                   "Hilscher"

/* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
/* name of a cifX PCI card              */
#define CIFX_RTDM_CARD_NAME             "netx"
/* name of a netPLC PCI card            */
#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
/* name of a netJACK PCI card           */
#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"

struct io_mem {
	uint32_t addr;
	uint32_t size;
	int32_t memtype;
	void __iomem *internal_addr;
};

struct io_info {
	struct io_mem mem[MAX_MAPS];
	int32_t irq;
	bool irq_enable;
	bool irq_registered;
	rtdm_irq_t irq_handle;
	struct ext_io_info *priv;
};

struct ext_io_info {
	uint32_t __iomem *plx;
	uint8_t dpm_mode;
	uint32_t plx_timing;
};

struct io_map_mem {
	uint32_t phys_addr;
	uint32_t virt_addr;
	uint32_t length;
};

static struct io_info *cifx_get_device_data(struct rtdm_device *info);
static struct ext_io_info *cifx_get_private(struct rtdm_device *info);

static int cifx_set_plx_timing(struct ext_io_info *ext_info);
static int cifx_get_plx_timing(struct ext_io_info *ext_info);
static int cifx_get_dpm_mode(struct ext_io_info *ext_info);

static int cifx_pci_open(struct rtdm_dev_context *context,
			 rtdm_user_info_t *user_info, int oflags);
static int cifx_pci_close(struct rtdm_dev_context *context,
			  rtdm_user_info_t *user_info);
static int cifx_pci_ioctl(struct rtdm_dev_context *context,
			  rtdm_user_info_t *user_info,
			  unsigned int request, void *arg);

static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void cifx_pci_remove(struct pci_dev *dev);

static inline int cifx_handler(rtdm_irq_t *irq);

/* Number or cifx found and open */
static int32_t cifx_num;

/* RTDM Device information structure */
static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version = RTDM_DEVICE_STRUCT_VER,

	.device_flags = RTDM_NAMED_DEVICE,
	.context_size = 0,
	.device_name = "",

	.open_nrt = cifx_pci_open,

	.ops = {
		.close_nrt = cifx_pci_close,

		.read_nrt = NULL,
		.write_nrt = NULL,

		.ioctl_rt = NULL,
		.ioctl_nrt = cifx_pci_ioctl,

		.read_rt = NULL,
		.write_rt = NULL,
		},

	.device_class = RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class = RTDM_SUBCLASS_GENERIC,
	.profile_version = 1,
	.driver_name = DRIVER_NAME,
	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
	.provider_name = PROVIDER_NAME,
};

/* Device table */
static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
	{
	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX, 0, 0}, {
	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA}, {
	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
		    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA}, {
	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM}, {
	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH}, {
	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM}, {
	PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
		    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH}, {
	0,}
};

/* cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name = "cifx",
	.id_table = cifx_pci_tbl,
	.probe = cifx_pci_probe,
	.remove = cifx_pci_remove,
};

/*
 *	cifx_rtdm_device_to_device_data
 *	Get device_data structure
 */
static struct io_info *cifx_get_device_data(struct rtdm_device *info)
{
	return info->device_data;
}

/*
 *	cifx_rtdm_device_to_private
 *	Get ext_io_info structure
 */
static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
{
	return ((struct io_info *)info->device_data)->priv;
}

/*
 * cifx_handler
 * cifx interrupt handler
 */
static inline int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device *info = rtdm_irq_get_arg(irq, void);
	struct io_info *device_data = info->device_data;

	/* Test if request is for this driver */
	if ((device_data->priv != NULL)
	    || (device_data->irq_registered == 0)
	    || (device_data->irq_enable == 0)) {
		/* This is a PLX device and cannot produce an IRQ,
		   IRQ not registred or not enable (cannot produce an IRQ) */
		return RTDM_IRQ_NONE;
	} else {
		void __iomem *int_enable_reg =
		    device_data->mem[DPM_INDEX].internal_addr +
		    DPM_HOST_INT_EN0;
		void __iomem *int_status_reg =
		    device_data->mem[DPM_INDEX].internal_addr +
		    DPM_HOST_INT_STAT0;

		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
		      & DPM_HOST_INT_MASK))
			return RTDM_IRQ_NONE;

		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg)
			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*
 *	cifx_set_plx_timing
 *	Set plx timing
 */
static int cifx_set_plx_timing(struct ext_io_info *ext_info)
{
	uint32_t __iomem *plx_timing;

	if (ext_info == NULL)
		return -ENODEV;

	plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = ext_info->plx_timing;

	return 0;
}

/*
 * cifx_get_plx_timing
 * Get plx timing
 */
static int cifx_get_plx_timing(struct ext_io_info *ext_info)
{
	if (ext_info == NULL)
		return -ENODEV;

	switch (ext_info->dpm_mode) {
	case 8:
		ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
		break;
	case 16:
		ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
		break;
	case 32:
		ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/*
 * cifx_get_dpm_mode
 * Get dpm mode
 */
static int cifx_get_dpm_mode(struct ext_io_info *ext_info)
{
	uint32_t __iomem *plx_gpio;

	if (ext_info == NULL)
		return -ENODEV;

	plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;

	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		ext_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		ext_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		ext_info->dpm_mode = 16;
	else
		return -EINVAL;

	return 0;
}

/*
 * cifx_pci_open
 * Open cifx pci driver
 */
static int cifx_pci_open(struct rtdm_dev_context *context,
			 rtdm_user_info_t *user_info, int oflags)
{
	return 0;
}

/*
 * cifx_pci_close
 * Close cifx pci driver
 */
static int cifx_pci_close(struct rtdm_dev_context *context,
			  rtdm_user_info_t *user_info)
{
	return 0;
}

/*
 * cifx_pci_ioctl
 * ioctl
 */
static int cifx_pci_ioctl(struct rtdm_dev_context *context,
			  rtdm_user_info_t *user_info,
			  unsigned int request, void *arg)
{
	int ret = 0;
	struct rtdm_device *info = (struct rtdm_device *)context->device;
	struct io_info *device_data = cifx_get_device_data(info);
	struct io_map_mem map_mem;

	switch (request) {
	case RTCIFX_GET_MEM_INFO:
		if (arg == NULL)
			return -EINVAL;

		ret = rtdm_safe_copy_to_user(user_info,
					     arg,
					     device_data->mem,
					     (2 * sizeof(uint32_t)));
		break;

	case RTCIFX_MMAP:
		if (arg == NULL)
			return -EINVAL;

		ret = rtdm_safe_copy_from_user(user_info,
					       &map_mem, arg, sizeof(map_mem));
		if (ret != 0)
			break;

		/* Map physical on virtual memory */
		ret = rtdm_iomap_to_user(user_info,
					 map_mem.phys_addr,
					 map_mem.length,
					 (PROT_READ | PROT_WRITE),
					 (void **)&map_mem.virt_addr,
					NULL,
					NULL);
		if (ret != 0)
			break;

		ret = rtdm_safe_copy_to_user(user_info,
						arg,
						&map_mem,
						sizeof(map_mem));
		break;

	case RTCIFX_MUNMAP:
		if (arg == NULL)
			return -EINVAL;

		ret = rtdm_safe_copy_from_user(user_info,
					       &map_mem, arg, sizeof(map_mem));
		if (ret != 0)
			break;

		/* Unap virtual memory */
		ret = rtdm_munmap(user_info,
				  (void *)map_mem.virt_addr, map_mem.length);
		break;

	case RTCIFX_REQUEST_IRQ:
		if (device_data->irq_registered == 0) {
			ret = rtdm_irq_request(&device_data->irq_handle,
					       device_data->irq,
					       cifx_handler,
					       RTDM_IRQTYPE_SHARED,
					       info->device_name, (void *)info);

			if (ret == 0)
				device_data->irq_registered = 1;
		}
		break;

	case RTCIFX_FREE_IRQ:
		if (device_data->irq_registered == 1) {
			ret = rtdm_irq_free(&device_data->irq_handle);

			if (ret == 0)
				device_data->irq_registered = 0;
		}
		break;

	case RTCIFX_ENABLE_IRQ:
		if (device_data->irq_registered == 1) {
			ret = rtdm_irq_enable(&device_data->irq_handle);

			if (ret == 0)
				device_data->irq_enable = 1;
		}
		break;

	case RTCIFX_DISABLE_IRQ:
		if (device_data->irq_registered == 1) {
			ret = rtdm_irq_disable(&device_data->irq_handle);

			if (ret == 0)
				device_data->irq_enable = 0;
		}
		break;

	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}

static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device *info = NULL;
	struct io_info *device_data = NULL;
	int32_t bar;
	int32_t ret = -ENODEV;

	/* Allocate device driver structure */
	info = kmalloc(sizeof(*info), GFP_KERNEL);

	if (info == NULL)
		return -ENOMEM;

	ret = pci_enable_device(dev);
	if (ret != 0)
		goto out_free;

	ret = pci_request_regions(dev, DRIVER_NAME);
	if (ret != 0)
		goto out_disable;

	/* Initialize structure with default values */
	memcpy(info, &cifx_device_tmpl, sizeof(*info));

	info->device_id = id->device;
	snprintf(info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name = info->device_name;

	switch (id->device) {
	case PCI_DEVICE_ID_HILSCHER_NETX:
		bar = DPM_BAR;
		info->peripheral_name = CIFX_RTDM_CARD_NAME;
		break;
	case PCI_DEVICE_ID_HILSCHER_NETPLC:
		bar = DPM_BAR;
		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
		break;
	case PCI_DEVICE_ID_HILSCHER_NETJACK:
		bar = DPM_BAR;
		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
		break;
	default:
		bar = PLX_DPM_BAR;
		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
		break;
	}

	info->device_data = NULL;

	/* Allocate specific data strcuture for device */
	device_data = kmalloc(sizeof(*device_data), GFP_KERNEL);

	if (device_data == NULL) {
		ret = -ENOMEM;
		goto out_release;
	}

	memset(device_data, 0, sizeof(*device_data));

	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);

	if (device_data->mem[DPM_INDEX].addr == 0)
		goto out_release;

	device_data->mem[DPM_INDEX].internal_addr =
	    ioremap_nocache(pci_resource_start(dev, bar),
			    pci_resource_len(dev, bar));

	if (device_data->mem[DPM_INDEX].internal_addr == 0)
		goto out_release;

	dev_info(&dev->dev, "DPM at %08X\n", device_data->mem[DPM_INDEX].addr);
	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;

	/* map extended mem (BAR 1 points to the extended memory) */
	device_data->mem[EXT_MEM_INDEX].addr =
	    pci_resource_start(dev, EXT_MEM_BAR);

	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0) {
		device_data->mem[EXT_MEM_INDEX].internal_addr =
		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
				    pci_resource_len(dev, EXT_MEM_BAR));

		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
			goto out_unmap;

		dev_info(&dev->dev,
			 "extended memory at %08X\n",
			 device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size =
		    pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}

	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
			  + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
		/* map PLX registers */
		struct ext_io_info *ext_info;

		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);

		if (ext_info == NULL) {
			ret = -ENOMEM;
			goto out_unmap;
		}

		device_data->priv = ext_info;

		/* set PXA PLX Timings */
		ext_info->plx =
		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
				    pci_resource_len(dev, PXA_PLX_BAR));

		if (ext_info->plx == NULL)
			goto out_unmap;
		if (cifx_get_dpm_mode(ext_info))
			goto out_unmap_plx;
		if (cifx_get_plx_timing(ext_info))
			goto out_unmap_plx;
		if (cifx_set_plx_timing(ext_info))
			goto out_unmap_plx;
	} else {
		struct ext_io_info *ext_info;

		ext_info = kmalloc(sizeof(*ext_info), GFP_KERNEL);

		if (ext_info == NULL) {
			ret = -ENOMEM;
			goto out_free_pxa;
		}

		ext_info->plx = NULL;
		ext_info->plx_timing = 0;
		ext_info->dpm_mode = 0;
		device_data->priv = ext_info;
	}

	/* Initialize irq data */
	device_data->irq = dev->irq;
	device_data->irq_enable = 0;
	device_data->irq_registered = 0;

	info->device_data = device_data;

	/* Register RTDM device driver */
	ret = rtdm_dev_register(info);
	if (ret != 0) {
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}

	pci_set_drvdata(dev, info);

	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
	else {
		struct ext_io_info *ext_info = device_data->priv;
		dev_info(&dev->dev,
			 "registered NXPCA-PCI adapter card in %d bit mode\n",
			 ((struct ext_io_info *)ext_info)->dpm_mode);
	}

	cifx_num++;

	return 0;

out_unmap_plx:
	iounmap((device_data->priv)->plx);

out_free_pxa:
	kfree(device_data->priv);

out_unmap:
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

out_release:
	pci_release_regions(dev);

out_disable:
	pci_disable_device(dev);

out_free:
	if (info->device_data != NULL)
		kfree(info->device_data);

	kfree(info);

	return ret;
}

static void cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device *info = pci_get_drvdata(dev);
	struct io_info *device_data = cifx_get_device_data(info);
	struct ext_io_info *ext_info = cifx_get_private(info);

	if (cifx_num > 0) {
		if (info->device_data == NULL)
			return;

		if (ext_info != NULL) {
			/* Disable all interrupts */
			iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
				  + DPM_HOST_INT_EN0);

			if (ext_info->plx != NULL)
				iounmap((void *)ext_info->plx);

			kfree((void *)ext_info);
		}

		/* Unregister device driver */
		rtdm_dev_unregister(info, 1000);

		pci_release_regions(dev);
		pci_disable_device(dev);
		pci_set_drvdata(dev, NULL);

		/* Unmap memory */
		iounmap(device_data->mem[DPM_INDEX].internal_addr);
		if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
			iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

		/* Release structure memory allocation */
		kfree(info->device_data);
		kfree(info);

		cifx_num--;
	}
}

static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 15:28                                     ` Jan Kiszka
@ 2013-03-06 21:05                                       ` Gilles Chanteperdrix
  2013-03-07 15:33                                         ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-06 21:05 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

On 03/06/2013 04:28 PM, Jan Kiszka wrote:

> Also here: Do not misuse write(), define an IOCTL that contains
> something like "MMAP" and another one with MUNMAP in its name - that's
> the purpose of this service, no?


A lot of drivers probably have to reinvent a way to pass all the
parameters for an mmap, why not adding an "mmap" method to RTDM drivers?


-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 13:58                                   ` Jerome Poncin
  2013-03-06 15:28                                     ` Jan Kiszka
@ 2013-03-06 20:42                                     ` Gilles Chanteperdrix
  1 sibling, 0 replies; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-06 20:42 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/06/2013 02:58 PM, Jerome Poncin wrote:

> Gilles,
> 
> I don't know, perhaps I missed some remarks, it's possible (by error or 
> by misunderstanding) .


Again, that is because you seem to be used to top-posting, which is the opposite way this mailing list (and many others) work.

> +static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
> +			      rtdm_user_info_t *user_info, const void *buf,
> +			      size_t nbyte)
> +{
> +	struct io_map_mem map_mem;
> +	int ret;
> +
> +	switch (nbyte) {
> +	case sizeof(map_mem):
> +		/* Copy data information for Kernel */
> +		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
> +			return 0;
> +
> +		if (*map_mem.virt_addr == NULL) {
> +			/* Map physical on virtual memory */
> +			ret = rtdm_iomap_to_user(user_info,
> +						map_mem.
> +						phys_addr,
> +						map_mem.length,
> +						(PROT_READ | PROT_WRITE),
> +						map_mem.virt_addr,
> +						NULL,
> +						NULL);
> +
> +			if (ret != 0)
> +				return 0;
> +		} else {
> +			/* Unap virtual memory */
> +			ret = rtdm_munmap(user_info,
> +					*map_mem.virt_addr,
> +					map_mem.length);
> +
> +			if (ret != 0)
> +				return 0;
> +		}
> +		break;
> +
> +	default:
> +		/* Error */
> +		return 0;
> +	}
> +
> +	return nbyte;


Again, left alone the fact that this function should not be a "write" 
method, this should be:

if (nbyte != sizeof(mmap_mem))
	return -EINVAL;

if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
	return -EFAULT;

if (*map_mem.virt_addr)
	return rtdm_munmap(user_info, *map_mem.virt_addr, map_mem.length);

return rtdm_iomap_to_user(user_info, map_mem.phys_addr, map_mem.length,
			(PROT_READ | PROT_WRITE), map_mem.virt_addr, NULL, NULL);


And I am wondering, if this is even correct: if map_mem.virt_addr is a 
user-space address, it is forbidden to dereference it directly in 
kernel-space, we should use another copy_from/to_user, even if it appears
to work on some (most in fact) architectures. It is probably better to 
put the virtual address directly in the map_mem structure instead of
a pointer requiring more contorsions.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 13:58                                   ` Jerome Poncin
@ 2013-03-06 15:28                                     ` Jan Kiszka
  2013-03-06 21:05                                       ` Gilles Chanteperdrix
  2013-03-06 20:42                                     ` Gilles Chanteperdrix
  1 sibling, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-03-06 15:28 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-03-06 14:58, Jerome Poncin wrote:
> diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
> new file mode 100644
> index 0000000..e04ddb7
> --- /dev/null
> +++ b/ksrc/drivers/cifx/cifx_pci.c
> @@ -0,0 +1,634 @@
> +/*
> + * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
> + *
> + * Xenomai 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.
> + *
> + * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/io.h>
> +#include <linux/mman.h>
> +
> +#include <asm-generic/xenomai/pci_ids.h>
> +
> +#include <rtdm/rtdm_driver.h>
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("RTDM board driver for CifX cards");
> +MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
> +
> +#define DPM_HOST_INT_EN0                0xfff0
> +#define DPM_HOST_INT_STAT0              0xffe0
> +#define PLX_GPIO_OFFSET                 0x15
> +#define PLX_TIMING_OFFSET               0x0a
> +
> +#define DPM_HOST_INT_MASK               0xe600ffff
> +#define DPM_HOST_INT_GLOBAL_EN          0x80000000
> +#define PLX_GPIO_DATA0_MASK             0x00000004
> +#define PLX_GPIO_DATA1_MASK             0x00000020
> +
> +#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
> +#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
> +#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
> +
> +/* Number of bar */
> +/* points to the DPM -> netX, netPLC, netJACK */
> +#define DPM_BAR                         0
> +/* points to the optional extended memory     */
> +#define EXT_MEM_BAR                     1
> +/* points to the DPM -> netXPLX               */
> +#define PLX_DPM_BAR                     2
> +/* timing config register                     */
> +#define PXA_PLX_BAR                     0
> +
> +/* Index of io_info structure's memory array */
> +/* first mapping describes DPM              */
> +#define DPM_INDEX                       0
> +/* second mapping describes extended memory */
> +#define EXT_MEM_INDEX                   1
> +
> +#define MAX_MAPS                        2
> +
> +#define MEM_PHYS                        1
> +
> +#define DRIVER_NAME                     "rtdm_cifx"
> +#define PERIPHERAL_NAME                 "cifx"
> +#define PROVIDER_NAME                   "Hilscher"
> +
> +/* name of a NXSB-PCA or NXPCA-PCI card */
> +#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
> +/* name of a cifX PCI card              */
> +#define CIFX_RTDM_CARD_NAME             "netx"
> +/* name of a netPLC PCI card            */
> +#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
> +/* name of a netJACK PCI card           */
> +#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
> +
> +struct io_mem {
> +    uint32_t addr;

The kernel uses tabs, not 4 spaces. You can try linux/scripts/Lindent,
and then manually post-process the result so that it looks good without
violating checkpatch requirements.

> +    uint32_t size;
> +    int32_t memtype;
> +    void __iomem *internal_addr;
> +};
> +
> +struct io_info {
> +    struct io_mem mem[MAX_MAPS];
> +    int32_t irq;
> +    bool irq_enable;
> +    bool irq_registered;
> +    rtdm_irq_t irq_handle;
> +    struct ext_io_info *priv;
> +};
> +
> +struct ext_io_info {
> +    uint32_t __iomem *plx;
> +    uint8_t dpm_mode;
> +    uint32_t plx_timing;
> +};
> +
> +struct io_map_mem {
> +    uint32_t phys_addr;
> +    void **virt_addr;
> +    uint32_t length;
> +};
> +
> +static struct io_info *cifx_get_device_data(struct rtdm_device *info);
> +static struct ext_io_info *cifx_get_private(struct rtdm_device *info);
> +
> +static int cifx_set_plx_timing(struct rtdm_device *info);
> +static int cifx_get_plx_timing(struct rtdm_device *info);
> +static int cifx_get_dpm_mode(struct rtdm_device *info);
> +
> +static int cifx_pci_open(struct rtdm_dev_context *context,
> +             rtdm_user_info_t *user_info, int oflags);
> +static int cifx_pci_close(struct rtdm_dev_context *context,
> +              rtdm_user_info_t *user_info);
> +static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
> +                 rtdm_user_info_t *user_info, void *buf,
> +                 size_t nbyte);
> +static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
> +                  rtdm_user_info_t *user_info, const void *buf,
> +                  size_t nbyte);
> +
> +static int cifx_pci_probe(struct pci_dev *dev, const struct
> pci_device_id *id);
> +static void cifx_pci_remove(struct pci_dev *dev);
> +
> +/* Number or cifx found and open */
> +static int32_t cifx_num;
> +
> +/* RTDM Device information structure */
> +static const struct rtdm_device __initdata cifx_device_tmpl = {
> +    .struct_version = RTDM_DEVICE_STRUCT_VER,
> +
> +    .device_flags = RTDM_NAMED_DEVICE,
> +    .context_size = 0,
> +    .device_name = "",
> +
> +    .open_nrt = cifx_pci_open,
> +
> +    .ops = {
> +        .close_nrt = cifx_pci_close,
> +
> +        .read_nrt = cifx_pci_read,
> +        .write_nrt = cifx_pci_write,
> +
> +        .ioctl_rt = NULL,
> +        .ioctl_nrt = NULL,
> +
> +        .read_rt = NULL,
> +        .write_rt = NULL,

This is no RTDM driver. You provide zero real-time services, thus your
Xenomai user could simply work against the standard UIO driver.

I suppose you really want to find a box on which you can test and
finalize IRQ support now. Otherwise, this whole RTDM excercise is really
pointless.

I'm reviewing the rest nevertheless, just in case.

> +        },
> +
> +    .device_class = RTDM_CLASS_EXPERIMENTAL,
> +    .device_sub_class = RTDM_SUBCLASS_GENERIC,
> +    .profile_version = 1,
> +    .driver_name = DRIVER_NAME,
> +    .driver_version = RTDM_DRIVER_VER(1, 0, 0),
> +    .provider_name = PROVIDER_NAME,
> +};
> +
> +/* Device table */
> +static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
> +    {PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX,
> +    0, 0},
> +    {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
> +    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA},
> +    {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
> +    PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA},
> +    {PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
> +    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM},
> +    {PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
> +    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH},
> +    {PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
> +    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM},
> +    {PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
> +    PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH},
> +    { 0,}
> +};
> +
> +/* RTDM cifX Driver */
> +static struct pci_driver cifx_pci_driver = {
> +    .name = "cifx",
> +    .id_table = cifx_pci_tbl,
> +    .probe = cifx_pci_probe,
> +    .remove = cifx_pci_remove,
> +};
> +
> +/*
> + *    cifx_rtdm_device_to_device_data
> + *    Get device_data structure
> + */
> +static struct io_info *cifx_get_device_data(struct rtdm_device *info)
> +{
> +    return info->device_data;
> +}
> +
> +/*
> + *    cifx_rtdm_device_to_private
> + *    Get ext_io_info structure
> + */
> +static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
> +{
> +    return ((struct io_info *)info->device_data)->priv;
> +}
> +
> +/*
> + *    cifx_set_plx_timing
> + *    Set plx timing
> + */
> +static int cifx_set_plx_timing(struct rtdm_device *info)
> +{
> +    struct ext_io_info *ext_info = cifx_get_private(info);
> +    uint32_t __iomem *plx_timing;
> +
> +    if (ext_info == NULL)

Well... you set it to non-NULL only a few lines before calling this
function.

But why calling this function with an rtdm_device pointer when it needs
ext_io_info and the caller has this reference? Needless complication.

> +        return -ENODEV;
> +
> +    plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
> +    *plx_timing = ext_info->plx_timing;
> +
> +    return 0;
> +}
> +
> +/*
> + * cifx_get_plx_timing
> + * Get plx timing
> + */
> +static int cifx_get_plx_timing(struct rtdm_device *info)
> +{
> +    struct ext_io_info *ext_info = cifx_get_private(info);
> +
> +    if (ext_info == NULL)

Same here.

> +        return -ENODEV;
> +
> +    switch (ext_info->dpm_mode) {
> +    case 8:
> +        ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
> +        break;
> +    case 16:
> +        ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
> +        break;
> +    case 32:
> +        ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
> +        break;
> +    default:
> +        return -EINVAL;
> +    }
> +
> +    return 0;
> +}
> +
> +/*
> + * cifx_get_dpm_mode
> + * Get dpm mode
> + */
> +static int cifx_get_dpm_mode(struct rtdm_device *info)
> +{
> +    struct ext_io_info *ext_info = cifx_get_private(info);
> +    uint32_t __iomem *plx_gpio;
> +
> +    if (ext_info == NULL)
> +        return -ENODEV;

And here.

> +
> +    plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;
> +
> +    if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
> +        && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
> +        ext_info->dpm_mode = 8;
> +    else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
> +         && (*plx_gpio & PLX_GPIO_DATA1_MASK))
> +        ext_info->dpm_mode = 32;
> +    else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
> +         && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
> +        ext_info->dpm_mode = 16;
> +    else
> +        return -EINVAL;
> +
> +    return 0;
> +}
> +
> +/*
> + * cifx_pci_open
> + * Open RTDM cifx pci driver
> + */
> +static int cifx_pci_open(struct rtdm_dev_context *context,
> +             rtdm_user_info_t *user_info, int oflags)
> +{
> +    return 0;
> +}
> +
> +/*
> + * cifx_pci_close
> + * Close RTDM cifx pci driver
> + */
> +static int cifx_pci_close(struct rtdm_dev_context *context,
> +              rtdm_user_info_t *user_info)
> +{
> +    return 0;
> +}
> +
> +/*
> + * cifx_pci_read
> + * Read
> + */
> +static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
> +                 rtdm_user_info_t *user_info, void *buf,
> +                 size_t nbyte)

read() is supposed to provide read access to *stream* like data sources.
You misuse it to deliver a static (after initialization) device
descripion. Better model this with a more descriptive IOCTL. And
document the API in the header you will need for the IOCTLs. Doxgen
format, please. There are several examples in include/rtdm.

> +{
> +    struct rtdm_device *info = (struct rtdm_device *)context->device;
> +
> +    if (nbyte > sizeof(struct io_info))
> +        return 0;

Still wrong.

> +
> +    /* Copy data information for userland */
> +    if (rtdm_safe_copy_to_user(user_info, buf, info->device_data, nbyte))
> +        return 0;

Also this.

> +
> +    return nbyte;
> +}
> +
> +/*
> + * cifx_pci_write
> + * write
> + */
> +static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
> +                  rtdm_user_info_t *user_info, const void *buf,
> +                  size_t nbyte)

Also here: Do not misuse write(), define an IOCTL that contains
something like "MMAP" and another one with MUNMAP in its name - that's
the purpose of this service, no?

> +{
> +    struct io_map_mem map_mem;
> +    int ret;
> +
> +    switch (nbyte) {
> +    case sizeof(map_mem):
> +        /* Copy data information for Kernel */
> +        if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
> +            return 0;

And this is another bogus error code.

> +
> +        if (*map_mem.virt_addr == NULL) {
> +            /* Map physical on virtual memory */
> +            ret = rtdm_iomap_to_user(user_info,
> +                        map_mem.
> +                        phys_addr,
> +                        map_mem.length,
> +                        (PROT_READ | PROT_WRITE),
> +                        map_mem.virt_addr,
> +                        NULL,
> +                        NULL);
> +
> +            if (ret != 0)
> +                return 0;

And this.

> +        } else {
> +            /* Unap virtual memory */
> +            ret = rtdm_munmap(user_info,
> +                    *map_mem.virt_addr,
> +                    map_mem.length);
> +
> +            if (ret != 0)
> +                return 0;

And another bug. You make it hard for userland to discover its own bugs
by hiding proper error codes systematically.

> +        }
> +        break;
> +
> +    default:
> +        /* Error */
> +        return 0;

Since when is 0 a valid error code?

> +    }
> +
> +    return nbyte;
> +}
> +
> +static int cifx_pci_probe(struct pci_dev *dev, const struct
> pci_device_id *id)
> +{
> +    struct rtdm_device *info = NULL;
> +    struct io_info *device_data = NULL;
> +    int32_t bar;
> +    int32_t ret;
> +
> +    /* Allocate device driver structure */
> +    info = rtdm_malloc(sizeof(struct rtdm_device));

As I already told you: You are in non-RT context here, thus normal
kmalloc is sufficient. Please fix,

> +
> +    if (info == NULL)
> +        return -ENOMEM;
> +
> +    ret = pci_enable_device(dev);
> +    if (ret != 0)
> +        goto out_free;
> +
> +    ret = pci_request_regions(dev, DRIVER_NAME);
> +    if (ret != 0)
> +        goto out_disable;
> +
> +    /* Initialize structure with default values */
> +    memcpy(info, &cifx_device_tmpl, sizeof(*info));
> +
> +    info->device_id = id->device;
> +    snprintf(info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
> +    info->proc_name = info->device_name;
> +
> +    switch (id->device) {
> +    case PCI_DEVICE_ID_HILSCHER_NETX:
> +        bar = DPM_BAR;
> +        info->peripheral_name = CIFX_RTDM_CARD_NAME;
> +        break;
> +    case PCI_DEVICE_ID_HILSCHER_NETPLC:
> +        bar = DPM_BAR;
> +        info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
> +        break;
> +    case PCI_DEVICE_ID_HILSCHER_NETJACK:
> +        bar = DPM_BAR;
> +        info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
> +        break;
> +    default:
> +        bar = PLX_DPM_BAR;
> +        info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
> +        break;
> +    }
> +
> +    info->device_data = NULL;
> +
> +    /* Allocate specific data strcuture for device */
> +    device_data = rtdm_malloc(sizeof(*device_data));
> +
> +    if (device_data == NULL)
> +        goto out_release;
> +
> +    memset(device_data, 0, sizeof(*device_data));
> +
> +    /* BAR 0 or 2 points to the card's dual port memory */
> +    device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
> +
> +    if (device_data->mem[DPM_INDEX].addr == 0)
> +        goto out_release;
> +
> +    device_data->mem[DPM_INDEX].internal_addr =
> +        ioremap_nocache(pci_resource_start(dev, bar),
> +                        pci_resource_len(dev, bar));
> +
> +    if (device_data->mem[DPM_INDEX].internal_addr == 0)
> +        goto out_release;
> +
> +    dev_info(&dev->dev, "DPM at %08X\n",
> device_data->mem[DPM_INDEX].addr);
> +    device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
> +    device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
> +
> +    /* map extended mem (BAR 1 points to the extended memory) */
> +    device_data->mem[EXT_MEM_INDEX].addr =
> +                    pci_resource_start(dev, EXT_MEM_BAR);
> +
> +    /* extended memory is optional, so don't care if it is not present */
> +    if (device_data->mem[EXT_MEM_INDEX].addr != 0) {
> +        device_data->mem[EXT_MEM_INDEX].internal_addr =
> +            ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
> +                    pci_resource_len(dev, EXT_MEM_BAR));
> +
> +        if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
> +            goto out_unmap;
> +
> +        dev_info(&dev->dev,
> +                "extended memory at %08X\n",
> +                device_data->mem[EXT_MEM_INDEX].addr);
> +        device_data->mem[EXT_MEM_INDEX].size =
> +                    pci_resource_len(dev, EXT_MEM_BAR);
> +        device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
> +    }
> +
> +    if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
> +        || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
> +        || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
> +        /* make sure all interrupts are disabled */
> +        iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
> +                            + DPM_HOST_INT_EN0);
> +        device_data->priv = NULL;
> +    } else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
> +        /* map PLX registers */
> +        struct ext_io_info *ext_info;
> +
> +        ext_info = rtdm_malloc(sizeof(*ext_info));
> +
> +        if (ext_info == NULL)
> +            goto out_unmap;
> +
> +        device_data->priv = ext_info;
> +
> +        /* set PXA PLX Timings */
> +        ext_info->plx = ioremap_nocache(
> +                    pci_resource_start(dev, PXA_PLX_BAR),
> +                    pci_resource_len(dev, PXA_PLX_BAR));
> +
> +        if (ext_info->plx == NULL)
> +            goto out_unmap;
> +        if (cifx_get_dpm_mode(info))
> +            goto out_unmap_plx;
> +        if (cifx_get_plx_timing(info))
> +            goto out_unmap_plx;
> +        if (cifx_set_plx_timing(info))
> +            goto out_unmap_plx;
> +    } else {
> +        struct ext_io_info *ext_info;
> +
> +        ext_info = rtdm_malloc(sizeof(*ext_info));
> +
> +        if (ext_info == NULL)
> +            goto out_free_pxa;
> +
> +        ext_info->plx = NULL;
> +        ext_info->plx_timing = 0;
> +        ext_info->dpm_mode = 0;
> +        device_data->priv = ext_info;
> +    }
> +
> +    /* Initialize irq data */
> +    device_data->irq = dev->irq;
> +    device_data->irq_enable = 0;
> +    device_data->irq_registered = 0;
> +
> +    info->device_data = device_data;
> +
> +    /* Register RTDM device driver */
> +    ret = rtdm_dev_register(info);
> +    if (ret != 0) {
> +        if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
> +            goto out_unmap;
> +        else
> +            goto out_unmap_plx;
> +    }
> +
> +    pci_set_drvdata(dev, info);
> +
> +    if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
> +        dev_info(&dev->dev, "registered CifX card\n");
> +    else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
> +        dev_info(&dev->dev, "registered netPLC card\n");
> +    else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
> +        dev_info(&dev->dev, "registered netJACK card\n");
> +    else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
> +        dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
> +    else {
> +        struct ext_io_info *ext_info = device_data->priv;
> +        dev_info(&dev->dev,
> +            "registered NXPCA-PCI adapter card in %d bit mode\n",
> +            ((struct ext_io_info *)ext_info)->dpm_mode);
> +    }
> +
> +    cifx_num++;
> +
> +    return 0;
> +
> + out_unmap_plx:
> +    iounmap((device_data->priv)->plx);
> +
> + out_free_pxa:
> +    rtdm_free(device_data->priv);
> +
> + out_unmap:
> +    iounmap(device_data->mem[DPM_INDEX].internal_addr);
> +    if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
> +        iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
> +
> + out_release:
> +    pci_release_regions(dev);
> +
> + out_disable:
> +    pci_disable_device(dev);
> +
> + out_free:
> +    if (info->device_data != NULL)
> +        rtdm_free(info->device_data);
> +
> +    rtdm_free(info);
> +
> +    return -ENODEV;

You throw aways what ret may contain about the error. You just need to
initialize it when the reason was "allocated_memory == NULL" to -ENOMEM.

> +}
> +
> +static void cifx_pci_remove(struct pci_dev *dev)
> +{
> +    struct rtdm_device *info = pci_get_drvdata(dev);
> +    struct io_info *device_data = cifx_get_device_data(info);
> +    struct ext_io_info *ext_info = cifx_get_private(info);
> +    int32_t ret;
> +
> +    if (info->device_data == NULL)
> +        return;
> +
> +    if (ext_info != NULL) {
> +        /* Disable all interrupts */
> +        iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
> +                            + DPM_HOST_INT_EN0);
> +
> +        if (ext_info->plx != NULL)
> +            iounmap((void *)ext_info->plx);
> +
> +        rtdm_free((void *)ext_info);
> +    }
> +
> +    /* Unregister RTDM device driver */
> +    ret = rtdm_dev_unregister(info, 1000);
> +    if (ret != 0)
> +        return;

Either WARN() or ignore this (practically) impossible error.

> +
> +    pci_release_regions(dev);
> +    pci_disable_device(dev);
> +    pci_set_drvdata(dev, NULL);
> +
> +    /* Unmap memory */
> +    iounmap(device_data->mem[DPM_INDEX].internal_addr);
> +    if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
> +        iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
> +
> +    /* Release structure memory allocation */
> +    rtdm_free(info->device_data);
> +    rtdm_free(info);
> +
> +    if (cifx_num > 0)

Impossible.

> +        cifx_num--;
> +}
> +
> +static int __init cifx_pci_init(void)
> +{
> +    cifx_num = 0;

Unneeded, cifx_num is a global static variable, thus implicitely
intialized to 0.

> +
> +    return pci_register_driver(&cifx_pci_driver);
> +}
> +
> +static void __exit cifx_pci_exit(void)
> +{
> +    pci_unregister_driver(&cifx_pci_driver);
> +}
> +
> +module_init(cifx_pci_init);
> +module_exit(cifx_pci_exit);
> +
> +/* End of file : cifx_pci.c */

Obviously.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 12:04                                 ` Gilles Chanteperdrix
@ 2013-03-06 13:58                                   ` Jerome Poncin
  2013-03-06 15:28                                     ` Jan Kiszka
  2013-03-06 20:42                                     ` Gilles Chanteperdrix
  0 siblings, 2 replies; 57+ messages in thread
From: Jerome Poncin @ 2013-03-06 13:58 UTC (permalink / raw)
  To: xenomai

Gilles,

I don't know, perhaps I missed some remarks, it's possible (by error or 
by misunderstanding) .

Now I read again all discussion with you and Jan.

I read again my code trying to apply all your remarks. I give you my 
last patch.
After that I don't know what to do...
I'm agree to test code if you have some fix to add, therefore don't 
hesitate to send me them.

This code with modification is not test, I'm waiting that the code is 
compliant to do a last test.

Thank you very much for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44


-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
+#endif
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..e04ddb7
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.h>
+
+#include <rtdm/rtdm_driver.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	struct ext_io_info *priv;
+};
+
+struct ext_io_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+static struct io_info *cifx_get_device_data(struct rtdm_device *info);
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info);
+
+static int cifx_set_plx_timing(struct rtdm_device *info);
+static int cifx_get_plx_timing(struct rtdm_device *info);
+static int cifx_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX,
+	0, 0},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH},
+	{ 0,}
+};
+
+/* RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_rtdm_device_to_device_data
+ *	Get device_data structure
+ */
+static struct io_info *cifx_get_device_data(struct rtdm_device *info)
+{
+	return info->device_data;
+}
+
+/*
+ *	cifx_rtdm_device_to_private
+ *	Get ext_io_info structure
+ */
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
+{
+	return ((struct io_info *)info->device_data)->priv;
+}
+
+/*
+ *	cifx_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_set_plx_timing(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	uint32_t __iomem *plx_timing;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = ext_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_get_plx_timing(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	switch (ext_info->dpm_mode) {
+	case 8:
+		ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_get_dpm_mode(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	uint32_t __iomem *plx_gpio;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open RTDM cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close RTDM cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_read
+ * Read
+ */
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info))
+		return 0;
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf, info->device_data, nbyte))
+		return 0;
+
+	return nbyte;
+}
+
+/*
+ * cifx_pci_write
+ * write
+ */
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+	struct io_map_mem map_mem;
+	int ret;
+
+	switch (nbyte) {
+	case sizeof(map_mem):
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
+			return 0;
+
+		if (*map_mem.virt_addr == NULL) {
+			/* Map physical on virtual memory */
+			ret = rtdm_iomap_to_user(user_info,
+						map_mem.
+						phys_addr,
+						map_mem.length,
+						(PROT_READ | PROT_WRITE),
+						map_mem.virt_addr,
+						NULL,
+						NULL);
+
+			if (ret != 0)
+				return 0;
+		} else {
+			/* Unap virtual memory */
+			ret = rtdm_munmap(user_info,
+					*map_mem.virt_addr,
+					map_mem.length);
+
+			if (ret != 0)
+				return 0;
+		}
+		break;
+
+	default:
+		/* Error */
+		return 0;
+	}
+
+	return nbyte;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	ret = pci_enable_device(dev);
+	if (ret != 0)
+		goto out_free;
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0)
+		goto out_disable;
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf(info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(*device_data));
+
+	if (device_data == NULL)
+		goto out_release;
+
+	memset(device_data, 0, sizeof(*device_data));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
+
+	if (device_data->mem[DPM_INDEX].addr == 0)
+		goto out_release;
+
+	device_data->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+						pci_resource_len(dev, bar));
+
+	if (device_data->mem[DPM_INDEX].internal_addr == 0)
+		goto out_release;
+
+	dev_info(&dev->dev, "DPM at %08X\n", device_data->mem[DPM_INDEX].addr);
+	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
+	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	device_data->mem[EXT_MEM_INDEX].addr =
+					pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (device_data->mem[EXT_MEM_INDEX].addr != 0) {
+		device_data->mem[EXT_MEM_INDEX].internal_addr =
+			ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+					pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
+			goto out_unmap;
+
+		dev_info(&dev->dev,
+				"extended memory at %08X\n",
+				device_data->mem[EXT_MEM_INDEX].addr);
+		device_data->mem[EXT_MEM_INDEX].size =
+					pci_resource_len(dev, EXT_MEM_BAR);
+		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		|| (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		|| (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+							+ DPM_HOST_INT_EN0);
+		device_data->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct ext_io_info *ext_info;
+
+		ext_info = rtdm_malloc(sizeof(*ext_info));
+
+		if (ext_info == NULL)
+			goto out_unmap;
+
+		device_data->priv = ext_info;
+
+		/* set PXA PLX Timings */
+		ext_info->plx = ioremap_nocache(
+					pci_resource_start(dev, PXA_PLX_BAR),
+					pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (ext_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct ext_io_info *ext_info;
+
+		ext_info = rtdm_malloc(sizeof(*ext_info));
+
+		if (ext_info == NULL)
+			goto out_free_pxa;
+
+		ext_info->plx = NULL;
+		ext_info->plx_timing = 0;
+		ext_info->dpm_mode = 0;
+		device_data->priv = ext_info;
+	}
+
+	/* Initialize irq data */
+	device_data->irq = dev->irq;
+	device_data->irq_enable = 0;
+	device_data->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct ext_io_info *ext_info = device_data->priv;
+		dev_info(&dev->dev,
+			"registered NXPCA-PCI adapter card in %d bit mode\n",
+			((struct ext_io_info *)ext_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap((device_data->priv)->plx);
+
+ out_free_pxa:
+	rtdm_free(device_data->priv);
+
+ out_unmap:
+	iounmap(device_data->mem[DPM_INDEX].internal_addr);
+	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	int32_t ret;
+
+	if (info->device_data == NULL)
+		return;
+
+	if (ext_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+							+ DPM_HOST_INT_EN0);
+
+		if (ext_info->plx != NULL)
+			iounmap((void *)ext_info->plx);
+
+		rtdm_free((void *)ext_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0)
+		return;
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	/* Unmap memory */
+	iounmap(device_data->mem[DPM_INDEX].internal_addr);
+	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
+

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06 10:33                               ` Jerome Poncin
@ 2013-03-06 12:04                                 ` Gilles Chanteperdrix
  2013-03-06 13:58                                   ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-06 12:04 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/06/2013 11:33 AM, Jerome Poncin wrote:

> 
> Hello Gilles,
> 
> I tried to integrate all of remarks. I give you my new patch.
> 
> If you have others remarks don't hesitate ;-).


We have already sent you other remarks, and you keep ignoring them,
maybe you have missed them because we are not top-posting?

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06  8:19                             ` Gilles Chanteperdrix
  2013-03-06  8:55                               ` Jerome Poncin
@ 2013-03-06 10:33                               ` Jerome Poncin
  2013-03-06 12:04                                 ` Gilles Chanteperdrix
  1 sibling, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-06 10:33 UTC (permalink / raw)
  To: Gilles Chanteperdrix, xenomai

Hello Gilles,

I tried to integrate all of remarks. I give you my new patch.

If you have others remarks don't hesitate ;-).

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





Le 06/03/2013 09:19, Gilles Chanteperdrix a écrit :
> On 03/06/2013 09:10 AM, Jerome Poncin wrote:
>
>> Hello Gilles,
>>
>> I don't understand, because I think I did a maximum of modifications
>> that you said me...
> Not really, both Jan and I gave you (different) reasons why this is wrong:
>
> +static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
> +			      rtdm_user_info_t *user_info, const void *buf,
> +			      size_t nbyte)
> +{
> +	struct io_map_mem map_mem;
> +	int ret;
> +
> +	if (nbyte > sizeof(struct io_map_mem))
> +		return 0;
> +
> +	if (nbyte == sizeof(struct io_map_mem)) {
> +		/* Copy data information for Kernel */
> +		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
> +			nbyte = 0;
> +		} else {
> +			if (*map_mem.virt_addr == NULL) {
> +				/* Map physical on virtual memory */
> +				ret = rtdm_iomap_to_user(user_info,
> +							 (phys_addr_t) map_mem.
> +							 phys_addr,
> +							 (size_t) map_mem.
> +							 length,
> +							 (PROT_READ |
> +							  PROT_WRITE),
> +							 map_mem.virt_addr,
> +							 NULL, NULL);
> +
> +				if (ret != 0)
> +					nbyte = 0;
> +			} else {
> +				/* Unap virtual memory */
> +				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
> +						  (size_t) map_mem.length);
> +
> +				if (ret != 0)
> +					nbyte = 0;
> +			}
> +		}
> +	} else {
> +		/* Error nothing to do */
> +		nbyte = 0;
> +	}
> +
> +	return nbyte;
> +}
>
> Yet you kept this in the "final" patch.
>
>
>> I'm agree to test the code if you fixed the code, no problem. Perhaps I
>> don't understand what you really want.
>>
>> For modification in 80 line, how to change this ? :
>>
>> struct pxa_dev_info *pxa_info =
>>          (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
>>      uint32_t __iomem *plx_timing;
>>
>> I can't do a function...
>
> Well, first of all you should not use "pxa" as a suffix, as you may know,
> there are processors named "pxa", so, this may conflict. Some name related
> to the board would be better, such as "cifx".
>
> Second, there are usually acesssors to things like "device_data" and "priv"
> members.
>
> Thirdly, in C, you do not need an explicit cast when casting from void *,
> to any pointer type, this is what makes using malloc convenient for instance.
> So, what you should really do is:
>
> struct io_info *io_info = the_device_data_accessor(info);
> struct cifx_dev_info *dev_info = the_priv_accessor(io_info);
>

-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
+#endif
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..fa7d765
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.h>
+
+#include <rtdm/rtdm_driver.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct ext_io_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	struct ext_io_info *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+static struct io_info *cifx_get_device_data(struct rtdm_device *info);
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info);
+
+static int cifx_set_plx_timing(struct rtdm_device *info);
+static int cifx_get_plx_timing(struct rtdm_device *info);
+static int cifx_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX,
+	0, 0},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH},
+	{ 0,}
+};
+
+/* RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_rtdm_device_to_device_data
+ *	Get device_data structure
+ */
+static struct io_info *cifx_get_device_data(struct rtdm_device *info)
+{
+	return info->device_data;
+}
+
+/*
+ *	cifx_rtdm_device_to_private
+ *	Get ext_io_info structure
+ */
+static struct ext_io_info *cifx_get_private(struct rtdm_device *info)
+{
+	return ((struct io_info *)info->device_data)->priv;
+}
+
+/*
+ *	cifx_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_set_plx_timing(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	uint32_t __iomem *plx_timing;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_timing = ext_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = ext_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_get_plx_timing(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	switch (ext_info->dpm_mode) {
+	case 8:
+		ext_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		ext_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		ext_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_get_dpm_mode(struct rtdm_device *info)
+{
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	uint32_t __iomem *plx_gpio;
+
+	if (ext_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = ext_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		ext_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open RTDM cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close RTDM cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_read
+ * Read
+ */
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info))
+		return 0;
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte))
+		return 0;
+
+	return nbyte;
+}
+
+/*
+ * cifx_pci_write
+ * write
+ */
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+	struct io_map_mem map_mem;
+	int ret;
+
+	switch (nbyte) {
+	case sizeof(map_mem):
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0)
+					nbyte = 0;
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0)
+					nbyte = 0;
+			}
+		}
+		break;
+
+	default:
+		/* Error */
+		return 0;
+	}
+
+	return nbyte;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	ret = pci_enable_device(dev);
+	if (ret != 0)
+		goto out_free;
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0)
+		goto out_disable;
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL)
+		goto out_release;
+
+	memset(device_data, 0, sizeof(*device_data));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
+
+	if (device_data->mem[DPM_INDEX].addr == 0)
+		goto out_release;
+
+	device_data->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+						pci_resource_len(dev, bar));
+
+	if (device_data->mem[DPM_INDEX].internal_addr == 0)
+		goto out_release;
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+			(long unsigned int)device_data->mem[DPM_INDEX].addr);
+	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
+	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	device_data->mem[EXT_MEM_INDEX].addr =
+					pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (device_data->mem[EXT_MEM_INDEX].addr != 0) {
+		device_data->mem[EXT_MEM_INDEX].internal_addr =
+			ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+					pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
+			goto out_unmap;
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+		(long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
+		device_data->mem[EXT_MEM_INDEX].size =
+					pci_resource_len(dev, EXT_MEM_BAR);
+		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+							+ DPM_HOST_INT_EN0);
+		device_data->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct ext_io_info *ext_info =
+				rtdm_malloc(sizeof(struct ext_io_info));
+
+		if (ext_info == NULL)
+			goto out_unmap;
+
+		device_data->priv = ext_info;
+
+		/* set PXA PLX Timings */
+		ext_info->plx = ioremap_nocache(
+					pci_resource_start(dev, PXA_PLX_BAR),
+					pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (ext_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct ext_io_info *ext_info =
+				rtdm_malloc(sizeof(struct ext_io_info));
+
+		if (ext_info == NULL)
+			goto out_free_pxa;
+
+		ext_info->plx = NULL;
+		ext_info->plx_timing = 0;
+		ext_info->dpm_mode = 0;
+		device_data->priv = ext_info;
+	}
+
+	/* Initialize irq data */
+	device_data->irq = dev->irq;
+	device_data->irq_enable = 0;
+	device_data->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct ext_io_info *ext_info = device_data->priv;
+		dev_info(&dev->dev,
+			"registered NXPCA-PCI adapter card in %d bit mode\n",
+			((struct ext_io_info *)ext_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap((device_data->priv)->plx);
+
+ out_free_pxa:
+	rtdm_free(device_data->priv);
+
+ out_unmap:
+	iounmap(device_data->mem[DPM_INDEX].internal_addr);
+	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = cifx_get_device_data(info);
+	struct ext_io_info *ext_info = cifx_get_private(info);
+	int32_t ret;
+
+	if (info->device_data == NULL)
+		return;
+
+	if (ext_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr
+							+ DPM_HOST_INT_EN0);
+
+		if (ext_info->plx != NULL)
+			iounmap((void *)ext_info->plx);
+
+		rtdm_free((void *)ext_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0)
+		return;
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	/* Unmap memory */
+	iounmap(device_data->mem[DPM_INDEX].internal_addr);
+	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
+		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
+

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06  8:19                             ` Gilles Chanteperdrix
@ 2013-03-06  8:55                               ` Jerome Poncin
  2013-03-06 10:33                               ` Jerome Poncin
  1 sibling, 0 replies; 57+ messages in thread
From: Jerome Poncin @ 2013-03-06  8:55 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

Hello Gilles,

Thank you for all your explanation.

I must give you some explanation too. My Driver base is code from Linux 
Kernel, uio_netx that I adapted for doing a Xenomai driver.
In this driver "pxa" as a suffix is used.

I will try to review code to give a new version.

Thank you for your help.

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





Le 06/03/2013 09:19, Gilles Chanteperdrix a écrit :
> On 03/06/2013 09:10 AM, Jerome Poncin wrote:
>
>> Hello Gilles,
>>
>> I don't understand, because I think I did a maximum of modifications
>> that you said me...
> Not really, both Jan and I gave you (different) reasons why this is wrong:
>
> +static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
> +			      rtdm_user_info_t *user_info, const void *buf,
> +			      size_t nbyte)
> +{
> +	struct io_map_mem map_mem;
> +	int ret;
> +
> +	if (nbyte > sizeof(struct io_map_mem))
> +		return 0;
> +
> +	if (nbyte == sizeof(struct io_map_mem)) {
> +		/* Copy data information for Kernel */
> +		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
> +			nbyte = 0;
> +		} else {
> +			if (*map_mem.virt_addr == NULL) {
> +				/* Map physical on virtual memory */
> +				ret = rtdm_iomap_to_user(user_info,
> +							 (phys_addr_t) map_mem.
> +							 phys_addr,
> +							 (size_t) map_mem.
> +							 length,
> +							 (PROT_READ |
> +							  PROT_WRITE),
> +							 map_mem.virt_addr,
> +							 NULL, NULL);
> +
> +				if (ret != 0)
> +					nbyte = 0;
> +			} else {
> +				/* Unap virtual memory */
> +				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
> +						  (size_t) map_mem.length);
> +
> +				if (ret != 0)
> +					nbyte = 0;
> +			}
> +		}
> +	} else {
> +		/* Error nothing to do */
> +		nbyte = 0;
> +	}
> +
> +	return nbyte;
> +}
>
> Yet you kept this in the "final" patch.
>
>
>> I'm agree to test the code if you fixed the code, no problem. Perhaps I
>> don't understand what you really want.
>>
>> For modification in 80 line, how to change this ? :
>>
>> struct pxa_dev_info *pxa_info =
>>          (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
>>      uint32_t __iomem *plx_timing;
>>
>> I can't do a function...
>
> Well, first of all you should not use "pxa" as a suffix, as you may know,
> there are processors named "pxa", so, this may conflict. Some name related
> to the board would be better, such as "cifx".
>
> Second, there are usually acesssors to things like "device_data" and "priv"
> members.
>
> Thirdly, in C, you do not need an explicit cast when casting from void *,
> to any pointer type, this is what makes using malloc convenient for instance.
> So, what you should really do is:
>
> struct io_info *io_info = the_device_data_accessor(info);
> struct cifx_dev_info *dev_info = the_priv_accessor(io_info);
>

-------------- next part --------------
/*
 * UIO Hilscher NetX card driver
 *
 * (C) 2007 Hans J. Koch <hjk@linutronix.de>
 *
 * Licensed under GPL version 2 only.
 *
 */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/uio_driver.h>

#include <linux/io.h>

#ifndef PCI_VENDOR_ID_HILSCHER
  #define PCI_VENDOR_ID_HILSCHER   0x15CF
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
  #define PCI_DEVICE_ID_HILSCHER_NETX  0x0000
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
  #define PCI_DEVICE_ID_HILSCHER_NETPLC  0x0010
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
  #define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
#endif

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
  #define PCI_SUBDEVICE_ID_NXSB_PCA  0x3235
#endif

#ifndef PCI_SUBDEVICE_ID_NXPCA
  #define PCI_SUBDEVICE_ID_NXPCA   0x3335
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
  #define PCI_SUBDEVICE_ID_NETPLC_RAM   0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
  #define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
  #define PCI_SUBDEVICE_ID_NETJACK_RAM   0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
  #define PCI_SUBDEVICE_ID_NETJACK_FLASH   0x0001
#endif

#define DPM_HOST_INT_EN0	0xfff0
#define DPM_HOST_INT_STAT0	0xffe0
#define PLX_GPIO_OFFSET         0x15
#define PLX_TIMING_OFFSET       0x0a

#define DPM_HOST_INT_MASK	0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN	0x80000000
#define PLX_GPIO_DATA0_MASK     0x00000004
#define PLX_GPIO_DATA1_MASK     0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 0x40824122

/* number of bar */
#define DPM_BAR     0 /* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 1 /* points to the optional extended memory     */
#define PLX_DPM_BAR 2 /* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 0 /* timing config register                     */

/* index of uio_info structure's memory array */
#define DPM_INDEX     0 /* first mapping describes DPM              */
#define EXT_MEM_INDEX 1 /* second mapping describes extended memory */

struct pxa_dev_info {
	uint32_t __iomem *plx;
	uint8_t dpm_mode;
	uint32_t plx_timing;
};

static irqreturn_t netx_handler(int irq, struct uio_info *dev_info)
{
	if(dev_info->priv != NULL)
	{
		/* This is a PLX device and cannot produce an IRQ */
		return IRQ_NONE;
	} else
	{	
		void __iomem *int_enable_reg = dev_info->mem[0].internal_addr
						+ DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = dev_info->mem[0].internal_addr
						+ DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
			& DPM_HOST_INT_MASK))
			return IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN,
			int_enable_reg);
		return IRQ_HANDLED;
	}
}

static int netx_pxa_set_plx_timing(struct uio_info *info)
{
	struct pxa_dev_info *pxa_info = (struct pxa_dev_info *) info->priv;
	uint32_t __iomem *plx_timing;
	if (!pxa_info)
		return -ENODEV;
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	return 0;
}

static int netx_pxa_get_plx_timing(struct uio_info *info)
{
	struct pxa_dev_info *pxa_info = (struct pxa_dev_info *) info->priv;
	if (!pxa_info)
		return -ENODEV;
	switch (pxa_info->dpm_mode) {
	case 8:
		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
		break;
	case 16:
		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
		break;
	case 32:
		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int netx_pxa_get_dpm_mode(struct uio_info *info)
{
	struct pxa_dev_info *pxa_info = (struct pxa_dev_info *) info->priv;
	uint32_t __iomem *plx_gpio;
	if (!pxa_info)
		return -ENODEV;
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) &&
	   ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) &&
		 (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) &&
		~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
	return 0;
}

static int __devinit netx_pci_probe(struct pci_dev *dev,
					const struct pci_device_id *id)
{
	struct uio_info *info;
	int bar;
	info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;
	if (pci_enable_device(dev))
		goto out_free;
	if (pci_request_regions(dev, "netx"))
		goto out_disable;
	switch (id->device) {
	case PCI_DEVICE_ID_HILSCHER_NETX:
		bar = DPM_BAR;
		info->name = "netx";
		break;
  case PCI_DEVICE_ID_HILSCHER_NETPLC:
		bar = DPM_BAR;
		info->name = "netplc";
		break;
  case PCI_DEVICE_ID_HILSCHER_NETJACK:
    bar = DPM_BAR;
    info->name = "netjack";
    break;
	default:
		bar = PLX_DPM_BAR;
		info->name = "netx_plx";
	}
	/* BAR 0 or 2 points to the card's dual port memory */
	info->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
  if (!info->mem[DPM_INDEX].addr)
    goto out_release;
 
  info->mem[DPM_INDEX].internal_addr = ioremap_nocache(
    pci_resource_start(dev, bar),
    pci_resource_len(dev, bar));
    
  if (!info->mem[DPM_INDEX].internal_addr)
    goto out_release;
  
  dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)info->mem[DPM_INDEX].addr);
  info->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  info->mem[DPM_INDEX].memtype = UIO_MEM_PHYS;
  
  /* map extended mem (BAR 1 points to the extended memory) */
  info->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
  /* extended memory is optional, so don't care if it is not present */
  if (info->mem[EXT_MEM_INDEX].addr)
  {
    info->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(
    pci_resource_start(dev, EXT_MEM_BAR),
    pci_resource_len(dev, EXT_MEM_BAR));  
    
    if (!info->mem[EXT_MEM_INDEX].internal_addr)
      goto out_unmap;
    
    dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)info->mem[EXT_MEM_INDEX].addr);
    info->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
    info->mem[EXT_MEM_INDEX].memtype = UIO_MEM_PHYS;
  }
  
  info->irq = dev->irq;
	info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
	info->handler = netx_handler;
	info->version = "0.0.1";
if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) ||
		(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) ||
		(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
		/* make sure all interrupts are disabled */
		iowrite32(0, info->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		info->priv = NULL;
	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
		/* map PLX registers */
		struct pxa_dev_info *pxa_info = (struct pxa_dev_info *)
			kzalloc(sizeof(struct pxa_dev_info), GFP_KERNEL);
		if (!pxa_info)
			goto out_unmap;
		info->priv = pxa_info;
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(
			pci_resource_start(dev, PXA_PLX_BAR),
			pci_resource_len(dev, PXA_PLX_BAR));
		if (!pxa_info->plx)
			goto out_unmap;
		if (netx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (netx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (netx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} else {
		struct pxa_dev_info *pxa_info = (struct pxa_dev_info *)
			kzalloc(sizeof(struct pxa_dev_info), GFP_KERNEL);
		if (!pxa_info)
			goto out_free_pxa;
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		info->priv = pxa_info;
	}

	if (uio_register_device(&dev->dev, info)) {
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}
	pci_set_drvdata(dev, info);
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev,
			"registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev,
			"registered netPLC card\n");
  else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
    dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,
			"registered NXSB-PCA adapter card\n");
	else {
		struct pxa_dev_info *pxa_info = (struct pxa_dev_info *)
			info->priv;
		dev_info(&dev->dev,
			"registered NXPCA-PCI adapter card in %d bit mode\n",
			pxa_info->dpm_mode);
	}
	return 0;
out_unmap_plx:
	iounmap(((struct pxa_dev_info *)(info->priv))->plx);
out_free_pxa:
	kfree(info->priv);
out_unmap:
	iounmap(info->mem[DPM_INDEX].internal_addr);
  if (info->mem[EXT_MEM_INDEX].internal_addr)
    iounmap(info->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
out_disable:
	pci_disable_device(dev);
out_free:
	kfree(info);
	return -ENODEV;
}

static void netx_pci_remove(struct pci_dev *dev)
{
	struct uio_info *info = pci_get_drvdata(dev);
	struct pxa_dev_info *pxa_info = (struct pxa_dev_info *)
		info->priv;
	if (!pxa_info) {
		/* Disable all interrupts */
		iowrite32(0, info->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	} 
	if ( pxa_info && pxa_info->plx)
		iounmap(pxa_info->plx);
	if (pxa_info)
		kfree(pxa_info);
	uio_unregister_device(info);
	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	iounmap(info->mem[DPM_INDEX].internal_addr);
  if (info->mem[EXT_MEM_INDEX].internal_addr)
    iounmap(info->mem[EXT_MEM_INDEX].internal_addr);
	kfree(info);
}

static struct pci_device_id netx_pci_ids[] = {
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
    .vendor = PCI_VENDOR_ID_HILSCHER,
    .device = PCI_DEVICE_ID_HILSCHER_NETJACK,
    .subvendor =  PCI_VENDOR_ID_HILSCHER,
    .subdevice =  PCI_SUBDEVICE_ID_NETJACK_RAM,
  },
  {
    .vendor = PCI_VENDOR_ID_HILSCHER,
    .device = PCI_DEVICE_ID_HILSCHER_NETJACK,
    .subvendor =  PCI_VENDOR_ID_HILSCHER,
    .subdevice =  PCI_SUBDEVICE_ID_NETJACK_FLASH,
  },
	{ 0, }
};

static struct pci_driver netx_pci_driver = {
	.name = "netx",
	.id_table = netx_pci_ids,
	.probe = netx_pci_probe,
	.remove = netx_pci_remove,
};

static int __init netx_init_module(void)
{
	return pci_register_driver(&netx_pci_driver);
}

static void __exit netx_exit_module(void)
{
	pci_unregister_driver(&netx_pci_driver);
}

module_init(netx_init_module);
module_exit(netx_exit_module);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hans J. Koch, Manuel Traut");

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-06  8:10                           ` Jerome Poncin
@ 2013-03-06  8:19                             ` Gilles Chanteperdrix
  2013-03-06  8:55                               ` Jerome Poncin
  2013-03-06 10:33                               ` Jerome Poncin
  0 siblings, 2 replies; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-06  8:19 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/06/2013 09:10 AM, Jerome Poncin wrote:

> 
> Hello Gilles,
> 
> I don't understand, because I think I did a maximum of modifications

> that you said me...

Not really, both Jan and I gave you (different) reasons why this is wrong:

+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem))
+		return 0;
+
+	if (nbyte == sizeof(struct io_map_mem)) {
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0)
+					nbyte = 0;
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0)
+					nbyte = 0;
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}

Yet you kept this in the "final" patch.


> 
> I'm agree to test the code if you fixed the code, no problem. Perhaps I
> don't understand what you really want.
> 
> For modification in 80 line, how to change this ? :
> 
> struct pxa_dev_info *pxa_info =
>         (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
>     uint32_t __iomem *plx_timing;
> 
> I can't do a function...


Well, first of all you should not use "pxa" as a suffix, as you may know,
there are processors named "pxa", so, this may conflict. Some name related 
to the board would be better, such as "cifx".

Second, there are usually acesssors to things like "device_data" and "priv"
members. 

Thirdly, in C, you do not need an explicit cast when casting from void *, 
to any pointer type, this is what makes using malloc convenient for instance.
So, what you should really do is:

struct io_info *io_info = the_device_data_accessor(info);
struct cifx_dev_info *dev_info = the_priv_accessor(io_info);

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 19:41                         ` Gilles Chanteperdrix
@ 2013-03-06  8:10                           ` Jerome Poncin
  2013-03-06  8:19                             ` Gilles Chanteperdrix
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-06  8:10 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

Hello Gilles,

I don't understand, because I think I did a maximum of modifications 
that you said me...

I'm agree to test the code if you fixed the code, no problem. Perhaps I 
don't understand what you really want.

For modification in 80 line, how to change this ? :

struct pxa_dev_info *pxa_info =
         (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
     uint32_t __iomem *plx_timing;

I can't do a function...

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44



Le 05/03/2013 20:41, Gilles Chanteperdrix a écrit :
> On 03/05/2013 04:42 PM, Jerome Poncin wrote:
>
>> Hello,
>>
>> Finally, I removed #define Debug  with a little code re factoring. I
>> tested with all kernel compilation.
>> It run well, therefore I send you my last patch.
>
> Ok, I understand you are not willing to follow our recommandations.
> Would you agree to test it if we fixed your code?
>
>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 15:42                       ` Jerome Poncin
@ 2013-03-05 19:41                         ` Gilles Chanteperdrix
  2013-03-06  8:10                           ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-05 19:41 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/05/2013 04:42 PM, Jerome Poncin wrote:

> Hello,
> 
> Finally, I removed #define Debug  with a little code re factoring. I 
> tested with all kernel compilation.
> It run well, therefore I send you my last patch.


Ok, I understand you are not willing to follow our recommandations.
Would you agree to test it if we fixed your code?


-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 11:26                     ` Jan Kiszka
  2013-03-05 12:21                       ` Gilles Chanteperdrix
  2013-03-05 12:30                       ` Gilles Chanteperdrix
@ 2013-03-05 15:42                       ` Jerome Poncin
  2013-03-05 19:41                         ` Gilles Chanteperdrix
  2 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-05 15:42 UTC (permalink / raw)
  To: xenomai

Hello,

Finally, I removed #define Debug  with a little code re factoring. I 
tested with all kernel compilation.
It run well, therefore I send you my last patch.

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44


-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
+#endif
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..2cfe2c0
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.h>
+
+#include <rtdm/rtdm_driver.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX,
+	0, 0},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXSB_PCA},
+	{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
+	PCI_VENDOR_ID_PLX, PCI_SUBDEVICE_ID_NXPCA},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETPLC_FLASH},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_RAM},
+	{PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK,
+	PCI_VENDOR_ID_HILSCHER, PCI_SUBDEVICE_ID_NETJACK_FLASH},
+	{ 0,}
+};
+
+/* RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_pxa_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_pxa_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_pxa_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open RTDM cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close RTDM cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_read
+ * Read
+ */
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info))
+		return 0;
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte))
+		return 0;
+
+	return nbyte;
+}
+
+/*
+ * cifx_pci_write
+ * write
+ */
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem))
+		return 0;
+
+	if (nbyte == sizeof(struct io_map_mem)) {
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0)
+					nbyte = 0;
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0)
+					nbyte = 0;
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	ret = pci_enable_device(dev);
+	if (ret != 0)
+		goto out_free;
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0)
+		goto out_disable;
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL)
+		goto out_release;
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0)
+		goto out_release;
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0)
+		goto out_release;
+
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0)
+			goto out_unmap;
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL)
+			goto out_unmap;
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (pxa_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL)
+			goto out_free_pxa;
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = 0;
+	((struct io_info *)device_data)->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL)
+		return;
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0)
+		return;
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 11:26                     ` Jan Kiszka
  2013-03-05 12:21                       ` Gilles Chanteperdrix
@ 2013-03-05 12:30                       ` Gilles Chanteperdrix
  2013-03-05 15:42                       ` Jerome Poncin
  2 siblings, 0 replies; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-05 12:30 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

On 03/05/2013 12:26 PM, Jan Kiszka wrote:

>> => I agree with you but that the price to be compliant with
>> checkpatch.pl... limitation to 80 characters per line is difficult for me.
>> If you saw some better thing to do, don't hesitate ;-) ! I tried to my
>> best !
> 
> If you overrun the 80-char limit, it is usually a good sign that you
> should introduce a function.


Or that you are nesting ifs the wrong way, as I tried to explain.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 11:26                     ` Jan Kiszka
@ 2013-03-05 12:21                       ` Gilles Chanteperdrix
  2013-03-05 12:30                       ` Gilles Chanteperdrix
  2013-03-05 15:42                       ` Jerome Poncin
  2 siblings, 0 replies; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-05 12:21 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

On 03/05/2013 12:26 PM, Jan Kiszka wrote:

> On 2013-03-05 11:45, Jerome Poncin wrote:
>> The code with #ifdef DEBUG is also questionable, it will tend to bitrot
>> since nobody will think to enable it.
>>
>> => I disagree with you, it could be helpful if somebody have a problem
>> and want to debug quickly.
>> But I can remove it if it's not standard to xenomai kernel.
> 
> #ifdef DEBUG is widely considered obsolete. If you have debug relevant
> information, tracepoints are much better as they are runtime switchable.
> 
> But to look at a concrete example:
> 
>> +static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
>> +                 rtdm_user_info_t *user_info, void *buf,
>> +                 size_t nbyte)
>> +{
>> +    struct rtdm_device *info = (struct rtdm_device *)context->device;
>> +
>> +    if (nbyte > sizeof(struct io_info)) {
>> +#ifdef DEBUG
>> +        rtdm_printk
>> +            ("cifx rtdm driver error : data user size too big\n");
>> +#endif /* DEBUG */
>> +
>> +        return 0;
> 
> If it is an error, return the proper code (-EINVAL? Or -E2BIG?). That
> will be visible without any driver instrumentation.
> 
>> +    }
>> +
>> +    /* Copy data information for userland */
>> +    if (rtdm_safe_copy_to_user(user_info, buf,
>> +                   ((struct io_info *)info->device_data),
>> +                   nbyte)) {
>> +#ifdef DEBUG
>> +        rtdm_printk
>> +            ("cifx rtdm driver error : can't copy data from driver\n");
>> +#endif /* DEBUG */
> 
> And this is a bug: return -EFAULT. Again, no need for driver
> instrumentation.
> 
>> +    }
>> +
>> +    return nbyte;
>> +}
> 
> ...
> 
>>
>> I think you are not convinced yet that "code is the best documentation"
>>
>> => Yes, you right it's because I worked long time on safety project (for
>> me it's a habit) .
>> Moreover I thunk it could be helpful in an open source project, if
>> somebody want to more easily understand code.
> 
> Non-trivial code is better augmented with comments.


Or better removed and replaced with trivial code...

> However, commenting
> on the obvious is like meaningless chatting. ;)


Yes, IMO, a driver should not be a tutorial for people wanting to write
other drivers, if they need a tutorial, they should look for a tutorial,
not for comments in existing code.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-05 10:45                   ` Jerome Poncin
@ 2013-03-05 11:26                     ` Jan Kiszka
  2013-03-05 12:21                       ` Gilles Chanteperdrix
                                         ` (2 more replies)
  0 siblings, 3 replies; 57+ messages in thread
From: Jan Kiszka @ 2013-03-05 11:26 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-03-05 11:45, Jerome Poncin wrote:
> The code with #ifdef DEBUG is also questionable, it will tend to bitrot
> since nobody will think to enable it.
> 
> => I disagree with you, it could be helpful if somebody have a problem
> and want to debug quickly.
> But I can remove it if it's not standard to xenomai kernel.

#ifdef DEBUG is widely considered obsolete. If you have debug relevant
information, tracepoints are much better as they are runtime switchable.

But to look at a concrete example:

> +static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
> +                 rtdm_user_info_t *user_info, void *buf,
> +                 size_t nbyte)
> +{
> +    struct rtdm_device *info = (struct rtdm_device *)context->device;
> +
> +    if (nbyte > sizeof(struct io_info)) {
> +#ifdef DEBUG
> +        rtdm_printk
> +            ("cifx rtdm driver error : data user size too big\n");
> +#endif /* DEBUG */
> +
> +        return 0;

If it is an error, return the proper code (-EINVAL? Or -E2BIG?). That
will be visible without any driver instrumentation.

> +    }
> +
> +    /* Copy data information for userland */
> +    if (rtdm_safe_copy_to_user(user_info, buf,
> +                   ((struct io_info *)info->device_data),
> +                   nbyte)) {
> +#ifdef DEBUG
> +        rtdm_printk
> +            ("cifx rtdm driver error : can't copy data from driver\n");
> +#endif /* DEBUG */

And this is a bug: return -EFAULT. Again, no need for driver
instrumentation.

> +    }
> +
> +    return nbyte;
> +}

...

> 
> I think you are not convinced yet that "code is the best documentation"
> 
> => Yes, you right it's because I worked long time on safety project (for
> me it's a habit) .
> Moreover I thunk it could be helpful in an open source project, if
> somebody want to more easily understand code.

Non-trivial code is better augmented with comments. However, commenting
on the obvious is like meaningless chatting. ;)

> 
> The coding style is a bit indigest
> 
> => I agree with you but that the price to be compliant with
> checkpatch.pl... limitation to 80 characters per line is difficult for me.
> If you saw some better thing to do, don't hesitate ;-) ! I tried to my
> best !

If you overrun the 80-char limit, it is usually a good sign that you
should introduce a function.

Jan

PS: Your mail client does funky marking of cited text. The web standard
is ">".

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-04 21:08                 ` Gilles Chanteperdrix
@ 2013-03-05 10:45                   ` Jerome Poncin
  2013-03-05 11:26                     ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-05 10:45 UTC (permalink / raw)
  To: xenomai

Hello Gilles,

1/ Have you tested your driver on Linux 2.4?

No, therefore I remove all necessary for compilation with Linux 2.4.

2/
+++ b/ksrc/drivers/cifx/Config.in~

> +++ b/ksrc/drivers/cifx/Kconfig~
> +++ b/ksrc/drivers/cifx/Makefile~
> +++ b/ksrc/drivers/cifx/cifx_pci.c~

We do not want these file. A simple way to avoid it (besides using diff
-x option), is to work with git, and generate your patches with git
format-patch.

I'm sorry I didn't see this file. It's clean now.

3/ I did all correction. I give you my new patch in attached file.


I have few remarks :

The code with #ifdef DEBUG is also questionable, it will tend to bitrot
since nobody will think to enable it.

=> I disagree with you, it could be helpful if somebody have a problem 
and want to debug quickly.
But I can remove it if it's not standard to xenomai kernel.

I think you are not convinced yet that "code is the best documentation"

=> Yes, you right it's because I worked long time on safety project (for 
me it's a habit) .
Moreover I thunk it could be helpful in an open source project, if 
somebody want to more easily understand code.

The coding style is a bit indigest

=> I agree with you but that the price to be compliant with 
checkpatch.pl... limitation to 80 characters per line is difficult for me.
If you saw some better thing to do, don't hesitate ;-) ! I tried to my 
best !

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44


-------------- next part --------------
diff --git a/include/asm-generic/pci_ids.h b/include/asm-generic/pci_ids.h
index d298bf4..3f8d7cc 100644
--- a/include/asm-generic/pci_ids.h
+++ b/include/asm-generic/pci_ids.h
@@ -40,4 +40,45 @@
 #define PCI_DEVICE_ID_PLX_9056 0x9056
 #endif
 
+/* cifx */
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER 0x15CF
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX 0x0000
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC 0x0010
+#endif
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK 0x0020
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA 0x3235
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA 0x3335
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH 0x0001
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM 0x0000
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH 0x0001
+#endif
+
 #endif /* _XENO_ASM_GENERIC_PCI_IDS_H */
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..42550bd
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,13 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..2ddac39
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2013 Hilscher France (JP) <www.hilscher.fr>
+ *
+ * Xenomai 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.
+ *
+ * Xenomai 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 Xenomai; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <asm-generic/xenomai/pci_ids.h>
+
+#include <rtdm/rtdm_driver.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	bool irq_enable;
+	bool irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/* Number or cifx found and open */
+static int32_t cifx_num;
+
+/* RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/* Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{PCI_VDEVICE(PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETX)},
+	{PCI_VDEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030),
+	.subvendor = PCI_VENDOR_ID_PLX,
+	.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{PCI_VDEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030),
+	.subvendor = PCI_VENDOR_ID_PLX,
+	.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{PCI_VDEVICE(PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC),
+	.subvendor = PCI_VENDOR_ID_HILSCHER,
+	.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{PCI_VDEVICE(PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETPLC),
+	.subvendor = PCI_VENDOR_ID_HILSCHER,
+	.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{PCI_VDEVICE(PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK),
+	.subvendor = PCI_VENDOR_ID_HILSCHER,
+	.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{PCI_VDEVICE(PCI_VENDOR_ID_HILSCHER, PCI_DEVICE_ID_HILSCHER_NETJACK),
+	.subvendor = PCI_VENDOR_ID_HILSCHER,
+	.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/* RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*
+ *	cifx_pxa_set_plx_timing
+ *	Set plx timing
+ */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*
+ * cifx_pxa_get_plx_timing
+ * Get plx timing
+ */
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * cifx_pxa_get_dpm_mode
+ * Get dpm mode
+ */
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (pxa_info == NULL)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*
+ * cifx_pci_open
+ * Open RTDM cifx pci driver
+ */
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_close
+ * Close RTDM cifx pci driver
+ */
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+	return 0;
+}
+
+/*
+ * cifx_pci_read
+ * Read
+ */
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*
+ * cifx_pci_write
+ * write
+ */
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+	if (nbyte == sizeof(struct io_map_mem)) {
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(*info));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (pxa_info->plx == NULL)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = 0;
+	((struct io_info *)device_data)->irq_registered = 0;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-04  9:13               ` Jerome Poncin
@ 2013-03-04 21:08                 ` Gilles Chanteperdrix
  2013-03-05 10:45                   ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-04 21:08 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/04/2013 10:13 AM, Jerome Poncin wrote:

> Hello,
> 
> I did two patch one for version head, and for 2.6 version in attached 
> files.  The result is identical.


xenomai-head is a symbolic link to xenomai-2.6. Well, if I did not
forget to put it again during the xenomai.org server migration.

> 
> Therefore, I let you
> 
> "perform a code review and merge
> the code if it is fine."


The coding style is a bit indigest, so I will criticize this first and
let you send a cleaned up version which I will really be able to read.
Maybe others will be able to really read the code, but I am afraid I can't.

> +#
> +# Xenomai configuration for Linux v2.4
> +#


Have you tested your driver on Linux 2.4?

> +++ b/ksrc/drivers/cifx/Config.in~

> +++ b/ksrc/drivers/cifx/Kconfig~
> +++ b/ksrc/drivers/cifx/Makefile~
> +++ b/ksrc/drivers/cifx/cifx_pci.c~

We do not want these file. A simple way to avoid it (besides using diff
-x option), is to work with git, and generate your patches with git
format-patch.


> +/***************************************************************************
> + *   Copyright (C) 2013                                                    *
> + *   Hilscher France (JP)                                                  *
> + *   http://www.hilscher.fr                                                *
> + *                                                                         *
> + *   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.             *
> + ***************************************************************************/


Please don't do that. Look at the other files in Xenomai sources to see
how we put the GPL "cartouche". And the doxygen cartouches as well.

The standard multiline comment is:

/*
 *
 */

> +

> +/*****************************************************************************/


We do not want that either

> +
> +/* Includes */


Useless comment, everything which begins with #include is obviously an
include

> +#ifndef TRUE
> +#define TRUE                            1
> +#endif				/* TRUE */
> +
> +#ifndef FALSE
> +#define FALSE                           0
> +#endif				/* TRUE */


No, you do not want to do that. If you really want to use true and
false, use the "bool" type (but I agree, this will not work with 2.4,
but have you really tested your driver with Linux 2.4?).

Besides, tests like if (foo == TRUE) are a bit preposterous. If foo is a
boolean, then if (foo) already tests if foo is true. If we follow your
reasoning why not adding a few more == TRUE ?
If (((foo == TRUE) == TRUE) == TRUE) ?


> +
> +#ifndef PCI_VENDOR_ID_HILSCHER
> +#define PCI_VENDOR_ID_HILSCHER          0x15CF
> +#endif				/* PCI_VENDOR_ID_HILSCHER */
> +
> +#ifndef PCI_DEVICE_ID_HILSCHER_NETX
> +#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
> +#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
> +
> +#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
> +#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
> +#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
> +
> +#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
> +#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
> +#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
> +
> +#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
> +#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
> +#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
> +
> +#ifndef PCI_SUBDEVICE_ID_NXPCA
> +#define PCI_SUBDEVICE_ID_NXPCA          0x3335
> +#endif				/* PCI_SUBDEVICE_ID_NXPCA */
> +
> +#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
> +#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
> +#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
> +
> +#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
> +#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
> +#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
> +
> +#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
> +#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
> +#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
> +
> +#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
> +#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
> +#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */


These defines should go to asm-generic/pci_ids.h


> +/* Prototypes */


Just as useless as "includes".

> +/* Local variables */


Again.

> +/** RTDM Device information structure */


Again


> +/** Device table */


Again.

> +static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
> +	{
> +		.vendor = PCI_VENDOR_ID_HILSCHER,
> +		.device = PCI_DEVICE_ID_HILSCHER_NETX,
> +		.subvendor = 0,
> +		.subdevice = 0,
> +	},


There are convenient standard macro to put these declarations on a
single line.

> +#ifdef IRQ_SUPPORT


If IRQ support is not tested, and is never compiled, then this is dead
code, remove it.

The code with #ifdef DEBUG is also questionable, it will tend to bitrot
since nobody will think to enable it.


> +	/* Test if (oflags) IRQ are use */
> +	if (oflags == TRUE) {
> +		if (((struct io_info_t *)info->device_data)->irq_registered
> +		    == FALSE) {
> +			/* Register IRQ */
> +			ret =
> +			    rtdm_irq_request(&
> +					     (((struct io_info_t *)info->
> +					       device_data)->irq_handle),
> +					     ((struct io_info_t *)info->
> +					      device_data)->irq, cifx_handler,
> +					     RTDM_IRQTYPE_SHARED,
> +					     info->device_name, (void *)info);


Your code is drifting a lot to the right.

That is because instead of:

if (ok)
	if (still_ok)
		if (still_ok2)
			if (still_ok3)
				action;

you should do

if (!ok)
	return;

if (!still_ok)
	return;

if (!still_ok2)
	return;

if (!still_ok3)
	return;

This is much more readable.
And if you want to please Philippe, you should replace:

if (!ok)

with

if (ok == 0)

He finds this more readable (it is easy to miss the '!' character when
reading fast, and read the test inverted).


> +/*****************************************************************************/
> +/*!
> + *   \brief  cifx_pci_probe
> + *
> + *   \param  [in]   dev
> + *   \param  [in]   id
> + *
> + *   \return 0 (OK) or Error
> + *
> + *   \note  Open the device.
> + *			This function is called when the device shall be opened.
> + */
> +/*****************************************************************************/
> +static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)


I am not sure this function needs to be documented. What should be
documented in an RTDM driver is the driver "profile", meaning the
behaviour of the externally usable interface, the behaviour of open,
read, write, and most of all the various ioctls it supports.

The comment is misleading: the probe function is not called when the
device is opened, but when the device is enumerated by a device
enumeration technique (be it a bus like PCI or USB with enumeration, or
platform devices or device tree), and matched with a driver. The suffix
_probe suffices to indicate this situation, no further comment is needed.

> +	/* Initialize structure with default values */
> +	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));


I would use sizeof(*info) here, if the type of the info pointer changes,
the memcpy will not have unintended effects.

> +


> +/*****************************************************************************/
> +/*!
> + *   \brief  cifx_pci_init
> + *
> + *   \return None
> + *
> + *   \note   It simply registers the RTDM device.
> + *   This function is called when the module is loaded.
> + */
> +/*****************************************************************************/
> +static int __init cifx_pci_init(void)
> +{
> +	cifx_num = 0;
> +
> +	return pci_register_driver(&cifx_pci_driver);
> +}


Useless comment again. The following line:

> +module_init(cifx_pci_init);

Is sufficient to indicate that the function is called when the module is
loaded. So, if you want to make that obvious, put the declaration close
to the function definition, and avoid the comment.

I think  you are not convinced yet that "code is the best
documentation". Imagine a moment that we remove the "module_init" macro
call, the function will no longer be called when the module is loaded,
yet the comment will still claim that it is, and can puzzle someone
debugging your code and wondering why the pci driver does not get
registered.

-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-01 13:56             ` Jerome Poncin
  2013-03-01 17:02               ` Jan Kiszka
  2013-03-01 20:06               ` Gilles Chanteperdrix
@ 2013-03-04  9:13               ` Jerome Poncin
  2013-03-04 21:08                 ` Gilles Chanteperdrix
  2 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-03-04  9:13 UTC (permalink / raw)
  To: xenomai

Hello,

I did two patch one for version head, and for 2.6 version in attached 
files.  The result is identical.

Therefore, I let you

"perform a code review and merge
the code if it is fine."

For information, I checked a complete kernel compilation with cifX driver, and it's running good on xenomai version 2.6.2.1.

Thank you very much for your help.


Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44


-------------- next part --------------
diff --git a/ksrc/drivers/cifx/Config.in b/ksrc/drivers/cifx/Config.in
new file mode 100644
index 0000000..b4e6be1
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Config.in~ b/ksrc/drivers/cifx/Config.in~
new file mode 100644
index 0000000..2bbb0bb
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in~
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX driver' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig~ b/ksrc/drivers/cifx/Kconfig~
new file mode 100644
index 0000000..914d6e6
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig~
@@ -0,0 +1,11 @@
+menu "Real-time IPC drivers"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..63cbc00
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,37 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-objs := cifx_pci.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+xeno_cifx_pci-objs += $(opt_objs-y)
+
+export-objs := $(xeno_cifx_pci-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_cifx_pci.o: $(xeno_cifx_pci-objs)
+	$(LD) -r -o $@ $(xeno_cifx_pci-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/Makefile~ b/ksrc/drivers/cifx/Makefile~
new file mode 100644
index 0000000..3c90f1a
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile~
@@ -0,0 +1,41 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_rtipc.o
+
+xeno_rtipc-y := rtipc.o
+
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_RTIPC) += xeno_rtipc.o
+
+xeno_rtipc-objs := rtipc.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+xeno_rtipc-objs += $(opt_objs-y)
+
+export-objs := $(xeno_rtipc-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_rtipc.o: $(xeno_rtipc-objs)
+	$(LD) -r -o $@ $(xeno_rtipc-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..677367d
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,1189 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
diff --git a/ksrc/drivers/cifx/cifx_pci.c~ b/ksrc/drivers/cifx/cifx_pci.c~
new file mode 100644
index 0000000..2b3ffea
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c~
@@ -0,0 +1,1190 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
-------------- next part --------------
diff --git a/ksrc/drivers/cifx/Config.in b/ksrc/drivers/cifx/Config.in
new file mode 100644
index 0000000..b4e6be1
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Config.in~ b/ksrc/drivers/cifx/Config.in~
new file mode 100644
index 0000000..2bbb0bb
--- /dev/null
+++ b/ksrc/drivers/cifx/Config.in~
@@ -0,0 +1,10 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+mainmenu_option next_comment
+comment 'Real-time Hilscher cifX driver'
+
+dep_tristate 'Hilscher cifX driver' CONFIG_XENO_DRIVERS_CIFX $CONFIG_XENO_SKIN_RTDM
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig b/ksrc/drivers/cifx/Kconfig
new file mode 100644
index 0000000..715a45e
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig
@@ -0,0 +1,11 @@
+menu "Hilscher cifX driver"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Kconfig~ b/ksrc/drivers/cifx/Kconfig~
new file mode 100644
index 0000000..914d6e6
--- /dev/null
+++ b/ksrc/drivers/cifx/Kconfig~
@@ -0,0 +1,11 @@
+menu "Real-time IPC drivers"
+
+config XENO_DRIVERS_CIFX
+	depends on XENO_SKIN_RTDM
+	tristate "Hilscher cifX"
+	help
+
+	This driver provides Hilscher cifX 
+	over RTDM.
+
+endmenu
diff --git a/ksrc/drivers/cifx/Makefile b/ksrc/drivers/cifx/Makefile
new file mode 100644
index 0000000..63cbc00
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile
@@ -0,0 +1,37 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-y := cifx_pci.o
+
+xeno_cifx_pci-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_cifx_pci.o
+
+xeno_cifx_pci-objs := cifx_pci.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_CIFX) += cifx_pci.o
+
+xeno_cifx_pci-objs += $(opt_objs-y)
+
+export-objs := $(xeno_cifx_pci-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_cifx_pci.o: $(xeno_cifx_pci-objs)
+	$(LD) -r -o $@ $(xeno_cifx_pci-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/Makefile~ b/ksrc/drivers/cifx/Makefile~
new file mode 100644
index 0000000..3c90f1a
--- /dev/null
+++ b/ksrc/drivers/cifx/Makefile~
@@ -0,0 +1,41 @@
+ifneq ($(VERSION).$(PATCHLEVEL),2.4)
+
+# Makefile frag for Linux v2.6 and v3.x
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai -Idrivers/xenomai/cifx
+
+obj-$(CONFIG_XENO_DRIVERS_CIFX) += xeno_rtipc.o
+
+xeno_rtipc-y := rtipc.o
+
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+xeno_rtipc-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_RTIPC) += xeno_rtipc.o
+
+xeno_rtipc-objs := rtipc.o
+
+opt_objs-y :=
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_XDDP) += xddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_IDDP) += iddp.o
+opt_objs-$(CONFIG_XENO_DRIVERS_RTIPC_BUFP) += bufp.o
+
+xeno_rtipc-objs += $(opt_objs-y)
+
+export-objs := $(xeno_rtipc-objs)
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat -I.
+
+include $(TOPDIR)/Rules.make
+
+xeno_rtipc.o: $(xeno_rtipc-objs)
+	$(LD) -r -o $@ $(xeno_rtipc-objs)
+
+endif
diff --git a/ksrc/drivers/cifx/cifx_pci.c b/ksrc/drivers/cifx/cifx_pci.c
new file mode 100644
index 0000000..677367d
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c
@@ -0,0 +1,1189 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */
diff --git a/ksrc/drivers/cifx/cifx_pci.c~ b/ksrc/drivers/cifx/cifx_pci.c~
new file mode 100644
index 0000000..2b3ffea
--- /dev/null
+++ b/ksrc/drivers/cifx/cifx_pci.c~
@@ -0,0 +1,1190 @@
+/***************************************************************************
+ *   Copyright (C) 2013                                                    *
+ *   Hilscher France (JP)                                                  *
+ *   http://www.hilscher.fr                                                *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+/*****************************************************************************/
+
+/* Includes */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <linux/mman.h>
+
+#include <rtdm/rtdm_driver.h>
+
+/*****************************************************************************/
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTDM board driver for CifX cards");
+MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");
+
+/*****************************************************************************/
+/*!
+ *   \addtogroup cifx_pci_Core
+ *   @{
+ */
+/*****************************************************************************/
+
+/* #define */
+
+#ifndef TRUE
+#define TRUE                            1
+#endif				/* TRUE */
+
+#ifndef FALSE
+#define FALSE                           0
+#endif				/* TRUE */
+
+#ifndef PCI_VENDOR_ID_HILSCHER
+#define PCI_VENDOR_ID_HILSCHER          0x15CF
+#endif				/* PCI_VENDOR_ID_HILSCHER */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETX
+#define PCI_DEVICE_ID_HILSCHER_NETX     0x0000
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETX */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
+#define PCI_DEVICE_ID_HILSCHER_NETPLC   0x0010
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETPLC */
+
+#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
+#define PCI_DEVICE_ID_HILSCHER_NETJACK  0x0020
+#endif				/* PCI_DEVICE_ID_HILSCHER_NETJACK */
+
+#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
+#define PCI_SUBDEVICE_ID_NXSB_PCA       0x3235
+#endif				/* PCI_SUBDEVICE_ID_NXSB_PCA */
+
+#ifndef PCI_SUBDEVICE_ID_NXPCA
+#define PCI_SUBDEVICE_ID_NXPCA          0x3335
+#endif				/* PCI_SUBDEVICE_ID_NXPCA */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
+#define PCI_SUBDEVICE_ID_NETPLC_RAM     0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
+#define PCI_SUBDEVICE_ID_NETPLC_FLASH   0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETPLC_FLASH */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
+#define PCI_SUBDEVICE_ID_NETJACK_RAM    0x0000
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_RAM */
+
+#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
+#define PCI_SUBDEVICE_ID_NETJACK_FLASH  0x0001
+#endif				/* PCI_SUBDEVICE_ID_NETJACK_FLASH */
+
+#define DPM_HOST_INT_EN0                0xfff0
+#define DPM_HOST_INT_STAT0              0xffe0
+#define PLX_GPIO_OFFSET                 0x15
+#define PLX_TIMING_OFFSET               0x0a
+
+#define DPM_HOST_INT_MASK               0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN          0x80000000
+#define PLX_GPIO_DATA0_MASK             0x00000004
+#define PLX_GPIO_DATA1_MASK             0x00000020
+
+#define NX_PCA_PCI_8_BIT_DPM_MODE       0x5431F962
+#define NX_PCA_PCI_16_BIT_DPM_MODE      0x4073F8E2
+#define NX_PCA_PCI_32_BIT_DPM_MODE      0x40824122
+
+/* Number of bar */
+/* points to the DPM -> netX, netPLC, netJACK */
+#define DPM_BAR                         0
+/* points to the optional extended memory     */
+#define EXT_MEM_BAR                     1
+/* points to the DPM -> netXPLX               */
+#define PLX_DPM_BAR                     2
+/* timing config register                     */
+#define PXA_PLX_BAR                     0
+
+/* Index of io_info structure's memory array */
+/* first mapping describes DPM              */
+#define DPM_INDEX                       0
+/* second mapping describes extended memory */
+#define EXT_MEM_INDEX                   1
+
+#define MAX_MAPS                        2
+
+#define MEM_PHYS                        1
+
+#define DRIVER_NAME                     "rtdm_cifx"
+#define PERIPHERAL_NAME                 "cifx"
+#define PROVIDER_NAME                   "Hilscher"
+
+/* name of a NXSB-PCA or NXPCA-PCI card */
+#define CIFX_RTDM_PLX_CARD_NAME         "netx_plx"
+/* name of a cifX PCI card              */
+#define CIFX_RTDM_CARD_NAME             "netx"
+/* name of a netPLC PCI card            */
+#define CIFX_RTDM_NETPLC_CARD_NAME      "netplc"
+/* name of a netJACK PCI card           */
+#define CIFX_RTDM_NETJACK_CARD_NAME     "netjack"
+
+/*****************************************************************************/
+
+/* structure */
+
+struct pxa_dev_info {
+	uint32_t __iomem *plx;
+	uint8_t dpm_mode;
+	uint32_t plx_timing;
+};
+
+struct io_mem {
+	uint32_t addr;
+	uint32_t size;
+	int32_t memtype;
+	void __iomem *internal_addr;
+};
+
+struct io_info {
+	struct io_mem mem[MAX_MAPS];
+	int32_t irq;
+	uint8_t irq_enable;
+	uint8_t irq_registered;
+	rtdm_irq_t irq_handle;
+	void *priv;
+};
+
+struct io_map_mem {
+	uint32_t phys_addr;
+	void **virt_addr;
+	uint32_t length;
+};
+
+/*****************************************************************************/
+
+/* Prototypes */
+
+#ifdef IRQ_SUPPORT
+static int cifx_handler(rtdm_irq_t *irq);
+#endif /* IRQ_SUPPORT */
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info);
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info);
+
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags);
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info);
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte);
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte);
+
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static void cifx_pci_remove(struct pci_dev *dev);
+
+/*****************************************************************************/
+
+/* Local variables */
+
+/** Number or cifx found and open */
+static int32_t cifx_num;
+
+/** RTDM Device information structure */
+static const struct rtdm_device __initdata cifx_device_tmpl = {
+	.struct_version = RTDM_DEVICE_STRUCT_VER,
+
+	.device_flags = RTDM_NAMED_DEVICE,
+	.context_size = 0,
+	.device_name = "",
+
+	.open_nrt = cifx_pci_open,
+
+	.ops = {
+		.close_nrt = cifx_pci_close,
+
+		.read_nrt = cifx_pci_read,
+		.write_nrt = cifx_pci_write,
+
+		.ioctl_rt = NULL,
+		.ioctl_nrt = NULL,
+
+		.read_rt = NULL,
+		.write_rt = NULL,
+		},
+
+	.device_class = RTDM_CLASS_EXPERIMENTAL,
+	.device_sub_class = RTDM_SUBCLASS_GENERIC,
+	.profile_version = 1,
+	.driver_name = DRIVER_NAME,
+	.driver_version = RTDM_DRIVER_VER(1, 0, 0),
+	.provider_name = PROVIDER_NAME,
+};
+
+/** Device table */
+static DEFINE_PCI_DEVICE_TABLE(cifx_pci_tbl) = {
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETX,
+		.subvendor = 0,
+		.subdevice = 0,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXSB_PCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_PLX,
+		.device = PCI_DEVICE_ID_PLX_9030,
+		.subvendor = PCI_VENDOR_ID_PLX,
+		.subdevice = PCI_SUBDEVICE_ID_NXPCA,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETPLC,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETPLC_FLASH,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_RAM,
+	},
+	{
+		.vendor = PCI_VENDOR_ID_HILSCHER,
+		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
+		.subvendor = PCI_VENDOR_ID_HILSCHER,
+		.subdevice = PCI_SUBDEVICE_ID_NETJACK_FLASH,
+	},
+	{ 0,}
+};
+
+/** RTDM cifX Driver */
+static struct pci_driver cifx_pci_driver = {
+	.name = "cifx",
+	.id_table = cifx_pci_tbl,
+	.probe = cifx_pci_probe,
+	.remove = cifx_pci_remove,
+};
+
+/*****************************************************************************/
+
+#ifdef IRQ_SUPPORT
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_handler
+ *
+ *   \param  [in]	irq       Resource task pointer
+ *
+ *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
+ *
+ *   \note   cifx interrupt handler
+ */
+/*****************************************************************************/
+static inline int cifx_handler(rtdm_irq_t *irq)
+{
+	struct rtdm_device *info =
+	    (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
+	struct io_info_t *device_data = (struct io_info_t *)info->device_data;
+
+	/* Test if request is for this driver */
+	if ((device_data->priv != NULL)
+	    || (device_data->irq_registered == FALSE)
+	    || (device_data->irq_enable == FALSE)) {
+		/* This is a PLX device and cannot produce an IRQ,
+		   IRQ not registred or not enable (cannot produce an IRQ) */
+		return RTDM_IRQ_NONE;
+	} else {
+		void __iomem *int_enable_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_EN0;
+		void __iomem *int_status_reg =
+		    device_data->mem[DPM_INDEX].internal_addr +
+		    DPM_HOST_INT_STAT0;
+
+		/* Is one of our interrupts enabled and active ? */
+		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg)
+		      & DPM_HOST_INT_MASK))
+			return RTDM_IRQ_NONE;
+
+		/* Disable interrupt */
+		iowrite32(ioread32(int_enable_reg)
+			  & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
+
+		return RTDM_IRQ_HANDLED;
+	}
+}
+
+#endif /* IRQ_SUPPORT */
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_set_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Set plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_timing;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
+	*plx_timing = pxa_info->plx_timing;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_plx_timing
+ *
+ *   \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get plx timing
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	switch (pxa_info->dpm_mode) {
+	case 8:
+		pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
+		break;
+	case 16:
+		pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
+		break;
+	case 32:
+		pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pxa_get_dpm_mode
+ *
+ *	 \param	[in]	info	cifx rtdm device information
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Get dpm mode
+ */
+/*****************************************************************************/
+static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
+{
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)((struct io_info *)info->device_data)->priv;
+	uint32_t __iomem *plx_gpio;
+
+	if (!pxa_info)
+		return -ENODEV;
+
+	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
+
+	if ((*plx_gpio & PLX_GPIO_DATA0_MASK)
+	    && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 8;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && (*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 32;
+	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK)
+		 && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
+		pxa_info->dpm_mode = 16;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_open
+ *
+ *   \param	[in]	context		context
+ *   \param	[in]	user_info	user information
+ *	 \param	[in]	oflags		flags (flag IRQ used)
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note   Open RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_open(struct rtdm_dev_context *context,
+			 rtdm_user_info_t *user_info, int oflags)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	int32_t ret;
+
+	/* Test if (oflags) IRQ are use */
+	if (oflags == TRUE) {
+		if (((struct io_info_t *)info->device_data)->irq_registered
+		    == FALSE) {
+			/* Register IRQ */
+			ret =
+			    rtdm_irq_request(&
+					     (((struct io_info_t *)info->
+					       device_data)->irq_handle),
+					     ((struct io_info_t *)info->
+					      device_data)->irq, cifx_handler,
+					     RTDM_IRQTYPE_SHARED,
+					     info->device_name, (void *)info);
+
+			if (ret != 0) {
+#ifdef DEBUG
+				switch (ret) {
+				case -EINVAL:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: an invalid parameter was passed\n");
+					break;
+				case -EBUSY:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request: the specified IRQ line is already in use\n");
+					break;
+				default:
+					rtdm_printk(
+"cifx rtdm driver error: rtdm_irq_request error\n");
+					break;
+				}
+#endif /* DEBUG */
+
+				return -ENODEV;
+			} else
+				((io_info_t *) info->
+				 device_data)->irq_registered = TRUE;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_close
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *
+ *	\return 0 (OK) or Error
+ *
+ *	\note	Close RTDM cifx pci driver
+ */
+/*****************************************************************************/
+static int cifx_pci_close(struct rtdm_dev_context *context,
+			  rtdm_user_info_t *user_info)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (((struct io_info_t *)info->device_data)->irq_registered == TRUE) {
+		if (((struct io_info_t *)info->device_data)->
+							irq_enable == TRUE) {
+			/* Disable IRQ */
+			if (rtdm_irq_disable
+			    (&
+			     (((struct io_info_t *)info->device_data)->
+			      irq_handle)) != 0) {
+#ifdef DEBUG
+				rtdm_printk(
+			"cifx rtdm driver error : rtdm_irq_disable error\n");
+#endif /* DEBUG */
+
+				return -ENODEV;
+			}
+		}
+
+		/* Unregister IRQ */
+		if (rtdm_irq_free
+		    (&(((struct io_info_t *)info->device_data)->irq_handle)) !=
+		    0) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_irq_free error\n");
+#endif /* DEBUG */
+
+			return -ENODEV;
+		}
+	}
+#endif /* IRQ_SUPPORT */
+
+	return 0;
+}
+
+/*****************************************************************************/
+/*!
+ *  \brief  cifx_pci_read
+ *
+ *	\param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *  \return size read
+ *
+ *  \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_read(struct rtdm_dev_context *context,
+			     rtdm_user_info_t *user_info, void *buf,
+			     size_t nbyte)
+{
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+
+	if (nbyte > sizeof(struct io_info)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+
+	/* Copy data information for userland */
+	if (rtdm_safe_copy_to_user(user_info, buf,
+				   ((struct io_info *)info->device_data),
+				   nbyte)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *	\brief  cifx_pci_write
+ *
+ *  \param	[in]	context		context
+ *	\param	[in]	user_info	user information
+ *	\param	[in]	buf	user	buffer
+ *	\param	[in]	nbyte		number of byte to read
+ *
+ *   \return size read
+ *
+ *   \note   Read
+ */
+/*****************************************************************************/
+static ssize_t cifx_pci_write(struct rtdm_dev_context *context,
+			      rtdm_user_info_t *user_info, const void *buf,
+			      size_t nbyte)
+{
+#ifdef IRQ_SUPPORT
+	struct rtdm_device *info = (struct rtdm_device *)context->device;
+	uint8_t irq_enable;
+#endif /* IRQ_SUPPORT */
+	struct io_map_mem map_mem;
+	int ret;
+
+	if (nbyte > sizeof(struct io_map_mem)) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : data user size too big\n");
+#endif /* DEBUG */
+
+		return 0;
+	}
+#ifdef IRQ_SUPPORT
+	if (nbyte == sizeof(uint8_t)) {
+		/* Copy data for Kernel */
+		if (rtdm_safe_copy_from_user
+		    (user_info, &irq_enable, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (((((struct io_info *)info->device_data)->
+			     irq_enable) != irq_enable)
+			&& (((struct io_info *)info->device_data)->
+				    irq_registered == TRUE)) {
+					if (irq_enable == TRUE) {
+						/* Enable IRQ */
+						rtdm_irq_enable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					} else {
+						/* Disable IRQ */
+						rtdm_irq_disable
+						    (&
+						     (((struct io_info *)info->
+						       device_data)->
+						      irq_handle);
+					}
+
+					((struct io_info *)info->device_data)->
+					    irq_enable = irq_enable;
+				}
+			}
+		}
+	} else if (nbyte == sizeof(struct io_map_mem)) {
+#else /* IRQ_SUPPORT */
+	if (nbyte == sizeof(struct io_map_mem)) {
+#endif /* IRQ_SUPPORT */
+		/* Copy data information for Kernel */
+		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte)) {
+			nbyte = 0;
+
+#ifdef DEBUG
+			rtdm_printk(
+		"cifx rtdm driver error : can't copy data from driver\n");
+#endif /* DEBUG */
+		} else {
+			if (*map_mem.virt_addr == NULL) {
+				/* Map physical on virtual memory */
+				ret = rtdm_iomap_to_user(user_info,
+							 (phys_addr_t) map_mem.
+							 phys_addr,
+							 (size_t) map_mem.
+							 length,
+							 (PROT_READ |
+							  PROT_WRITE),
+							 map_mem.virt_addr,
+							 NULL, NULL);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+"cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");
+						break;
+					case -ENOMEM:
+						rtdm_printk(
+"cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");
+						break;
+					case -EAGAIN:
+						rtdm_printk(
+"cifx rtdm driver error : too much memory has been already locked by the user process\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			} else {
+				/* Unap virtual memory */
+				ret = rtdm_munmap(user_info, *map_mem.virt_addr,
+						  (size_t) map_mem.length);
+
+				if (ret != 0) {
+					nbyte = 0;
+
+#ifdef DEBUG
+					switch (ret) {
+					case -EINVAL:
+						rtdm_printk(
+		"cifx rtdm driver error : an invalid address or size was passed\n");
+						break;
+					case -EPERM:
+						rtdm_printk(
+	"cifx rtdm driver error : an illegal invocation environment is detected\n");
+						break;
+					default:
+						rtdm_printk(
+			"cifx rtdm driver error : rtdm_safe_copy_from_user error\n");
+						break;
+					}
+#endif /* DEBUG */
+				}
+			}
+		}
+	} else {
+		/* Error nothing to do */
+		nbyte = 0;
+	}
+
+	return nbyte;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_probe
+ *
+ *   \param  [in]   dev
+ *   \param  [in]   id
+ *
+ *   \return 0 (OK) or Error
+ *
+ *   \note  Open the device.
+ *			This function is called when the device shall be opened.
+ */
+/*****************************************************************************/
+static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct rtdm_device *info = NULL;
+	struct io_info_t *device_data = NULL;
+	int32_t bar;
+	int32_t ret;
+
+	/* Allocate device driver structure */
+	info = rtdm_malloc(sizeof(struct rtdm_device));
+
+	if (info == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		return -ENOMEM;
+	}
+
+	ret = pci_enable_device(dev);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_enable_device error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_free;
+	}
+
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret != 0) {
+#ifdef DEBUG
+		rtdm_printk(
+		"cifx rtdm driver error : pci_request_regions error : %i\n",
+		ret);
+#endif /* DEBUG */
+
+		goto out_disable;
+	}
+
+	/* Initialize structure with default values */
+	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
+
+	info->device_id = id->device;
+	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i",
+		 cifx_num);
+	info->proc_name = info->device_name;
+
+	switch (id->device) {
+	case PCI_DEVICE_ID_HILSCHER_NETX:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETPLC:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
+		break;
+	case PCI_DEVICE_ID_HILSCHER_NETJACK:
+		bar = DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
+		break;
+	default:
+		bar = PLX_DPM_BAR;
+		info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
+		break;
+	}
+
+	info->device_data = NULL;
+
+	/* Allocate specific data strcuture for device */
+	device_data = rtdm_malloc(sizeof(struct io_info));
+
+	if (device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	memset(device_data, 0, sizeof(struct io_info));
+
+	/* BAR 0 or 2 points to the card's dual port memory */
+	((struct io_info *)device_data)->mem[DPM_INDEX].addr =
+	    pci_resource_start(dev, bar);
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].addr == 0) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : pci_resource_start error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr =
+	    ioremap_nocache(pci_resource_start(dev, bar),
+			    pci_resource_len(dev, bar));
+
+	if (((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr
+									== 0) {
+#ifdef DEBUG
+		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+		goto out_release;
+	}
+
+	dev_info(&dev->dev, "DPM at %08lX\n",
+		 (long unsigned int)((struct io_info *)device_data)->
+		 mem[DPM_INDEX].addr);
+	((struct io_info *)device_data)->mem[DPM_INDEX].size =
+	    pci_resource_len(dev, bar);
+	((struct io_info *)device_data)->mem[DPM_INDEX].memtype = MEM_PHYS;
+
+	/* map extended mem (BAR 1 points to the extended memory) */
+	((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr =
+	    pci_resource_start(dev, EXT_MEM_BAR);
+
+	/* extended memory is optional, so don't care if it is not present */
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].addr != 0) {
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr =
+		    ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR),
+				    pci_resource_len(dev, EXT_MEM_BAR));
+
+		if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+		    internal_addr == 0) {
+#ifdef DEBUG
+			rtdm_printk(
+			"cifx rtdm driver error : ioremap_nocache error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		dev_info(&dev->dev, "extended memory at %08lX\n",
+			 (long unsigned int)((struct io_info *)device_data)->
+			 mem[EXT_MEM_INDEX].addr);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].size =
+		    pci_resource_len(dev, EXT_MEM_BAR);
+		((struct io_info *)device_data)->mem[EXT_MEM_INDEX].memtype =
+		    MEM_PHYS;
+	}
+
+	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+	    || (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) {
+		/* make sure all interrupts are disabled */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+		((struct io_info *)device_data)->priv = NULL;
+	} else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) {
+		/* map PLX registers */
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_unmap;
+		}
+
+		((struct io_info *)device_data)->priv = pxa_info;
+
+		/* set PXA PLX Timings */
+		pxa_info->plx =
+		    ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR),
+				    pci_resource_len(dev, PXA_PLX_BAR));
+
+		if (!pxa_info->plx)
+			goto out_unmap;
+		if (cifx_pxa_get_dpm_mode(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_get_plx_timing(info))
+			goto out_unmap_plx;
+		if (cifx_pxa_set_plx_timing(info))
+			goto out_unmap_plx;
+	} else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)
+		    rtdm_malloc(sizeof(struct pxa_dev_info));
+
+		if (pxa_info == NULL) {
+#ifdef DEBUG
+			rtdm_printk
+			    ("cifx rtdm driver error : rtdm_malloc error\n");
+#endif /* DEBUG */
+
+			goto out_free_pxa;
+		}
+
+		((struct pxa_dev_info *)pxa_info)->plx = NULL;
+		((struct pxa_dev_info *)pxa_info)->plx_timing = 0;
+		((struct pxa_dev_info *)pxa_info)->dpm_mode = 0;
+		((struct io_info *)device_data)->priv = pxa_info;
+	}
+
+	/* Initialize irq data */
+	((struct io_info *)device_data)->irq = dev->irq;
+	((struct io_info *)device_data)->irq_enable = FALSE;
+	((struct io_info *)device_data)->irq_registered = FALSE;
+
+	info->device_data = device_data;
+
+	/* Register RTDM device driver */
+	ret = rtdm_dev_register(info);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -EINVAL:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
+			break;
+		case -ENOMEM:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
+			break;
+		case -EEXIST:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_register error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
+			goto out_unmap;
+		else
+			goto out_unmap_plx;
+	}
+
+	pci_set_drvdata(dev, info);
+
+	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
+		dev_info(&dev->dev, "registered CifX card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
+		dev_info(&dev->dev, "registered netPLC card\n");
+	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
+		dev_info(&dev->dev, "registered netJACK card\n");
+	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
+		dev_info(&dev->dev, "registered NXSB-PCA adapter card\n");
+	else {
+		struct pxa_dev_info *pxa_info =
+		    (struct pxa_dev_info *)((struct io_info *)info->
+					    device_data)->priv;
+		dev_info(&dev->dev,
+			 "registered NXPCA-PCI adapter card in %d bit mode\n",
+			 ((struct pxa_dev_info *)pxa_info)->dpm_mode);
+	}
+
+	cifx_num++;
+
+	return 0;
+
+ out_unmap_plx:
+	iounmap(((struct pxa_dev_info *)(((struct io_info *)info->device_data)->
+					 priv))->plx);
+
+ out_free_pxa:
+	rtdm_free(((struct io_info *)info->device_data)->priv);
+
+ out_unmap:
+	iounmap(((struct io_info *)info->device_data)->mem[DPM_INDEX].
+		internal_addr);
+	if (((struct io_info *)info->device_data)->mem[EXT_MEM_INDEX].
+	    internal_addr != 0)
+		iounmap(((struct io_info *)info->device_data)->
+			mem[EXT_MEM_INDEX].internal_addr);
+
+ out_release:
+	pci_release_regions(dev);
+
+ out_disable:
+	pci_disable_device(dev);
+
+ out_free:
+	if (info->device_data != NULL)
+		rtdm_free(info->device_data);
+
+	rtdm_free(info);
+
+	return -ENODEV;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_remove
+ *
+ *   \param [in] dev
+ *
+ *   \return None
+ *
+ *   \note   Close the device.
+ *   This function is called when the device shall be closed.
+ */
+/*****************************************************************************/
+static void cifx_pci_remove(struct pci_dev *dev)
+{
+	struct rtdm_device *info = pci_get_drvdata(dev);
+	struct io_info *device_data = (struct io_info *)info->device_data;
+	struct pxa_dev_info *pxa_info =
+	    (struct pxa_dev_info *)device_data->priv;
+	int32_t ret;
+
+	if (info->device_data == NULL) {
+#ifdef DEBUG
+		rtdm_printk
+		    ("cifx rtdm driver error : device_data NULL pointer\n");
+#endif /* DEBUG */
+		return;
+	}
+
+	if (pxa_info != NULL) {
+		/* Disable all interrupts */
+		iowrite32(0,
+			  ((struct io_info *)device_data)->mem[DPM_INDEX].
+			  internal_addr + DPM_HOST_INT_EN0);
+
+		if (pxa_info->plx != NULL)
+			iounmap((void *)pxa_info->plx);
+
+		rtdm_free((void *)pxa_info);
+	}
+
+	/* Unregister RTDM device driver */
+	ret = rtdm_dev_unregister(info, 1000);
+	if (ret != 0) {
+#ifdef DEBUG
+		switch (ret) {
+		case -ENODEV:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
+			break;
+		case -EAGAIN:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
+			break;
+		default:
+			rtdm_printk(
+"cifx rtdm driver error : rtdm_dev_unregister error\n");
+			break;
+		}
+#endif /* DEBUG */
+
+		return;
+	}
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+
+	iounmap(((struct io_info *)device_data)->mem[DPM_INDEX].internal_addr);
+	if (((struct io_info *)device_data)->mem[EXT_MEM_INDEX].internal_addr !=
+	    0)
+		iounmap(((struct io_info *)device_data)->mem[EXT_MEM_INDEX].
+			internal_addr);
+
+	/* Release structure memory allocation */
+	rtdm_free(info->device_data);
+	rtdm_free(info);
+
+	if (cifx_num > 0)
+		cifx_num--;
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_init
+ *
+ *   \return None
+ *
+ *   \note   It simply registers the RTDM device.
+ *   This function is called when the module is loaded.
+ */
+/*****************************************************************************/
+static int __init cifx_pci_init(void)
+{
+	cifx_num = 0;
+
+	return pci_register_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*!
+ *   \brief  cifx_pci_exit
+ *
+ *   \return None
+ *
+ *   \note  It unregister the RTDM device.
+ *   This function is called when the module is unloaded.
+ */
+/*****************************************************************************/
+static void __exit cifx_pci_exit(void)
+{
+	pci_unregister_driver(&cifx_pci_driver);
+}
+
+/*****************************************************************************/
+/*! \}     cifx_pci_Core                                                     */
+/*****************************************************************************/
+
+module_init(cifx_pci_init);
+module_exit(cifx_pci_exit);
+
+/* End of file : cifx_pci.c */

^ permalink raw reply related	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-01 13:56             ` Jerome Poncin
  2013-03-01 17:02               ` Jan Kiszka
@ 2013-03-01 20:06               ` Gilles Chanteperdrix
  2013-03-04  9:13               ` Jerome Poncin
  2 siblings, 0 replies; 57+ messages in thread
From: Gilles Chanteperdrix @ 2013-03-01 20:06 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 03/01/2013 02:56 PM, Jerome Poncin wrote:

> Hello,
> 
> I finished to reformat my driver according to kernel coding style.
> 
> I'm compiling no version to test it ;-) !
> 
> I'm ready to do a patch against Xenomai git head. The patch will add the 
> driver source
> code under ksrc/drivers/cifx and change the Makefiles and Kconfigs as 
> required.
> 
> I did this command to get Xenomai git head :
> 
> git clone git://git.xenomai.org/xenomai-head.git xenomai-head


Please do not use xenomai-head. Use xenomai-2.6 if you are patching the
2.6 branch, or xenomai-forge if you are patching the -forge branch.

> 
> but connexion is refused. What must I do to clone Xenomai git head and 
> do my patch ?


This should be fixed now.

Please stop top-posting.


-- 
                                                                Gilles.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-03-01 13:56             ` Jerome Poncin
@ 2013-03-01 17:02               ` Jan Kiszka
  2013-03-01 20:06               ` Gilles Chanteperdrix
  2013-03-04  9:13               ` Jerome Poncin
  2 siblings, 0 replies; 57+ messages in thread
From: Jan Kiszka @ 2013-03-01 17:02 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-03-01 14:56, Jerome Poncin wrote:
> Hello,
> 
> I finished to reformat my driver according to kernel coding style.
> 
> I'm compiling no version to test it ;-) !
> 
> I'm ready to do a patch against Xenomai git head. The patch will add the
> driver source
> code under ksrc/drivers/cifx and change the Makefiles and Kconfigs as
> required.
> 
> I did this command to get Xenomai git head :
> 
> git clone git://git.xenomai.org/xenomai-head.git xenomai-head
> 
> but connexion is refused. What must I do to clone Xenomai git head and
> do my patch ?

Try via http://, git is apparently broken ATM.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-28 12:08           ` Jerome Poncin
@ 2013-03-01 13:56             ` Jerome Poncin
  2013-03-01 17:02               ` Jan Kiszka
                                 ` (2 more replies)
  0 siblings, 3 replies; 57+ messages in thread
From: Jerome Poncin @ 2013-03-01 13:56 UTC (permalink / raw)
  To: xenomai

Hello,

I finished to reformat my driver according to kernel coding style.

I'm compiling no version to test it ;-) !

I'm ready to do a patch against Xenomai git head. The patch will add the 
driver source
code under ksrc/drivers/cifx and change the Makefiles and Kconfigs as 
required.

I did this command to get Xenomai git head :

git clone git://git.xenomai.org/xenomai-head.git xenomai-head

but connexion is refused. What must I do to clone Xenomai git head and 
do my patch ?

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





Le 28/02/2013 13:08, Jerome Poncin a écrit :
> Hello,
>
> "And it is impossible to disable/unload drivers that conflict with 
> that IRQ? "
> => I disable a maximum but other driver on the same IRQ are SATA, USB, 
> etc...
>
> Nor do you have a modern system at hand? Those tend to use more MSI
> than legacy IRQs for the on-board devices (or did you disable
> CONFIG_PCI_MSI?) and provide more legacy IRQ lines (8 instead of 4).
> => OK I will see and try.
>
> Then remove IRQ support. If it's untested, it's worthless.
> => You are right, but I prefer put a compilation condition with #ifdef 
> for the future.
>
> First of all, reformat your driver according to kernel coding style
> (check with linux/scripts/checkpatch.pl). Then provide it in form of a
> patch against Xenomai git head. The patch should add the driver source
> code under ksrc/drivers/cifx (or so) and change the Makefiles and
> Kconfigs as required. Make sure the result is properly built along a
> normal Xenomai kernel build. We can then perform a code review and merge
> the code if it is fine.
> => OK thank you for all these information, I will try.
>
> Thank you for your help,
>
> Hilscher France
> 12, rue du 35ème Régiment d'Aviation
> Miniparc du Chêne
> 69500 BRON
> France
> Tél. : +33 (0) 4 72 37 98 40
> Fax  : +33 (0) 4 78 26 83 27
> http://www.hilscher.fr
> HILSCHER FRANCE     Jérôme Poncin
> jponcin@hilscher.com
> Ingénieur Développement Logiciel
> Tél. : +33 (0) 4 72 37 98 44
>
>
>
>
>
> Le 28/02/2013 12:31, Jan Kiszka a écrit :
>> On 2013-02-28 09:15, Jerome Poncin wrote:
>>> Hello,
>>>
>>> I tried to put one IRQ only for my cifX board without success. I have
>>> not enough IRQ on my PC and the most of them are shared.
>>> I modified Linux kernel to limit driver, I checked that all was correct
>>> in BIOS etc. I had the same problem for a driver on another system.
>> And it is impossible to disable/unload drivers that conflict with that
>> IRQ? Nor do you have a modern system at hand? Those tend to use more MSI
>> than legacy IRQs for the on-board devices (or did you disable
>> CONFIG_PCI_MSI?) and provide more legacy IRQ lines (8 instead of 4).
>>
>>> It's not really important for the moment because the normal use of the
>>> driver is polling.
>> Then remove IRQ support. If it's untested, it's worthless.
>>
>>> Therefore for me, the part of Xenomai kernel driver for CifX is 
>>> finished
>>> and can be integrated to next release of Xenomai.
>>> I don't know how to integrate my source to Xenomai kernel, therefore I
>>> give you my last release of Xenomai kernel driver for cifX with the
>>> makefile for compilation option.
>> First of all, reformat your driver according to kernel coding style
>> (check with linux/scripts/checkpatch.pl). Then provide it in form of a
>> patch against Xenomai git head. The patch should add the driver source
>> code under ksrc/drivers/cifx (or so) and change the Makefiles and
>> Kconfigs as required. Make sure the result is properly built along a
>> normal Xenomai kernel build. We can then perform a code review and merge
>> the code if it is fine.
>>
>> Jan
>>
>
> _______________________________________________
> Xenomai mailing list
> Xenomai@xenomai.org
> http://www.xenomai.org/mailman/listinfo/xenomai
>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-28 11:31         ` Jan Kiszka
@ 2013-02-28 12:08           ` Jerome Poncin
  2013-03-01 13:56             ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-02-28 12:08 UTC (permalink / raw)
  Cc: xenomai

Hello,

"And it is impossible to disable/unload drivers that conflict with that 
IRQ? "
=> I disable a maximum but other driver on the same IRQ are SATA, USB, 
etc...

Nor do you have a modern system at hand? Those tend to use more MSI
than legacy IRQs for the on-board devices (or did you disable
CONFIG_PCI_MSI?) and provide more legacy IRQ lines (8 instead of 4).
=> OK I will see and try.

Then remove IRQ support. If it's untested, it's worthless.
=> You are right, but I prefer put a compilation condition with #ifdef for the future.

First of all, reformat your driver according to kernel coding style
(check with linux/scripts/checkpatch.pl). Then provide it in form of a
patch against Xenomai git head. The patch should add the driver source
code under ksrc/drivers/cifx (or so) and change the Makefiles and
Kconfigs as required. Make sure the result is properly built along a
normal Xenomai kernel build. We can then perform a code review and merge
the code if it is fine.
=> OK thank you for all these information, I will try.

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





Le 28/02/2013 12:31, Jan Kiszka a écrit :
> On 2013-02-28 09:15, Jerome Poncin wrote:
>> Hello,
>>
>> I tried to put one IRQ only for my cifX board without success. I have
>> not enough IRQ on my PC and the most of them are shared.
>> I modified Linux kernel to limit driver, I checked that all was correct
>> in BIOS etc. I had the same problem for a driver on another system.
> And it is impossible to disable/unload drivers that conflict with that
> IRQ? Nor do you have a modern system at hand? Those tend to use more MSI
> than legacy IRQs for the on-board devices (or did you disable
> CONFIG_PCI_MSI?) and provide more legacy IRQ lines (8 instead of 4).
>
>> It's not really important for the moment because the normal use of the
>> driver is polling.
> Then remove IRQ support. If it's untested, it's worthless.
>
>> Therefore for me, the part of Xenomai kernel driver for CifX is finished
>> and can be integrated to next release of Xenomai.
>> I don't know how to integrate my source to Xenomai kernel, therefore I
>> give you my last release of Xenomai kernel driver for cifX with the
>> makefile for compilation option.
> First of all, reformat your driver according to kernel coding style
> (check with linux/scripts/checkpatch.pl). Then provide it in form of a
> patch against Xenomai git head. The patch should add the driver source
> code under ksrc/drivers/cifx (or so) and change the Makefiles and
> Kconfigs as required. Make sure the result is properly built along a
> normal Xenomai kernel build. We can then perform a code review and merge
> the code if it is fine.
>
> Jan
>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-28  8:15       ` Jerome Poncin
@ 2013-02-28 11:31         ` Jan Kiszka
  2013-02-28 12:08           ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-28 11:31 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-02-28 09:15, Jerome Poncin wrote:
> Hello,
> 
> I tried to put one IRQ only for my cifX board without success. I have
> not enough IRQ on my PC and the most of them are shared.
> I modified Linux kernel to limit driver, I checked that all was correct
> in BIOS etc. I had the same problem for a driver on another system.

And it is impossible to disable/unload drivers that conflict with that
IRQ? Nor do you have a modern system at hand? Those tend to use more MSI
than legacy IRQs for the on-board devices (or did you disable
CONFIG_PCI_MSI?) and provide more legacy IRQ lines (8 instead of 4).

> It's not really important for the moment because the normal use of the
> driver is polling.

Then remove IRQ support. If it's untested, it's worthless.

> Therefore for me, the part of Xenomai kernel driver for CifX is finished
> and can be integrated to next release of Xenomai.
> I don't know how to integrate my source to Xenomai kernel, therefore I
> give you my last release of Xenomai kernel driver for cifX with the
> makefile for compilation option.

First of all, reformat your driver according to kernel coding style
(check with linux/scripts/checkpatch.pl). Then provide it in form of a
patch against Xenomai git head. The patch should add the driver source
code under ksrc/drivers/cifx (or so) and change the Makefiles and
Kconfigs as required. Make sure the result is properly built along a
normal Xenomai kernel build. We can then perform a code review and merge
the code if it is fine.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-26 14:28     ` Jan Kiszka
@ 2013-02-28  8:15       ` Jerome Poncin
  2013-02-28 11:31         ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-02-28  8:15 UTC (permalink / raw)
  To: xenomai

Hello,

I tried to put one IRQ only for my cifX board without success. I have 
not enough IRQ on my PC and the most of them are shared.
I modified Linux kernel to limit driver, I checked that all was correct 
in BIOS etc. I had the same problem for a driver on another system.
It's not really important for the moment because the normal use of the 
driver is polling.
Therefore for me, the part of Xenomai kernel driver for CifX is finished 
and can be integrated to next release of Xenomai.
I don't know how to integrate my source to Xenomai kernel, therefore I 
give you my last release of Xenomai kernel driver for cifX with the 
makefile for compilation option.

Thank you for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44



Le 26/02/2013 15:28, Jan Kiszka a écrit :
> On 2013-02-26 15:25, Jerome Poncin wrote:
>> Hello Jan,
>>
>> Thank you for your answer. I checked /proc/interrupts and lspci -v, and I saw that the IRQ is shared.
>>
>> "If yes, resolve that conflict."
>>
>> => What must I do ? I'm not sure to have understood ?
> See
> http://xenomai.org/index.php/FAQs#What_can_I_do_if_Xenomai_and_Linux_devices_share_the_same_IRQ.3F
>
>>
>> /*****************************************************************************/
>> /*!
>> *   \brief  cifx_handler
>> *
>> *   \param  [in]    irq      Resource task pointer
>> *
>> *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
>> *
>> *   \note   cifx interrupt handler
>> */
>> /*****************************************************************************/
>> static /*inline*/ int cifx_handler(rtdm_irq_t *irq)
>> {
>>      struct rtdm_device    *info             = (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
>>      io_info_t             *device_data     = (io_info_t *) info->device_data;
>>
>>      if ((device_data->priv != NULL) || (device_data->irq_registered == FALSE) || (device_data->irq_enable == FALSE))
>>      {
>>          /* This is a PLX device and cannot produce an IRQ */
>>          return RTDM_IRQ_NONE;
>>      }
>>      else
>>      {
>>          void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
>>          void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
>>
>>          /* Is one of our interrupts enabled and active ? */
>>          if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
>>              return RTDM_IRQ_NONE;
>>
>>          /* Disable interrupt */
>>          iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
>>
>>          return RTDM_IRQ_HANDLED;
>>      }
>> }
>>
>> If IRQ is not mine, I return RTDM_IRQ_NONE, it's not correct ?
> It is. The problem is the sharing between RT and Linux. That cannot work.
>
> Jan
>

-------------- next part --------------
/***************************************************************************
 *   Copyright (C) 2013 		                                   		   *
 *   Hilscher France (JP)                                                  *
 *   http://www.hilscher.fr/ 						   					   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

/***************************************************************************/

/* Includes */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>

#include <sys/mman.h>

#include <rtdm/rtdm_driver.h>

/***************************************************************************/

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

/***************************************************************************/
/*!
*   \addtogroup cifx_pci_Core
*   @{
*/
/***************************************************************************/

/* #define */

#ifndef TRUE
#define TRUE						1		
#endif /* TRUE */

#ifndef FALSE
#define FALSE						0		
#endif /* TRUE */

#ifndef PCI_VENDOR_ID_HILSCHER
	#define PCI_VENDOR_ID_HILSCHER   			0x15CF
#endif /* PCI_VENDOR_ID_HILSCHER */

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
	#define PCI_DEVICE_ID_HILSCHER_NETX  		0x0000
#endif /* PCI_DEVICE_ID_HILSCHER_NETX */

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
	#define PCI_DEVICE_ID_HILSCHER_NETPLC  		0x0010
#endif /* PCI_DEVICE_ID_HILSCHER_NETPLC */

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
	#define PCI_DEVICE_ID_HILSCHER_NETJACK  	0x0020
#endif /* PCI_DEVICE_ID_HILSCHER_NETJACK */

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
	#define PCI_SUBDEVICE_ID_NXSB_PCA  			0x3235
#endif /* PCI_SUBDEVICE_ID_NXSB_PCA */

#ifndef PCI_SUBDEVICE_ID_NXPCA
	#define PCI_SUBDEVICE_ID_NXPCA   			0x3335
#endif /* PCI_SUBDEVICE_ID_NXPCA */

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
	#define PCI_SUBDEVICE_ID_NETPLC_RAM  		0x0000
#endif /* PCI_SUBDEVICE_ID_NETPLC_RAM */

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
	#define PCI_SUBDEVICE_ID_NETPLC_FLASH   	0x0001
#endif /* PCI_SUBDEVICE_ID_NETPLC_FLASH */

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
	#define PCI_SUBDEVICE_ID_NETJACK_RAM   		0x0000
#endif /* PCI_SUBDEVICE_ID_NETJACK_RAM */

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
	#define PCI_SUBDEVICE_ID_NETJACK_FLASH   	0x0001
#endif /* PCI_SUBDEVICE_ID_NETJACK_FLASH */

#define DPM_HOST_INT_EN0						0xfff0
#define DPM_HOST_INT_STAT0						0xffe0
#define PLX_GPIO_OFFSET        					0x15
#define PLX_TIMING_OFFSET       				0x0a

#define DPM_HOST_INT_MASK						0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN					0x80000000
#define PLX_GPIO_DATA0_MASK     				0x00000004
#define PLX_GPIO_DATA1_MASK     				0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  				0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 				0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 				0x40824122

/* Number of bar */
#define DPM_BAR    								0			/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 							1 			/* points to the optional extended memory     */
#define PLX_DPM_BAR 							2 			/* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 							0 			/* timing config register                     */

/* Index of io_info structure's memory array */
#define DPM_INDEX     							0 			/* first mapping describes DPM              */
#define EXT_MEM_INDEX 							1			/* second mapping describes extended memory */

#define MAX_MAPS    							2

#define MEM_PHYS    							1

#define DRIVER_NAME								"rtdm_cifx"
#define PERIPHERAL_NAME							"cifx"
#define PROVIDER_NAME							"Hilscher"

#define CIFX_RTDM_PLX_CARD_NAME     			"netx_plx"  /* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME         			"netx"      /* name of a cifX PCI card              */
#define CIFX_RTDM_NETPLC_CARD_NAME  			"netplc"    /* name of a netPLC PCI card            */
#define CIFX_RTDM_NETJACK_CARD_NAME 			"netjack"   /* name of a netJACK PCI card           */

/***************************************************************************/

typedef struct {
	uint32_t __iomem 	*plx;
	uint8_t 			dpm_mode;
	uint32_t  			plx_timing;
} pxa_dev_info;

typedef struct {
	uint32_t			addr;
	uint32_t 			size;
	int32_t 			memtype;
	void __iomem 		*internal_addr;
} io_mem;  

typedef struct {
	io_mem				mem[MAX_MAPS];
	int32_t				irq;
	uint8_t 			irq_enable;
	uint8_t 			irq_registered;
	rtdm_irq_t  		irq_handle;
	void				*priv;
} io_info_t;

typedef struct {
	uint32_t			phys_addr;
	void **				virt_addr;
	uint32_t			length;
} io_map_mem;

/***************************************************************************/

/* Prototypes */

static int 		cifx_handler(rtdm_irq_t *irq);
static int 		cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int 		cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int 		cifx_pxa_get_dpm_mode(struct rtdm_device *info);

static int 		cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags);
static int 		cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info);
static ssize_t  cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte);
static ssize_t  cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte);

static int 		cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void 	cifx_pci_remove(struct pci_dev *dev);

/***************************************************************************/

/* Local variables */

/** Number or cifx found and open */
static 	int32_t 	cifx_num	=	0;

/** RTDM Device information structure */
static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version		= RTDM_DEVICE_STRUCT_VER,
	
	.device_flags		= RTDM_NAMED_DEVICE,
	.context_size   	= 0,
	.device_name		= "",

	.open_nrt		= cifx_pci_open,

	.ops = {
		.close_nrt	= cifx_pci_close,

		.read_nrt   = cifx_pci_read,
		.write_nrt  = cifx_pci_write,
		
		.ioctl_rt	= NULL,
		.ioctl_nrt	= NULL,

		.read_rt	= NULL,
		.write_rt	= NULL,
	},

	.device_class		= RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class	= RTDM_SUBCLASS_GENERIC,
	.profile_version	= 1,
	.driver_name		= DRIVER_NAME,
	.driver_version		= RTDM_DRIVER_VER(1, 0, 0),
	.provider_name		= PROVIDER_NAME,
};

/** Device table */
static struct pci_device_id cifx_pci_tbl[] = {
	{
		.vendor =		PCI_VENDOR_ID_HILSCHER,
		.device =		PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =		PCI_VENDOR_ID_PLX,
		.device =		PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =		PCI_VENDOR_ID_PLX,
		.device =		PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =		PCI_VENDOR_ID_HILSCHER,
		.device =		PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =		PCI_VENDOR_ID_HILSCHER,
		.device =		PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
		.vendor = 		PCI_VENDOR_ID_HILSCHER,
		.device = 		PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  	PCI_VENDOR_ID_HILSCHER,
		.subdevice =  	PCI_SUBDEVICE_ID_NETJACK_RAM,
	},
	{
		.vendor = 		PCI_VENDOR_ID_HILSCHER,
		.device = 		PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  	PCI_VENDOR_ID_HILSCHER,
		.subdevice =  	PCI_SUBDEVICE_ID_NETJACK_FLASH,
	},
	{ 0, }
};

/** RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name		= "cifx",
	.id_table	= cifx_pci_tbl,
	.probe		= cifx_pci_probe,
	.remove		= cifx_pci_remove,
};

/***************************************************************************/

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]	irq  	Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static inline int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device	*info 			= (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
	io_info_t 			*device_data 	= (io_info_t *) info->device_data;
	
	/* Test if request is for this driver */
	if ((device_data->priv != NULL) || (device_data->irq_registered == FALSE) || (device_data->irq_enable == FALSE))
	{
		/* This is a PLX device and cannot produce an IRQ, IRQ not registred or not enable (cannot produce an IRQ) */
		return RTDM_IRQ_NONE;
	} 
	else
	{	
		void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
			return RTDM_IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_set_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info 	 *pxa_info 	= (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem *plx_timing;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	
	if (!pxa_info)
		return -ENODEV;
		
	switch (pxa_info->dpm_mode) 
	{
		case 8:
			pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
			break;
		case 16:
			pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
			break;
		case 32:
			pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
			break;
		default:
			return -EINVAL;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_dpm_mode
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
	pxa_dev_info 		*pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem 	*plx_gpio;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
		
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_open
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	oflags		flags (flag IRQ used)
*
*   \return 0 (OK) or Error
*
*   \note   Open RTDM cifx pci driver
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	int32_t					ret;

	/* Test if (oflags) IRQ are use */
	if (oflags == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_registered == FALSE)
		{	
			/* Register IRQ */
			if ((ret = rtdm_irq_request(&(((io_info_t *)info->device_data)->irq_handle), ((io_info_t *)info->device_data)->irq, cifx_handler, RTDM_IRQTYPE_SHARED, info->device_name, (void *)info)) != 0)
			{
#ifdef DEBUG
				switch (ret)
				{
					case -EINVAL :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an invalid parameter was passed\n");
						break;
				
					case -EBUSY :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the specified IRQ line is already in use\n");
						break;
		
					default :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error\n");
						break;
				}				
#endif /* DEBUG */

				return -ENODEV;
			}
			else
			{
				((io_info_t *)info->device_data)->irq_registered = TRUE;
			}
		}
	}

	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_close
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*
*   \return 0 (OK) or Error
*
*   \note   Close RTDM cifx pci driver
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
			
	if (((io_info_t *)info->device_data)->irq_registered == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_enable == TRUE)
		{
			/* Disable IRQ */
			if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
			{
#ifdef DEBUG
				rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
		
				return -ENODEV;
			}
		}

		/* Unregister IRQ */
		if (rtdm_irq_free(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
		{
#ifdef DEBUG
				rtdm_printk("cifx rtdm driver error : rtdm_irq_free error\n");				
#endif /* DEBUG */
		
				return -ENODEV;	
		}
	}

	return 0;
}
	
/*****************************************************************************/
/*!
*   \brief  cifx_pci_read
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	
	if (nbyte > sizeof(io_info_t))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}
	
	/* Copy data information for userland */
	if (rtdm_safe_copy_to_user(user_info, buf, ((io_info_t *)info->device_data), nbyte))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
	}

	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_write
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte)
{
	struct rtdm_device 	*info = (struct rtdm_device *)context->device;
	uint8_t				irq_enable;
	io_map_mem			map_mem;
	int					ret;
	
	if (nbyte > sizeof(io_map_mem))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}

	if (nbyte == sizeof(uint8_t))
	{
		/* Copy data for Kernel */
		if (rtdm_safe_copy_from_user(user_info, &irq_enable, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if ((((io_info_t *)info->device_data)->irq_enable) != irq_enable)
			{
				if (((io_info_t *)info->device_data)->irq_registered == TRUE)
				{
					if (irq_enable == TRUE)
					{
						/* Enable IRQ */
						if (rtdm_irq_enable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_enable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}
					else
					{
						/* Disable IRQ */
						if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}				
				
					((io_info_t *)info->device_data)->irq_enable = irq_enable;
				}
				else
				{
#ifdef DEBUG
					rtdm_printk("cifx rtdm driver error : try to enable or diable IRQ but not registered\n");				
#endif /* DEBUG */
				}
			}
		}
	}
	else if (nbyte == sizeof(io_map_mem))
	{
		/* Copy data information for Kernel */
		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if (*map_mem.virt_addr == NULL)
			{
				/* Map physical on virtual memory */
				ret = rtdm_iomap_to_user(user_info, (phys_addr_t)map_mem.phys_addr, (size_t)map_mem.length, (PROT_READ | PROT_WRITE), map_mem.virt_addr, NULL, NULL);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG					
					switch (ret)
					{
						case -EINVAL :				

								rtdm_printk("cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");				

							break;
							
						case -ENOMEM :				

								rtdm_printk("cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");				

							break;
							
						case -EAGAIN:		

								rtdm_printk("cifx rtdm driver error : too much memory has been already locked by the user process\n");				
		
							break;
							
						case -EPERM :	

								rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");				
	
							break;
							
						default :

								rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */	
				}
			}	
			else
			{
				/* Unap virtual memory */
				ret = rtdm_munmap(user_info, *map_mem.virt_addr, (size_t)map_mem.length);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG				
					switch (ret)
					{
						case -EINVAL :
					
							rtdm_printk("cifx rtdm driver error : an invalid address or size was passed\n");				
					
							break;
				
						case -EPERM :
					
							rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");	
					
							break;			
				
						default :
					
							rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */
				}
			}
		}	
	}
	else
	{
		/* Error nothing to do */
		nbyte = 0;
	}
	
	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_probe
*
*   \param  [in]	dev  		
*	\param	[in]	id			
*
*   \return 0 (OK) or Error
*
*   \note   Open the device. 
*			This function is called when the device shall be opened.
*/
/*****************************************************************************/	
static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device 	*info			=	NULL;
	io_info_t			*device_data	=	NULL;	
	int32_t 			bar;
	int32_t				ret;
		
	/* Allocate device driver structure */
	info = rtdm_malloc(sizeof(struct rtdm_device));
				
	if (info == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		return -ENOMEM;
	}
	
	if ((ret = pci_enable_device(dev)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", ret);
#endif /* DEBUG */
 
		goto out_free;
	}
	
	if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_request_regions error : %i\n", ret);
#endif /* DEBUG */
	
		goto out_disable;
	}
	
	/* Initialize structure with default values */
	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
	
	info->device_id	= id->device;
	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name	= info->device_name;
	
	switch (id->device) 
	{
		case PCI_DEVICE_ID_HILSCHER_NETX:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETPLC:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETJACK:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
			break;
		default:
			bar = PLX_DPM_BAR;
			info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
			break;
	}
	
	info->device_data = NULL;
	
	/* Allocate specific data strcuture for device */
	device_data = rtdm_malloc(sizeof(io_info_t));
	
	if (device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	memset(device_data, 0, sizeof(io_info_t));
	
	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
	if (device_data->mem[DPM_INDEX].addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_resource_start error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	device_data->mem[DPM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
    
	if (device_data->mem[DPM_INDEX].internal_addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */
	
		goto out_release;
	}
	
  	dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)device_data->mem[DPM_INDEX].addr);
  	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
  
	/* map extended mem (BAR 1 points to the extended memory) */
 	device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0)
	{
		device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));  
		
		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */			
		
			goto out_unmap;
		}
		
		dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}
  	
	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) 
	{
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} 
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) 
	{
		/* map PLX registers */
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */	

			goto out_unmap;
		}
		
		device_data->priv = pxa_info;
		
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
		
		if (!pxa_info->plx)
			goto out_unmap;
		if (cifx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (cifx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (cifx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} 
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

			goto out_free_pxa;
		}
		
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		device_data->priv = pxa_info;
	}
	
	/* Initialize irq data */
	device_data->irq = dev->irq;
	device_data->irq_enable = FALSE;
	device_data->irq_registered = FALSE;
	
	info->device_data = device_data;

	/* Register RTDM device driver */
	if ((ret = rtdm_dev_register(info)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -EINVAL :

				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
				break;
				
			case -ENOMEM :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
				break;
				
			case -EEXIST :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
				break;	
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n");
				break;
		}
#endif /* DEBUG */
	
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}
	
	pci_set_drvdata(dev, info);
	
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,	"registered NXSB-PCA adapter card\n");
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t *)info->device_data)->priv;
		dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit mode\n", pxa_info->dpm_mode);
	}
		
	cifx_num++;
	
	return 0;

out_unmap_plx:
	iounmap(((pxa_dev_info *)(((io_info_t *)info->device_data)->priv))->plx);
	
out_free_pxa:
	rtdm_free(((io_info_t *)info->device_data)->priv);
	
out_unmap:
	iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
	if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
	
out_disable:
	pci_disable_device(dev);
	
out_free:
	if (info->device_data != NULL)
	{
		rtdm_free(info->device_data);
	}
	rtdm_free(info);
	
	return -ENODEV;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_remove
*
*   \param  [in]	dev  			
*
*   \return None
*
*   \note   Close the device. 
*			This function is called when the device shall be closed.
*/
/*****************************************************************************/	
static void cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device 	*info 			= pci_get_drvdata(dev);
	io_info_t			*device_data 	= (io_info_t *)info->device_data;	
	pxa_dev_info 		*pxa_info 		= (pxa_dev_info *)device_data->priv;
	int32_t				ret;

	if (info->device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n");
#endif /* DEBUG */
		return;
	}
	
	if (pxa_info != NULL) 
	{
		/* Disable all interrupts */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	
		if (pxa_info->plx != NULL)
			iounmap((void *)pxa_info->plx);

		rtdm_free((void *)pxa_info);		
	}
	
	/* Unregister RTDM device driver */
	if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -ENODEV :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
				break;			
			
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error\n");
				break;	
		}
#endif /* DEBUG */

		return;
	}

	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

	/* Release structure memory allocation */
	rtdm_free(info->device_data);
	rtdm_free(info);
	
	if (cifx_num > 0)
		cifx_num--;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_init			
*
*   \return None
*
*   \note   It simply registers the RTDM device. 
*			This function is called when the module is loaded.
*/
/*****************************************************************************/	
static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_exit			
*
*   \return None
*
*   \note   It unregister the RTDM device. 
*			This function is called when the module is unloaded.
*/
/*****************************************************************************/	
static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*! \}     cifx_pci_Core	                   				     			 */
/*****************************************************************************/

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

/* End of file : cifx_pci.c */
-------------- next part --------------
###### CONFIGURATION ######

### List of applications to be build
APPLICATIONS = cifx_xenomai_sample

### Note: to override the search path for the xeno-config script, use "make XENO=..."


### List of modules to be build
MODULES = cifx_pci 

### Note: to override the kernel source path, use "make KSRC=..."

MY_CFLAGS = -I/media/Doc/rtdm/libcifx -I/media/Doc/rtdm/libcifx/Toolkit -O2 #-DDEBUG

MY_LDFLAGS =  -L/usr/xenomai/lib -L/usr/lib/i386-linux-gnu/ -lpthread -lrt -lpciaccess -lcifx

###### USER SPACE BUILD (no change required normally) ######
ifeq ($(KERNELRELEASE),)
ifneq ($(APPLICATIONS),)

### Default Xenomai installation path
XENO ?= /usr/xenomai

XENOCONFIG=$(shell PATH=$(XENO):$(XENO)/bin:$(PATH) which xeno-config 2>/dev/null)

### Sanity check
ifeq ($(XENOCONFIG),)
all::
	@echo ">>> Invoke make like this: \"make XENO=/path/to/xeno-config\" <<<"
	@echo
endif


CC=$(shell $(XENOCONFIG) --cc)

CFLAGS=$(shell $(XENOCONFIG) --skin=posix --cflags) \
	$(shell $(XENOCONFIG) --skin=rtdm --cflags) $(MY_CFLAGS)

LDFLAGS=$(MY_LDFLAGS)
LDLIBS=$(shell $(XENOCONFIG) --skin=posix --ldflags) \
	$(shell $(XENOCONFIG) --skin=rtdm --ldflags) $(MY_LDFLAGS)

# This includes the library path of given Xenomai into the binary to make live
# easier for beginners if Xenomai's libs are not in any default search path.
LDFLAGS+=-Xlinker -rpath -Xlinker $(shell $(XENOCONFIG) --libdir) $(MY_LDFLAGS)

all:: $(APPLICATIONS)

clean::
	$(RM) $(APPLICATIONS) *.o

endif
endif



###### KERNEL MODULE BUILD (no change required normally) ######
ifneq ($(MODULES),)

### Default to sources of currently running kernel
KSRC ?= /lib/modules/$(shell uname -r)/build

OBJS     := ${patsubst %, %.o, $(MODULES)}
CLEANMOD := ${patsubst %, .%*, $(MODULES)}
PWD      := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi)

### Kernel 2.6 or 3.0
PATCHLEVEL:=$(shell sed 's/PATCHLEVEL = \(.*\)/\1/;t;d' $(KSRC)/Makefile)
VERSION:=$(shell sed 's/VERSION = \(.*\)/\1/;t;d' $(KSRC)/Makefile)
ifneq ($(VERSION).$(PATCHLEVEL),2.4)

obj-m        := $(OBJS)
EXTRA_CFLAGS := -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/posix $(ADD_CFLAGS)

all::
	$(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules

### Kernel 2.4
else

ARCH    ?= $(shell uname -i)
INCLUDE := -I$(KSRC)/include/xenomai -I$(KSRC)/include/xenomai/compat -I$(KSRC)/include/xenomai/posix
CFLAGS  += $(shell $(MAKE) -s -C $(KSRC) CC=$(CC) ARCH=$(ARCH) SUBDIRS=$(PWD) modules) $(INCLUDE)

all:: $(OBJS)

endif

## Target for capturing 2.4 module CFLAGS
modules:
	@echo "$(CFLAGS)"

clean::
	$(RM) $(CLEANMOD) *.o *.ko *.mod.c Module*.symvers Module.markers modules.order
	$(RM) -R .tmp*

endif

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-26 14:25   ` Jerome Poncin
@ 2013-02-26 14:28     ` Jan Kiszka
  2013-02-28  8:15       ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-26 14:28 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-02-26 15:25, Jerome Poncin wrote:
> Hello Jan,
> 
> Thank you for your answer. I checked /proc/interrupts and lspci -v, and I saw that the IRQ is shared.
> 
> "If yes, resolve that conflict."
> 
> => What must I do ? I'm not sure to have understood ?

See
http://xenomai.org/index.php/FAQs#What_can_I_do_if_Xenomai_and_Linux_devices_share_the_same_IRQ.3F

> 
> 
> /*****************************************************************************/
> /*!
> *   \brief  cifx_handler
> *
> *   \param  [in]    irq      Resource task pointer
> *
> *   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
> *
> *   \note   cifx interrupt handler
> */
> /*****************************************************************************/
> static /*inline*/ int cifx_handler(rtdm_irq_t *irq)
> {
>     struct rtdm_device    *info             = (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
>     io_info_t             *device_data     = (io_info_t *) info->device_data;
> 
>     if ((device_data->priv != NULL) || (device_data->irq_registered == FALSE) || (device_data->irq_enable == FALSE))
>     {
>         /* This is a PLX device and cannot produce an IRQ */
>         return RTDM_IRQ_NONE;
>     }
>     else
>     {
>         void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
>         void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
> 
>         /* Is one of our interrupts enabled and active ? */
>         if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
>             return RTDM_IRQ_NONE;
> 
>         /* Disable interrupt */
>         iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);
> 
>         return RTDM_IRQ_HANDLED;
>     }
> }
> 
> If IRQ is not mine, I return RTDM_IRQ_NONE, it's not correct ?

It is. The problem is the sharing between RT and Linux. That cannot work.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-26 11:37 ` Jan Kiszka
@ 2013-02-26 14:25   ` Jerome Poncin
  2013-02-26 14:28     ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-02-26 14:25 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

Hello Jan,

Thank you for your answer. I checked /proc/interrupts and lspci -v, and I saw that the IRQ is shared.

"If yes, resolve that conflict."

=> What must I do ? I'm not sure to have understood ?

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]    irq      Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static /*inline*/ int cifx_handler(rtdm_irq_t *irq)
{
     struct rtdm_device    *info             = (struct rtdm_device 
*)rtdm_irq_get_arg(irq, void);
     io_info_t             *device_data     = (io_info_t *) 
info->device_data;

     if ((device_data->priv != NULL) || (device_data->irq_registered == 
FALSE) || (device_data->irq_enable == FALSE))
     {
         /* This is a PLX device and cannot produce an IRQ */
         return RTDM_IRQ_NONE;
     }
     else
     {
         void __iomem *int_enable_reg = 
device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
         void __iomem *int_status_reg = 
device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;

         /* Is one of our interrupts enabled and active ? */
         if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & 
DPM_HOST_INT_MASK))
             return RTDM_IRQ_NONE;

         /* Disable interrupt */
         iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, 
int_enable_reg);

         return RTDM_IRQ_HANDLED;
     }
}

If IRQ is not mine, I return RTDM_IRQ_NONE, it's not correct ?

Thank you very much for your help,

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





Le 26/02/2013 12:37, Jan Kiszka a écrit :
> On 2013-02-26 10:29, Jerome Poncin wrote:
>> Hello,
>>
>> I have a problem with driver for Hilscher cifx with IRQ.
>>
>> All driver run good (I verified in polling mode) but in case I activate
>> IRQ the system freeze.
>>
>> I checked parameters of "rtdm_irq_request" function without success (all
>> seems good) ! I tried to see on internet to get some information about
>> the use of "rtdm_irq_request", or compare my code with other driver but
>> it's not easy...
>> I give you in attached file my code because I have no idea about my
>> problem, and it's really difficult to have some information or trace
>> after system freeze...
>> Do you have an idea about my problem ?
>> static inline int cifx_handler(rtdm_irq_t *irq)
>           ^^^^^^
> But I suspect the compiler is smart enough to ignore this.
>
> Is the line you are registering for shared with other devices? Check
> /proc/interrupts and lspci -v. If yes, resolve that conflict.
>
> If not, add printk to your IRQ handler, redirect the kernel messages to
> a serial console and try to find out how far and how ofter you get into
> the handler.
>
> Well, and then there is the option of source-level debugging. kgdb for
> I-pipe patches aren't merged yet, but more convenient is KVM-based
> debugging anyway. See [1] for the concept. Just requires VT-d or AMD
> IOMMU on your target.
>
> Jan
>
> PS: Still no kernel coding style. Specifically the long lines makes it
> hard to read.
>
> [1]
> http://chemnitzer.linux-tage.de/2012/vortraege/folien/1061-VirtualDebugging.pdf
>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-26  9:29 Jerome Poncin
@ 2013-02-26 11:37 ` Jan Kiszka
  2013-02-26 14:25   ` Jerome Poncin
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-26 11:37 UTC (permalink / raw)
  To: Jerome Poncin; +Cc: xenomai

On 2013-02-26 10:29, Jerome Poncin wrote:
> Hello,
> 
> I have a problem with driver for Hilscher cifx with IRQ.
> 
> All driver run good (I verified in polling mode) but in case I activate
> IRQ the system freeze.
> 
> I checked parameters of "rtdm_irq_request" function without success (all
> seems good) ! I tried to see on internet to get some information about
> the use of "rtdm_irq_request", or compare my code with other driver but
> it's not easy...
> I give you in attached file my code because I have no idea about my
> problem, and it's really difficult to have some information or trace
> after system freeze...
> Do you have an idea about my problem ?

> static inline int cifx_handler(rtdm_irq_t *irq)
         ^^^^^^
But I suspect the compiler is smart enough to ignore this.

Is the line you are registering for shared with other devices? Check
/proc/interrupts and lspci -v. If yes, resolve that conflict.

If not, add printk to your IRQ handler, redirect the kernel messages to
a serial console and try to find out how far and how ofter you get into
the handler.

Well, and then there is the option of source-level debugging. kgdb for
I-pipe patches aren't merged yet, but more convenient is KVM-based
debugging anyway. See [1] for the concept. Just requires VT-d or AMD
IOMMU on your target.

Jan

PS: Still no kernel coding style. Specifically the long lines makes it
hard to read.

[1]
http://chemnitzer.linux-tage.de/2012/vortraege/folien/1061-VirtualDebugging.pdf

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [Xenomai]  Hilscher driver for cifX boards
@ 2013-02-26  9:29 Jerome Poncin
  2013-02-26 11:37 ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Jerome Poncin @ 2013-02-26  9:29 UTC (permalink / raw)
  To: xenomai

Hello,

I have a problem with driver for Hilscher cifx with IRQ.

All driver run good (I verified in polling mode) but in case I activate 
IRQ the system freeze.

I checked parameters of "rtdm_irq_request" function without success (all 
seems good) ! I tried to see on internet to get some information about 
the use of "rtdm_irq_request", or compare my code with other driver but 
it's not easy...
I give you in attached file my code because I have no idea about my 
problem, and it's really difficult to have some information or trace 
after system freeze...
Do you have an idea about my problem ?

Thank you very much for you help,
-- 

Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http://www.hilscher.fr
HILSCHER FRANCE 	Jérôme Poncin
jponcin@hilscher.com
Ingénieur Développement Logiciel
Tél. : +33 (0) 4 72 37 98 44





-------------- next part --------------
/***************************************************************************
 *   Copyright (C) 2013 		                                   		   *
 *   Hilscher France (JP)                                                  *
 *   http://www.hilscher.fr/ 						   					   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

/***************************************************************************/

/* Includes */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>

#include <sys/mman.h>

#include <rtdm/rtdm_driver.h>

/***************************************************************************/

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

/***************************************************************************/
/*!
*   \addtogroup cifx_pci_Core
*   @{
*/
/***************************************************************************/

/* #define */

#ifndef TRUE
#define TRUE						1		
#endif /* TRUE */

#ifndef FALSE
#define FALSE						0		
#endif /* TRUE */

#ifndef PCI_VENDOR_ID_HILSCHER
	#define PCI_VENDOR_ID_HILSCHER   			0x15CF
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
	#define PCI_DEVICE_ID_HILSCHER_NETX  		0x0000
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
	#define PCI_DEVICE_ID_HILSCHER_NETPLC  		0x0010
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
	#define PCI_DEVICE_ID_HILSCHER_NETJACK  	0x0020
#endif

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
	#define PCI_SUBDEVICE_ID_NXSB_PCA  			0x3235
#endif

#ifndef PCI_SUBDEVICE_ID_NXPCA
	#define PCI_SUBDEVICE_ID_NXPCA   			0x3335
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
	#define PCI_SUBDEVICE_ID_NETPLC_RAM  		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
	#define PCI_SUBDEVICE_ID_NETPLC_FLASH   	0x0001
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
	#define PCI_SUBDEVICE_ID_NETJACK_RAM   		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
	#define PCI_SUBDEVICE_ID_NETJACK_FLASH   	0x0001
#endif

#define DPM_HOST_INT_EN0						0xfff0
#define DPM_HOST_INT_STAT0						0xffe0
#define PLX_GPIO_OFFSET        					0x15
#define PLX_TIMING_OFFSET       				0x0a

#define DPM_HOST_INT_MASK						0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN					0x80000000
#define PLX_GPIO_DATA0_MASK     				0x00000004
#define PLX_GPIO_DATA1_MASK     				0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  				0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 				0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 				0x40824122

/* number of bar */
#define DPM_BAR    								0			/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 							1 			/* points to the optional extended memory     */
#define PLX_DPM_BAR 							2 			/* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 							0 			/* timing config register                     */

/* index of io_info structure's memory array */
#define DPM_INDEX     							0 			/* first mapping describes DPM              */
#define EXT_MEM_INDEX 							1			/* second mapping describes extended memory */

#define MAX_MAPS    							2

/* defines for memtype */
#define MEM_PHYS    							1

#define DRIVER_NAME								"rtdm_cifx"
#define PERIPHERAL_NAME							"cifx"
#define PROVIDER_NAME							"Hilscher"

#define CIFX_RTDM_PLX_CARD_NAME     			"netx_plx"  /* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME         			"netx"      /* name of a cifX PCI card              */
#define CIFX_RTDM_NETPLC_CARD_NAME  			"netplc"    /* name of a netPLC PCI card            */
#define CIFX_RTDM_NETJACK_CARD_NAME 			"netjack"   /* name of a netJACK PCI card           */

typedef struct {
	uint32_t __iomem 	*plx;
	uint8_t 			dpm_mode;
	uint32_t  			plx_timing;
} pxa_dev_info;

typedef struct {
	uint32_t			addr;
	uint32_t 			size;
	int32_t 			memtype;
	void __iomem 		*internal_addr;
} io_mem;  

typedef struct {
	io_mem				mem[MAX_MAPS];
	int32_t				irq;
	uint8_t 			irq_enable;
	uint8_t 			irq_registered;
	rtdm_irq_t  		irq_handle;
	void				*priv;
} io_info_t;

typedef struct {
	uint32_t			phys_addr;
	void **				virt_addr;
	uint32_t			length;
} io_map_mem;

/***************************************************************************/

/* Prototypes */

static int 	cifx_handler(rtdm_irq_t *irq);
static int 	cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_dpm_mode(struct rtdm_device *info);

static int 	cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags);
static int 	cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info);
static ssize_t  cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte);
static ssize_t  cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte);

static int 	cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void cifx_pci_remove(struct pci_dev *dev);

/***************************************************************************/

/* Local variables */

static 	int32_t 	cifx_num	=	0;


static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version		= RTDM_DEVICE_STRUCT_VER,
	
	.device_flags		= RTDM_NAMED_DEVICE,
	.context_size   	= 0,
	.device_name		= "",

	.open_nrt		= cifx_pci_open,

	.ops = {
		.close_nrt	= cifx_pci_close,

		.read_nrt   = cifx_pci_read,
		.write_nrt  = cifx_pci_write,
		
		.ioctl_rt	= NULL,
		.ioctl_nrt	= NULL,

		.read_rt	= NULL,
		.write_rt	= NULL,
	},

	.device_class		= RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class	= RTDM_SUBCLASS_GENERIC,
	.profile_version	= 1,
	.driver_name		= DRIVER_NAME,
	.driver_version		= RTDM_DRIVER_VER(1, 0, 0),
	.provider_name		= PROVIDER_NAME,
};

static struct pci_device_id cifx_pci_tbl[] = {
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_RAM,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_FLASH,
	},
	{ 0, }
};

/* This structure describe the RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name		= "cifx",
	.id_table	= cifx_pci_tbl,
	.probe		= cifx_pci_probe,
	.remove		= cifx_pci_remove,
};

/***************************************************************************/

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]	irq  	Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static inline int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device	*info 			= (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
	io_info_t 			*device_data 	= (io_info_t *) info->device_data;
	
	if (device_data->priv != NULL)
	{
		/* This is a PLX device and cannot produce an IRQ */
		return RTDM_IRQ_NONE;
	} 
	else
	{	
		void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
			return IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_set_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info 	 *pxa_info 	= (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem *plx_timing;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	
	if (!pxa_info)
		return -ENODEV;
		
	switch (pxa_info->dpm_mode) 
	{
		case 8:
			pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
			break;
		case 16:
			pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
			break;
		case 32:
			pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
			break;
		default:
			return -EINVAL;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_dpm_mode
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
	pxa_dev_info 		*pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem 	*plx_gpio;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
		
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_open
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	oflags		flags
*
*   \return 0 (OK) or Error
*
*   \note   Open
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	int32_t					ret;

	if (oflags == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_registered == FALSE)
		{	
			if ((ret = rtdm_irq_request(&(((io_info_t *)info->device_data)->irq_handle), ((io_info_t *)info->device_data)->irq, cifx_handler, RTDM_IRQTYPE_SHARED, info->device_name, (void *)info)) != 0)
			{
#ifdef DEBUG
				switch (ret)
				{
					case -EINVAL :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an invalid parameter was passed\n");
						break;
				
					case -EBUSY :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the specified IRQ line is already in use\n");
						break;
		
					default :
			
						rtdm_printk("cifx rtdm driver error : rtdm_irq_request error\n");
						break;
				}				
#endif /* DEBUG */

				return -ENODEV;
			}
			else
			{
				((io_info_t *)info->device_data)->irq_registered = TRUE;
			}
		}
	}

	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_close
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*
*   \return 0 (OK) or Error
*
*   \note   Close
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
			
	if (((io_info_t *)info->device_data)->irq_registered == TRUE)
	{
		if (((io_info_t *)info->device_data)->irq_enable == TRUE)
		{
			if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
			{
#ifdef DEBUG
				rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
		
				return -ENODEV;
			}
		}
	}

	return 0;
}
	
/*****************************************************************************/
/*!
*   \brief  cifx_pci_read
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_read(struct rtdm_dev_context *context, rtdm_user_info_t *user_info, void *buf, size_t nbyte)
{
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	
	if (nbyte > sizeof(io_info_t))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}
	
	if (rtdm_safe_copy_to_user(user_info, buf, ((io_info_t *)info->device_data), nbyte))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
	}

	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_write
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	buf	user 	buffer
*	\param	[in]	nbyte		number of byte to read
*
*   \return size read
*
*   \note   Read
*/
/*****************************************************************************/
static ssize_t cifx_pci_write(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, const void *buf, size_t nbyte)
{
	struct rtdm_device 	*info = (struct rtdm_device *)context->device;
	uint8_t				irq_enable;
	io_map_mem			map_mem;
	int					ret;
	
	if (nbyte > sizeof(io_map_mem))
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : data user size too big\n");
#endif /* DEBUG */
	
		return 0;
	}

	if (nbyte == sizeof(uint8_t))
	{
		if (rtdm_safe_copy_from_user(user_info, &irq_enable, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if ((((io_info_t *)info->device_data)->irq_enable) != irq_enable)
			{
				if (((io_info_t *)info->device_data)->irq_registered == TRUE)
				{
					if (irq_enable == TRUE)
					{
						if (rtdm_irq_enable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_enable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}
					else
					{
						if (rtdm_irq_disable(&(((io_info_t *)info->device_data)->irq_handle)) != 0)
						{
#ifdef DEBUG
							rtdm_printk("cifx rtdm driver error : rtdm_irq_disable error\n");				
#endif /* DEBUG */
					
							return -ENODEV;
						}
					}				
				
					((io_info_t *)info->device_data)->irq_enable = irq_enable;
				}
				else
				{
#ifdef DEBUG
					rtdm_printk("cifx rtdm driver error : try to enable or diable IRQ but not registered\n");				
#endif /* DEBUG */
				}
			}
		}
	}
	else if (nbyte == sizeof(io_map_mem))
	{
		if (rtdm_safe_copy_from_user(user_info, &map_mem, buf, nbyte))
		{
			nbyte = 0;
							
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : can't copy data from driver\n");
#endif /* DEBUG */
		}
		else
		{
			if (*map_mem.virt_addr == NULL)
			{
				ret = rtdm_iomap_to_user(user_info, (phys_addr_t)map_mem.phys_addr, (size_t)map_mem.length, (PROT_READ | PROT_WRITE), map_mem.virt_addr, NULL, NULL);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG					
					switch (ret)
					{
						case -EINVAL :				

								rtdm_printk("cifx rtdm driver error : an invalid start address, size, or destination address was passed\n");				

							break;
							
						case -ENOMEM :				

								rtdm_printk("cifx rtdm driver error : there is insufficient free memory or the limit of memory mapping for the user process was reached\n");				

							break;
							
						case -EAGAIN:		

								rtdm_printk("cifx rtdm driver error : too much memory has been already locked by the user process\n");				
		
							break;
							
						case -EPERM :	

								rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");				
	
							break;
							
						default :

								rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */	
				}
			}	
			else
			{
				ret = rtdm_munmap(user_info, *map_mem.virt_addr, (size_t)map_mem.length);
				
				if (ret != 0)
				{
					nbyte = 0;

#ifdef DEBUG				
					switch (ret)
					{
						case -EINVAL :
					
							rtdm_printk("cifx rtdm driver error : an invalid address or size was passed\n");				
					
							break;
				
						case -EPERM :
					
							rtdm_printk("cifx rtdm driver error : an illegal invocation environment is detected\n");	
					
							break;			
				
						default :
					
							rtdm_printk("cifx rtdm driver error : rtdm_safe_copy_from_user error\n");				
			
							break;
					}
#endif /* DEBUG */
				}
			}
		}	
	}
	else
	{
		nbyte = 0;
	}
	
	return nbyte;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_probe
*
*   \param  [in]	dev  		
*	\param	[in]	id			
*
*   \return 0 (OK) or Error
*
*   \note   Open the device. 
*			This function is called when the device shall be opened.
*/
/*****************************************************************************/	
static int cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device 	*info			=	NULL;
	io_info_t			*device_data	=	NULL;	
	int32_t 			bar;
	int32_t				ret;
		
	info = rtdm_malloc(sizeof(struct rtdm_device));
				
	if (info == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		return -ENOMEM;
	}
	
	if ((ret = pci_enable_device(dev)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", ret);
#endif /* DEBUG */
 
		goto out_free;
	}
	
	if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_request_regions error : %i\n", ret);
#endif /* DEBUG */
	
		goto out_disable;
	}
	
	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
	
	info->device_id	= id->device;
	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name	= info->device_name;
	
	switch (id->device) 
	{
		case PCI_DEVICE_ID_HILSCHER_NETX:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETPLC:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETJACK:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
			break;
		default:
			bar = PLX_DPM_BAR;
			info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
			break;
	}
	
	info->device_data = NULL;
	device_data = rtdm_malloc(sizeof(io_info_t));
	
	if (device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	memset(device_data, 0, sizeof(io_info_t));
	
	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
	if (device_data->mem[DPM_INDEX].addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : pci_resource_start error\n");
#endif /* DEBUG */

		goto out_release;
	}
	
	device_data->mem[DPM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
    
	if (device_data->mem[DPM_INDEX].internal_addr == 0)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */
	
		goto out_release;
	}
	
  	dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)device_data->mem[DPM_INDEX].addr);
  	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
  
	/* map extended mem (BAR 1 points to the extended memory) */
 	device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0)
	{
		device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));  
		
		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG */			
		
			goto out_unmap;
		}
		
		dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}
  	
	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) 
	{
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} 
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) 
	{
		/* map PLX registers */
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */	

			goto out_unmap;
		}
		
		device_data->priv = pxa_info;
		
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
		
		if (!pxa_info->plx)
			goto out_unmap;
		if (cifx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (cifx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (cifx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} 
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG */

			goto out_free_pxa;
		}
		
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		device_data->priv = pxa_info;
	}
	
	device_data->irq = dev->irq;
	device_data->irq_enable = FALSE;
	device_data->irq_registered = FALSE;
	
	info->device_data = device_data;

	if ((ret = rtdm_dev_register(info)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -EINVAL :

				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
				break;
				
			case -ENOMEM :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
				break;
				
			case -EEXIST :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
				break;	
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n");
				break;
		}
#endif /* DEBUG */
	
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}
	
	pci_set_drvdata(dev, info);
	
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,	"registered NXSB-PCA adapter card\n");
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t *)info->device_data)->priv;
		dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit mode\n", pxa_info->dpm_mode);
	}
		
	cifx_num++;
	
	return 0;

out_unmap_plx:
	iounmap(((pxa_dev_info *)(((io_info_t *)info->device_data)->priv))->plx);
	
out_free_pxa:
	rtdm_free(((io_info_t *)info->device_data)->priv);
	
out_unmap:
	iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
	if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
	
out_disable:
	pci_disable_device(dev);
	
out_free:
	if (info->device_data != NULL)
	{
		rtdm_free(info->device_data);
	}
	rtdm_free(info);
	
	return -ENODEV;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_remove
*
*   \param  [in]	dev  			
*
*   \return None
*
*   \note   Close the device. 
*			This function is called when the device shall be closed.
*/
/*****************************************************************************/	
static void cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device 	*info 			= pci_get_drvdata(dev);
	io_info_t			*device_data 	= (io_info_t *)info->device_data;	
	pxa_dev_info 		*pxa_info 		= (pxa_dev_info *)device_data->priv;
	int32_t				ret;

	if (info->device_data == NULL)
	{
#ifdef DEBUG
		rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n");
#endif /* DEBUG */
		return;
	}
	
	if (pxa_info != NULL) 
	{
		/* Disable all interrupts */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	
		if (pxa_info->plx != NULL)
			iounmap((void *)pxa_info->plx);

		rtdm_free((void *)pxa_info);		
	}
	
	if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
	{
#ifdef DEBUG
		switch(ret)
		{
			case -ENODEV :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
				break;			
			
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error\n");
				break;	
		}
#endif /* DEBUG */

		return;
	}

	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

	rtdm_free(info->device_data);
	rtdm_free(info);
	
	if (cifx_num > 0)
		cifx_num--;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_init			
*
*   \return None
*
*   \note   It simply registers the RTDM device. 
*			This function is called when the module is loaded.
*/
/*****************************************************************************/	
static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_exit			
*
*   \return None
*
*   \note   It unregister the RTDM device. 
*			This function is called when the module is unloaded.
*/
/*****************************************************************************/	
static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*! \}     cifx_pci_Core	                   				     			 */
/*****************************************************************************/

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

/* End of file : cifx_pci.c */

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-15 14:54         ` Jan Kiszka
@ 2013-02-18 11:43           ` Stéphane LOS
  0 siblings, 0 replies; 57+ messages in thread
From: Stéphane LOS @ 2013-02-18 11:43 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Xenomai

Le 15/02/2013 15:54, Jan Kiszka a écrit :
> On 2013-02-14 16:01, Stéphane LOS wrote:
>> Hi,
>>
>> Please find attached the newest version that seems better to us.
> Some remarks on the code first:
>   - Consider reformatting your code according to kernel style, it will
>     improve readability (no long lines, e.g.).
>   - rtdm_malloc is for the rare case that you allocate memory over RT
>     context. But probe is still Linux.
>   - If you register/free the IRQ handler on open/close, you must also
>     enable/disable the IRQ sources in the hardware in those functions.
>   - On removal, unregister the RTDM device first. That will synchronize
>     with remaining open instances.
>   - Minor: Avoid __devinit/exit, they were removed from recent kernels.
>
> So, what is the bug again? How does the oops message look like? When
> will the device start generating IRQs, and do they arrive while rebooting?
>
> Jan
>
Thank you for your comments.
I have forwarded them to the developer.
Let's wait for his answer...

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-14 15:01       ` Stéphane LOS
@ 2013-02-15 14:54         ` Jan Kiszka
  2013-02-18 11:43           ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-15 14:54 UTC (permalink / raw)
  To: Stéphane LOS; +Cc: Xenomai

On 2013-02-14 16:01, Stéphane LOS wrote:
> Hi,
> 
> Please find attached the newest version that seems better to us.

Some remarks on the code first:
 - Consider reformatting your code according to kernel style, it will
   improve readability (no long lines, e.g.).
 - rtdm_malloc is for the rare case that you allocate memory over RT
   context. But probe is still Linux.
 - If you register/free the IRQ handler on open/close, you must also
   enable/disable the IRQ sources in the hardware in those functions.
 - On removal, unregister the RTDM device first. That will synchronize
   with remaining open instances.
 - Minor: Avoid __devinit/exit, they were removed from recent kernels.

So, what is the bug again? How does the oops message look like? When
will the device start generating IRQs, and do they arrive while rebooting?

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-14 13:36     ` Stéphane LOS
@ 2013-02-14 15:01       ` Stéphane LOS
  2013-02-15 14:54         ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-14 15:01 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Xenomai

Hi,

Please find attached the newest version that seems better to us.

Thank your for your comments.

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-------------- next part --------------
/***************************************************************************
 *   Copyright (C) 2013 		                                   		   *
 *   Hilscher France (JP)                                                  *
 *   http://www.hilscher.fr/ 						   					   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

/***************************************************************************/

/* Includes */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>

#include <rtdm/rtdm_driver.h>

/***************************************************************************/

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

/***************************************************************************/
/*!
*   \addtogroup cifx_pci_Core
*   @{
*/
/***************************************************************************/

/* #define */

/* Activate printk trace for debug */
#define DEBUG_PRINTK

#ifndef PCI_VENDOR_ID_HILSCHER
	#define PCI_VENDOR_ID_HILSCHER   			0x15CF
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
	#define PCI_DEVICE_ID_HILSCHER_NETX  		0x0000
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
	#define PCI_DEVICE_ID_HILSCHER_NETPLC  		0x0010
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
	#define PCI_DEVICE_ID_HILSCHER_NETJACK  	0x0020
#endif

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
	#define PCI_SUBDEVICE_ID_NXSB_PCA  			0x3235
#endif

#ifndef PCI_SUBDEVICE_ID_NXPCA
	#define PCI_SUBDEVICE_ID_NXPCA   			0x3335
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
	#define PCI_SUBDEVICE_ID_NETPLC_RAM  		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
	#define PCI_SUBDEVICE_ID_NETPLC_FLASH   	0x0001
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
	#define PCI_SUBDEVICE_ID_NETJACK_RAM   		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
	#define PCI_SUBDEVICE_ID_NETJACK_FLASH   	0x0001
#endif

#define DPM_HOST_INT_EN0						0xfff0
#define DPM_HOST_INT_STAT0						0xffe0
#define PLX_GPIO_OFFSET        					0x15
#define PLX_TIMING_OFFSET       				0x0a

#define DPM_HOST_INT_MASK						0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN					0x80000000
#define PLX_GPIO_DATA0_MASK     				0x00000004
#define PLX_GPIO_DATA1_MASK     				0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  				0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 				0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 				0x40824122

/* number of bar */
#define DPM_BAR    								0			/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 							1 			/* points to the optional extended memory     */
#define PLX_DPM_BAR 							2 			/* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 							0 			/* timing config register                     */

/* index of io_info structure's memory array */
#define DPM_INDEX     							0 			/* first mapping describes DPM              */
#define EXT_MEM_INDEX 							1			/* second mapping describes extended memory */

#define MAX_MAPS    							2

/* defines for memtype */
#define MEM_PHYS    							1

#define DRIVER_NAME								"rtdm_cifx"
#define PERIPHERAL_NAME							"cifx"
#define PROVIDER_NAME							"Hilscher"

#define CIFX_RTDM_PLX_CARD_NAME     			"netx_plx"  /* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME         			"netx"      /* name of a cifX PCI card              */
#define CIFX_RTDM_NETPLC_CARD_NAME  			"netplc"    /* name of a netPLC PCI card            */
#define CIFX_RTDM_NETJACK_CARD_NAME 			"netjack"   /* name of a netJACK PCI card           */

typedef struct {
	uint32_t __iomem 	*plx;
	uint8_t 			dpm_mode;
	uint32_t  			plx_timing;
} pxa_dev_info;

typedef struct {
	uint32_t			addr;
	uint32_t 			size;
	int32_t 			memtype;
	void __iomem 		*internal_addr;
} io_mem;  

typedef struct {
	io_mem				mem[MAX_MAPS];
	int32_t				irq;
	uint32_t			irq_flags;
	void				*priv;
	rtdm_irq_handler_t	handler;
	void				*irq_handle;
} io_info_t;

/***************************************************************************/

/* Prototypes */

static int 	cifx_handler(rtdm_irq_t *irq);
static int 	cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_dpm_mode(struct rtdm_device *info);

static int 	cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags);
static int 	cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info);

static int 	__devinit cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void __devexit cifx_pci_remove(struct pci_dev *dev);

/***************************************************************************/

/* Local variables */

static 	int32_t cifx_num	=	0;

static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version		= RTDM_DEVICE_STRUCT_VER,
	
	.device_flags		= RTDM_NAMED_DEVICE,
	.device_name		= "",

	.open_nrt		= cifx_pci_open,

	.ops = {
		.close_nrt	= cifx_pci_close,

		.ioctl_rt	= NULL,
		.ioctl_nrt	= NULL,

		.read_rt	= NULL,

		.write_rt	= NULL,
	},

	.device_class		= RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class	= RTDM_SUBCLASS_GENERIC,
	.profile_version	= 1,
	.driver_name		= DRIVER_NAME,
	.driver_version		= RTDM_DRIVER_VER(1, 0, 0),
	.provider_name		= PROVIDER_NAME,
	.proc_name		= PERIPHERAL_NAME,
};

static struct pci_device_id cifx_pci_tbl[] = {
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_RAM,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_FLASH,
	},
	{ 0, }
};

/* This structure describe the RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name		= "cifx",
	.id_table	= cifx_pci_tbl,
	.probe		= cifx_pci_probe,
	.remove		= __devexit_p(cifx_pci_remove),
};

struct cifx_pci_context {
	int32_t cifx_num;
};

/***************************************************************************/

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]	irq  	Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static inline int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device	*info 			= (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
	io_info_t 			*device_data 	= (io_info_t *) info->device_data;
	
	if (device_data->priv != NULL)
	{
		/* This is a PLX device and cannot produce an IRQ */
		return RTDM_IRQ_NONE;
	} 
	else
	{	
		void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
			return IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_set_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info 	 *pxa_info 	= (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem *plx_timing;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	
	if (!pxa_info)
		return -ENODEV;
		
	switch (pxa_info->dpm_mode) 
	{
		case 8:
			pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
			break;
		case 16:
			pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
			break;
		case 32:
			pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
			break;
		default:
			return -EINVAL;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_dpm_mode
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
	pxa_dev_info 		*pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem 	*plx_gpio;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
		
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_open
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	oflags		flags
*
*   \return 0 (OK) or Error
*
*   \note   Open
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags)
{
	struct cifx_pci_context *ctx = (struct cifx_pci_context *)context->dev_private; 
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	int32_t					ret;

	ctx->cifx_num = cifx_num;
	
	if ((ret = rtdm_irq_request(((io_info_t *)info->device_data)->irq_handle, ((io_info_t *)info->device_data)->irq, ((io_info_t *)info->device_data)->handler, ((io_info_t *)info->device_data)->irq_flags, info->device_name, (void *)info)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch (ret)
		{
			case -EINVAL :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an invalid parameter was passed\n");
				break;
				
			case -EBUSY :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the specified IRQ line is already in use\n");
				break;
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error\n");
				break;
		}				
#endif /* DEBUG_PRINTK */

		return -ENODEV;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_close
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*
*   \return 0 (OK) or Error
*
*   \note   Close
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	struct cifx_pci_context *ctx = (struct cifx_pci_context *)context->dev_private;
	struct rtdm_device 		*info = (struct rtdm_device *)context->device;
	int32_t					ret;
	
	ctx->cifx_num = cifx_num;
		
	if (((io_info_t *)info->device_data)->irq_handle != NULL)
	{
		if ((ret = rtdm_irq_free(((io_info_t *)info->device_data)->irq_handle)) != 0)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_irq_free error\n");
#endif /* DEBUG_PRINTK */

			return -ENODEV;;
		}
		else
		{
			rtdm_free(((io_info_t *)info->device_data)->irq_handle);
		}
	}
	
	return 0;
}
	
/*****************************************************************************/
/*!
*   \brief  cifx_pci_probe
*
*   \param  [in]	dev  		
*	\param	[in]	id			
*
*   \return 0 (OK) or Error
*
*   \note   Open the device. 
*			This function is called when the device shall be opened.
*/
/*****************************************************************************/	
static int __devinit cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device 	*info			=	NULL;
	rtdm_irq_t  		*irq_handle 	= 	NULL;
	io_info_t			*device_data	=	NULL;	
	int32_t 			bar;
	int32_t				ret;
		
	info = rtdm_malloc(sizeof(struct rtdm_device));
				
	if (info == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		return -ENOMEM;
	}
	
	if ((ret = pci_enable_device(dev)) != 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", ret);
#endif /* DEBUG_PRINTK */
 
		goto out_free;
	}
	
	if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_request_regions error : %i\n", ret);
#endif /* DEBUG_PRINTK */
	
		goto out_disable;
	}
	
	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
	
	info->device_id	= id->device;
	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name	= info->device_name;
	info->context_size = sizeof(struct cifx_pci_context);
	
	switch (id->device) 
	{
		case PCI_DEVICE_ID_HILSCHER_NETX:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETPLC:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETJACK:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
			break;
		default:
			bar = PLX_DPM_BAR;
			info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
			break;
	}
	
	info->device_data = NULL;
	device_data = rtdm_malloc(sizeof(io_info_t));
	
	if (device_data == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		return -ENOMEM;
	}
	
	memset(device_data, 0, sizeof(io_info_t));
	
	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
	if (device_data->mem[DPM_INDEX].addr == 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_resource_start error\n");
#endif /* DEBUG_PRINTK */

		goto out_release;
	}
	
	device_data->mem[DPM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
    
	if (device_data->mem[DPM_INDEX].internal_addr == 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG_PRINTK */
	
		goto out_release;
	}
	
  	dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)device_data->mem[DPM_INDEX].addr);
  	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
  
	/* map extended mem (BAR 1 points to the extended memory) */
 	device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0)
	{
		device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));  
		
		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG_PRINTK */			
		
			goto out_unmap;
		}
		
		dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}
  	
	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) 
	{
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} 
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) 
	{
		/* map PLX registers */
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */	

			goto out_unmap;
		}
		
		device_data->priv = pxa_info;
		
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
		
		if (!pxa_info->plx)
			goto out_unmap;
		if (cifx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (cifx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (cifx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} 
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

			goto out_free_pxa;
		}
		
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		device_data->priv = pxa_info;
	}

	info->device_data = device_data;

	if ((ret = rtdm_dev_register(info)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch(ret)
		{
			case -EINVAL :

				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
				break;
				
			case -ENOMEM :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
				break;
				
			case -EEXIST :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
				break;	
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n");
				break;
		}
#endif /* DEBUG_PRINTK */
	
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}

	device_data->irq = dev->irq;
	device_data->irq_flags = RTDM_IRQTYPE_SHARED;
	device_data->handler = cifx_handler;
	device_data->irq_handle = NULL;

	irq_handle = rtdm_malloc(sizeof(rtdm_irq_t));
	
	if (irq_handle == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		goto out_free_irq;
	}

	memset(irq_handle, 0, sizeof(rtdm_irq_t));
		
	device_data->irq_handle = irq_handle;

	pci_set_drvdata(dev, info);
	
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,	"registered NXSB-PCA adapter card\n");
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t *)info->device_data)->priv;
		dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit mode\n", pxa_info->dpm_mode);
	}
		
	cifx_num++;
		
	return 0;

out_free_irq:
	rtdm_free(((io_info_t *)info->device_data)->irq_handle);

out_unmap_plx:
	iounmap(((pxa_dev_info *)(((io_info_t *)info->device_data)->priv))->plx);
	
out_free_pxa:
	rtdm_free(((io_info_t *)info->device_data)->priv);
	
out_unmap:
	iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
	if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
	
out_disable:
	pci_disable_device(dev);
	
out_free:
	if (irq_handle != NULL)
	{
		rtdm_free(irq_handle);
	}
	if (info->device_data != NULL)
	{
		rtdm_free(info->device_data);
	}
	rtdm_free(info);
	
	return -ENODEV;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_remove
*
*   \param  [in]	dev  			
*
*   \return None
*
*   \note   Close the device. 
*			This function is called when the device shall be closed.
*/
/*****************************************************************************/	
static void __devexit cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device 	*info 			= pci_get_drvdata(dev);
	io_info_t			*device_data 	= (io_info_t *)info->device_data;	
	pxa_dev_info 		*pxa_info 		= (pxa_dev_info *)device_data->priv;
	int32_t				ret;

	if (info->device_data == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n");
#endif /* DEBUG_PRINTK */
		return;
	}
	
	if (pxa_info != NULL) 
	{
		/* Disable all interrupts */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	
		if (pxa_info->plx != NULL)
			iounmap((void *)pxa_info->plx);

		rtdm_free((void *)pxa_info);		
	}

	if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch(ret)
		{
			case -ENODEV :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
				break;			
			
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error\n");
				break;	
		}
#endif /* DEBUG_PRINTK */

		return;
	}

	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

	rtdm_free(info->device_data);
	rtdm_free(info);
	
	if (cifx_num > 0)
		cifx_num--;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_init			
*
*   \return None
*
*   \note   It simply registers the RTDM device. 
*			This function is called when the module is loaded.
*/
/*****************************************************************************/	
static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_exit			
*
*   \return None
*
*   \note   It unregister the RTDM device. 
*			This function is called when the module is unloaded.
*/
/*****************************************************************************/	
static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*! \}     cifx_pci_Core	                   				     			 */
/*****************************************************************************/

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

/* End of file : cifx_pci.c */

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-13 14:09   ` Stéphane LOS
@ 2013-02-14 13:36     ` Stéphane LOS
  2013-02-14 15:01       ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-14 13:36 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Xenomai

Le 13/02/2013 15:09, Stéphane LOS a écrit :
> Le 12/02/2013 12:51, Jan Kiszka a écrit :
>> On 2013-02-12 12:37, Stéphane LOS wrote:
>>> Hello there,
>>>
>>> It seems we have managed to build an RTDM module and we can insmod it
>>> and it shows up in the named devices list.
>>>
>>> If we forget to rmmod the module, the kernel crashes when stopping or
>>> rebooting.
>> So you have a bug in your driver that requires fixing. Is the device
>> opened while you shutdown? What does the backtrace tell you you about
>> the crash? If you share your code early, we could review it already.
>>
>> Jan
>>
> Yes, of course we have a bug. I think that we have plenty of them in 
> fact. ;-)
> I would like to share the code but it is a little early since we are 
> trying to figure out what we have to do.
> Something is written started from what we have found in the sources 
> but we still have to learn.
> The RTDM API documentation is good but we have very little knowledge 
> on how RTDM drivers should be used with Xenomai.
> We lack general information.
> Since the following links are broken now :
> http://www.xenomai.org/index.php/Weblinks#Installation_of_Xenomai_and_RTDM_Driver_Writing 
>
> I remember that there use to be here a documentation about the RTDM 
> driver for CIF boards, it was years ago.
> My colleague is actually working on the driver, I intervene here 
> because I like writing in English and I am the support guy. ;-)
>
> Best Regards,
> Cordialement,
>
> Stéphane LOS
> slos@hilscher.com
> Support technique
>
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Hilscher France
> 12, rue du 35ème Régiment d'Aviation
> Miniparc du Chêne
> 69500 BRON
> France
> Tél. : +33 (0) 4 72 37 98 40
> Fax  : +33 (0) 4 78 26 83 27
> http ://www.hilscher.fr
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>
> _______________________________________________
> Xenomai mailing list
> Xenomai@xenomai.org
> http://www.xenomai.org/mailman/listinfo/xenomai
>

Hello,

Please find attached the faulty code being developed.

Thank you in advance for your comments and hints.

By the way, our Linux driver supports as many boards as needed.

Is it possible with a RTDM driver to drive several boards ?
I guess yes but we don't understand yet how things go to the 
/proc/xenomai file system.
What should we find there ?

Again thank you for your help.

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-------------- next part --------------
/***************************************************************************
 *   Copyright (C) 2013 		                                   		   *
 *   Hilscher France (JP)                                                  *
 *   http://www.hilscher.fr/ 						   					   *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

/***************************************************************************/

/* Includes */

#include <linux/device.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>

#include <rtdm/rtdm_driver.h>

/***************************************************************************/

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("RTDM board driver for CifX cards");
MODULE_AUTHOR("Hilscher France (JP) <www.hilscher.fr>");

/***************************************************************************/
/*!
*   \addtogroup cifx_pci_Core
*   @{
*/
/***************************************************************************/

/* #define */

/* Activate printk trace for debug */
#define DEBUG_PRINTK

#ifndef PCI_VENDOR_ID_HILSCHER
	#define PCI_VENDOR_ID_HILSCHER   			0x15CF
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETX
	#define PCI_DEVICE_ID_HILSCHER_NETX  		0x0000
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETPLC
	#define PCI_DEVICE_ID_HILSCHER_NETPLC  		0x0010
#endif

#ifndef PCI_DEVICE_ID_HILSCHER_NETJACK
	#define PCI_DEVICE_ID_HILSCHER_NETJACK  	0x0020
#endif

#ifndef PCI_SUBDEVICE_ID_NXSB_PCA
	#define PCI_SUBDEVICE_ID_NXSB_PCA  			0x3235
#endif

#ifndef PCI_SUBDEVICE_ID_NXPCA
	#define PCI_SUBDEVICE_ID_NXPCA   			0x3335
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_RAM
	#define PCI_SUBDEVICE_ID_NETPLC_RAM  		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETPLC_FLASH
	#define PCI_SUBDEVICE_ID_NETPLC_FLASH   	0x0001
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_RAM
	#define PCI_SUBDEVICE_ID_NETJACK_RAM   		0x0000
#endif

#ifndef PCI_SUBDEVICE_ID_NETJACK_FLASH
	#define PCI_SUBDEVICE_ID_NETJACK_FLASH   	0x0001
#endif

#define DPM_HOST_INT_EN0						0xfff0
#define DPM_HOST_INT_STAT0						0xffe0
#define PLX_GPIO_OFFSET        					0x15
#define PLX_TIMING_OFFSET       				0x0a

#define DPM_HOST_INT_MASK						0xe600ffff
#define DPM_HOST_INT_GLOBAL_EN					0x80000000
#define PLX_GPIO_DATA0_MASK     				0x00000004
#define PLX_GPIO_DATA1_MASK     				0x00000020

#define NX_PCA_PCI_8_BIT_DPM_MODE  				0x5431F962
#define NX_PCA_PCI_16_BIT_DPM_MODE 				0x4073F8E2
#define NX_PCA_PCI_32_BIT_DPM_MODE 				0x40824122

/* number of bar */
#define DPM_BAR    								0			/* points to the DPM -> netX, netPLC, netJACK */
#define EXT_MEM_BAR 							1 			/* points to the optional extended memory     */
#define PLX_DPM_BAR 							2 			/* points to the DPM -> netXPLX               */ 
#define PXA_PLX_BAR 							0 			/* timing config register                     */

/* index of io_info structure's memory array */
#define DPM_INDEX     							0 			/* first mapping describes DPM              */
#define EXT_MEM_INDEX 							1			/* second mapping describes extended memory */

#define MAX_MAPS    							2

/* defines for memtype */
#define MEM_PHYS    							1

#define DRIVER_NAME								"rtdm_cifx"
#define PERIPHERAL_NAME							"cifx"
#define PROVIDER_NAME							"Hilscher"

#define CIFX_RTDM_PLX_CARD_NAME     			"netx_plx"  /* name of a NXSB-PCA or NXPCA-PCI card */
#define CIFX_RTDM_CARD_NAME         			"netx"      /* name of a cifX PCI card              */
#define CIFX_RTDM_NETPLC_CARD_NAME  			"netplc"    /* name of a netPLC PCI card            */
#define CIFX_RTDM_NETJACK_CARD_NAME 			"netjack"   /* name of a netJACK PCI card           */

typedef struct {
	uint32_t __iomem 	*plx;
	uint8_t 			dpm_mode;
	uint32_t  			plx_timing;
} pxa_dev_info;

typedef struct {
	uint32_t			addr;
	uint32_t 			size;
	int32_t 			memtype;
	void __iomem 		*internal_addr;
} io_mem;  

typedef struct {
	io_mem				mem[MAX_MAPS];
	int32_t				irq;
	uint32_t			irq_flags;
	void				*priv;
	rtdm_irq_handler_t	handler;
	void				*irq_handle;
} io_info_t;

/***************************************************************************/

/* Prototypes */

static int 	cifx_handler(rtdm_irq_t *irq);
static int 	cifx_pxa_set_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_plx_timing(struct rtdm_device *info);
static int 	cifx_pxa_get_dpm_mode(struct rtdm_device *info);

static int 	cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags);
static int 	cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info);

static int 	__devinit cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void __devexit cifx_pci_remove(struct pci_dev *dev);

/***************************************************************************/

/* Local variables */

static int cifx_num	=	0;

static const struct rtdm_device __initdata cifx_device_tmpl = {
	.struct_version		= RTDM_DEVICE_STRUCT_VER,

	.device_flags		= RTDM_NAMED_DEVICE,
	.device_name		= "",

	.open_nrt		= cifx_pci_open,

	.ops = {
		.close_nrt	= cifx_pci_close,

		.ioctl_rt	= NULL,
		.ioctl_nrt	= NULL,

		.read_rt	= NULL,

		.write_rt	= NULL,
	},

	.device_class		= RTDM_CLASS_EXPERIMENTAL,
	.device_sub_class	= RTDM_SUBCLASS_GENERIC,
	.profile_version	= 1,
	.driver_name		= DRIVER_NAME,
	.driver_version		= RTDM_DRIVER_VER(1, 0, 0),
	.provider_name		= PROVIDER_NAME,
	.proc_name		= PERIPHERAL_NAME,
};

static struct pci_device_id cifx_pci_tbl[] = {
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETX,
		.subvendor =	0,
		.subdevice =	0,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXSB_PCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_PLX,
		.device =	PCI_DEVICE_ID_PLX_9030,
		.subvendor =	PCI_VENDOR_ID_PLX,
		.subdevice =	PCI_SUBDEVICE_ID_NXPCA,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_RAM,
	},
	{
		.vendor =	PCI_VENDOR_ID_HILSCHER,
		.device =	PCI_DEVICE_ID_HILSCHER_NETPLC,
		.subvendor =	PCI_VENDOR_ID_HILSCHER,
		.subdevice =	PCI_SUBDEVICE_ID_NETPLC_FLASH,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_RAM,
	},
	{
		.vendor = PCI_VENDOR_ID_HILSCHER,
		.device = PCI_DEVICE_ID_HILSCHER_NETJACK,
		.subvendor =  PCI_VENDOR_ID_HILSCHER,
		.subdevice =  PCI_SUBDEVICE_ID_NETJACK_FLASH,
	},
	{ 0, }
};

/* This structure describe the RTDM cifX Driver */
static struct pci_driver cifx_pci_driver = {
	.name		= "cifx",
	.id_table	= cifx_pci_tbl,
	.probe		= cifx_pci_probe,
	.remove		= __devexit_p(cifx_pci_remove),
};

/***************************************************************************/

/*****************************************************************************/
/*!
*   \brief  cifx_handler
*
*   \param  [in]	irq  	Resource task pointer
*
*   \return RTDM_IRQ_NONE or RTDM_IRQ_HANDLED
*
*   \note   cifx interrupt handler
*/
/*****************************************************************************/
static int cifx_handler(rtdm_irq_t *irq)
{
	struct rtdm_device	*info 			= (struct rtdm_device *)rtdm_irq_get_arg(irq, void);
	io_info_t 			*device_data 	= (io_info_t *) info->device_data;
	
	if (device_data->priv != NULL)
	{
		/* This is a PLX device and cannot produce an IRQ */
		return RTDM_IRQ_NONE;
	} 
	else
	{	
		void __iomem *int_enable_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0;
		void __iomem *int_status_reg = device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_STAT0;
	
		/* Is one of our interrupts enabled and active ? */
		if (!(ioread32(int_enable_reg) & ioread32(int_status_reg) & DPM_HOST_INT_MASK))
			return IRQ_NONE;
	
		/* Disable interrupt */
		iowrite32(ioread32(int_enable_reg) & ~DPM_HOST_INT_GLOBAL_EN, int_enable_reg);

		return RTDM_IRQ_HANDLED;
	}
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_set_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Set plx timing
*/
/*****************************************************************************/
static int cifx_pxa_set_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info 	 *pxa_info 	= (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem *plx_timing;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_timing = pxa_info->plx + PLX_TIMING_OFFSET;
	*plx_timing = pxa_info->plx_timing;
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_plx_timing
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get plx timing
*/
/*****************************************************************************/
static int cifx_pxa_get_plx_timing(struct rtdm_device *info)
{
	pxa_dev_info *pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	
	if (!pxa_info)
		return -ENODEV;
		
	switch (pxa_info->dpm_mode) 
	{
		case 8:
			pxa_info->plx_timing = NX_PCA_PCI_8_BIT_DPM_MODE;
			break;
		case 16:
			pxa_info->plx_timing = NX_PCA_PCI_16_BIT_DPM_MODE;
			break;
		case 32:
			pxa_info->plx_timing = NX_PCA_PCI_32_BIT_DPM_MODE;
			break;
		default:
			return -EINVAL;
	}
	
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pxa_get_dpm_mode
*
*   \param  [in]	info  	cifx rtdm device information
*
*   \return 0 (OK) or Error
*
*   \note   Get dpm mode
*/
/*****************************************************************************/
static int cifx_pxa_get_dpm_mode(struct rtdm_device *info)
{
	pxa_dev_info 		*pxa_info = (pxa_dev_info *) ((io_info_t *)info->device_data)->priv;
	uint32_t __iomem 	*plx_gpio;
	
	if (!pxa_info)
		return -ENODEV;
		
	plx_gpio = pxa_info->plx + PLX_GPIO_OFFSET;
	
	if ((*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 8;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && (*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 32;
	else if (~(*plx_gpio & PLX_GPIO_DATA0_MASK) && ~(*plx_gpio & PLX_GPIO_DATA1_MASK))
		pxa_info->dpm_mode = 16;
	else
		return -EINVAL;
		
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_open
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*	\param	[in]	oflags		flags
*
*   \return 0 (OK) or Error
*
*   \note   Open
*/
/*****************************************************************************/
static int cifx_pci_open(struct rtdm_dev_context *context, rtdm_user_info_t * user_info, int oflags)
{
	return 0;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_close
*
*   \param  [in]	context  	context
*	\param	[in]	user_info	user information
*
*   \return 0 (OK) or Error
*
*   \note   Close
*/
/*****************************************************************************/
static int cifx_pci_close(struct rtdm_dev_context *context, rtdm_user_info_t * user_info)
{
	return 0;
}
	
/*****************************************************************************/
/*!
*   \brief  cifx_pci_probe
*
*   \param  [in]	dev  		
*	\param	[in]	id			
*
*   \return 0 (OK) or Error
*
*   \note   Open the device. 
*			This function is called when the device shall be opened.
*/
/*****************************************************************************/	
static int __devinit cifx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct rtdm_device 	*info			=	NULL;
	rtdm_irq_t  		*irq_handle 	= 	NULL;
	io_info_t			*device_data	=	NULL;	
	int32_t 			bar;
	int32_t				ret;
		
	info = rtdm_malloc(sizeof(struct rtdm_device));
				
	if (info == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		return -ENOMEM;
	}
	
	if ((ret = pci_enable_device(dev)) != 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_enable_device error : %i\n", ret);
#endif /* DEBUG_PRINTK */
 
		goto out_free;
	}
	
	if ((ret = pci_request_regions(dev, DRIVER_NAME)) != 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_request_regions error : %i\n", ret);
#endif /* DEBUG_PRINTK */
	
		goto out_disable;
	}
	
	memcpy(info, &cifx_device_tmpl, sizeof(struct rtdm_device));
	
	info->device_id	= id->device;
	snprintf((char *)info->device_name, RTDM_MAX_DEVNAME_LEN, "cifx%i", cifx_num);
	info->proc_name	= info->device_name;

	switch (id->device) 
	{
		case PCI_DEVICE_ID_HILSCHER_NETX:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETPLC:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETPLC_CARD_NAME;
			break;
		case PCI_DEVICE_ID_HILSCHER_NETJACK:
			bar = DPM_BAR;
			info->peripheral_name = CIFX_RTDM_NETJACK_CARD_NAME;
			break;
		default:
			bar = PLX_DPM_BAR;
			info->peripheral_name = CIFX_RTDM_PLX_CARD_NAME;
			break;
	}
	
	info->device_data = NULL;
	device_data = rtdm_malloc(sizeof(io_info_t));
	
	if (device_data == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		return -ENOMEM;
	}
	
	memset(device_data, 0, sizeof(io_info_t));
	
	/* BAR 0 or 2 points to the card's dual port memory */
	device_data->mem[DPM_INDEX].addr = pci_resource_start(dev, bar);
  
	if (device_data->mem[DPM_INDEX].addr == 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : pci_resource_start error\n");
#endif /* DEBUG_PRINTK */

		goto out_release;
	}
	
	device_data->mem[DPM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, bar), pci_resource_len(dev, bar));
    
	if (device_data->mem[DPM_INDEX].internal_addr == 0)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG_PRINTK */
	
		goto out_release;
	}
	
  	dev_info(&dev->dev, "DPM at %08lX\n", (long unsigned int)device_data->mem[DPM_INDEX].addr);
  	device_data->mem[DPM_INDEX].size = pci_resource_len(dev, bar);
  	device_data->mem[DPM_INDEX].memtype = MEM_PHYS;
  
	/* map extended mem (BAR 1 points to the extended memory) */
 	device_data->mem[EXT_MEM_INDEX].addr = pci_resource_start(dev, EXT_MEM_BAR);
 
	/* extended memory is optional, so don't care if it is not present */
	if (device_data->mem[EXT_MEM_INDEX].addr != 0)
	{
		device_data->mem[EXT_MEM_INDEX].internal_addr = ioremap_nocache(pci_resource_start(dev, EXT_MEM_BAR), pci_resource_len(dev, EXT_MEM_BAR));  
		
		if (device_data->mem[EXT_MEM_INDEX].internal_addr == 0)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : ioremap_nocache error\n");
#endif /* DEBUG_PRINTK */			
		
			goto out_unmap;
		}
		
		dev_info(&dev->dev, "extended memory at %08lX\n", (long unsigned int)device_data->mem[EXT_MEM_INDEX].addr);
		device_data->mem[EXT_MEM_INDEX].size    = pci_resource_len(dev, EXT_MEM_BAR);
		device_data->mem[EXT_MEM_INDEX].memtype = MEM_PHYS;
	}
  	
	if ((id->device == PCI_DEVICE_ID_HILSCHER_NETX) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETPLC) 
	||	(id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)) 
	{
		/* make sure all interrupts are disabled */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
		device_data->priv = NULL;
	} 
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXPCA) 
	{
		/* map PLX registers */
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */	

			goto out_unmap;
		}
		
		device_data->priv = pxa_info;
		
		/* set PXA PLX Timings */
		pxa_info->plx = ioremap_nocache(pci_resource_start(dev, PXA_PLX_BAR), pci_resource_len(dev, PXA_PLX_BAR));
		
		if (!pxa_info->plx)
			goto out_unmap;
		if (cifx_pxa_get_dpm_mode(info))
			goto out_unmap_plx;
		if (cifx_pxa_get_plx_timing(info))
			goto out_unmap_plx;
		if (cifx_pxa_set_plx_timing(info))
			goto out_unmap_plx;
	} 
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)rtdm_malloc(sizeof(pxa_dev_info));
		
		if (pxa_info == NULL)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

			goto out_free_pxa;
		}
		
		pxa_info->plx = NULL;
		pxa_info->plx_timing = 0;
		pxa_info->dpm_mode = 0;
		device_data->priv = pxa_info;
	}

	info->device_data = device_data;

	if ((ret = rtdm_dev_register(info)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch(ret)
		{
			case -EINVAL :

				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the device structure contains invalid entries. Check kernel log in this case\n");
				break;
				
			case -ENOMEM :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the context for an exclusive device cannot be allocated\n");
				break;
				
			case -EEXIST :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : the specified device name of protocol ID is already in use\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error : some /proc entry cannot be created\n");
				break;	
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_register error\n");
				break;
		}
#endif /* DEBUG_PRINTK */
	
		if (id->subdevice != PCI_SUBDEVICE_ID_NXPCA)
			goto out_unmap;
		else
			goto out_unmap_plx;
	}

	device_data->irq = dev->irq;
	device_data->irq_flags = RTDM_IRQTYPE_SHARED;
	device_data->handler = cifx_handler;
	device_data->irq_handle = NULL;

	irq_handle = rtdm_malloc(sizeof(rtdm_irq_t));
	
	if (irq_handle == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : rtdm_malloc error\n");
#endif /* DEBUG_PRINTK */

		goto out_free_irq;
	}

	memset(irq_handle, 0, sizeof(rtdm_irq_t));
	
	if ((ret = rtdm_irq_request(irq_handle, device_data->irq, device_data->handler, device_data->irq_flags, info->device_name, (void *)info)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch (ret)
		{
			case -EINVAL :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : an invalid parameter was passed\n");
				break;
				
			case -EBUSY :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error : the specified IRQ line is already in use\n");
				break;
		
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_irq_request error\n");
				break;
		}				
#endif /* DEBUG_PRINTK */

		goto out_release_irq;
	}
		
	device_data->irq_handle = irq_handle;

	pci_set_drvdata(dev, info);
	
	if (id->device == PCI_DEVICE_ID_HILSCHER_NETX)
		dev_info(&dev->dev, "registered CifX card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETPLC)
		dev_info(&dev->dev, "registered netPLC card\n");
	else if (id->device == PCI_DEVICE_ID_HILSCHER_NETJACK)
		dev_info(&dev->dev, "registered netJACK card\n");
	else if (id->subdevice == PCI_SUBDEVICE_ID_NXSB_PCA)
		dev_info(&dev->dev,	"registered NXSB-PCA adapter card\n");
	else 
	{
		pxa_dev_info *pxa_info = (pxa_dev_info *)((io_info_t *)info->device_data)->priv;
		dev_info(&dev->dev, "registered NXPCA-PCI adapter card in %d bit mode\n", pxa_info->dpm_mode);
	}
		
	cifx_num++;
		
	return 0;
	
out_release_irq :
	rtdm_irq_free(irq_handle);

out_free_irq:
	rtdm_free(((io_info_t *)info->device_data)->irq_handle);

out_unmap_plx:
	iounmap(((pxa_dev_info *)(((io_info_t *)info->device_data)->priv))->plx);
	
out_free_pxa:
	rtdm_free(((io_info_t *)info->device_data)->priv);
	
out_unmap:
	iounmap(((io_info_t *)info->device_data)->mem[DPM_INDEX].internal_addr);
	if (((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(((io_info_t *)info->device_data)->mem[EXT_MEM_INDEX].internal_addr);
out_release:
	pci_release_regions(dev);
	
out_disable:
	pci_disable_device(dev);
	
out_free:
	if (irq_handle != NULL)
	{
		rtdm_free(irq_handle);
	}
	if (info->device_data != NULL)
	{
		rtdm_free(info->device_data);
	}
	rtdm_free(info);
	
	return -ENODEV;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_remove
*
*   \param  [in]	dev  			
*
*   \return None
*
*   \note   Close the device. 
*			This function is called when the device shall be closed.
*/
/*****************************************************************************/	
static void __devexit cifx_pci_remove(struct pci_dev *dev)
{
	struct rtdm_device 	*info 			= pci_get_drvdata(dev);
	io_info_t			*device_data 	= (io_info_t *)info->device_data;	
	pxa_dev_info 		*pxa_info 		= (pxa_dev_info *)device_data->priv;
	int32_t				ret;

	if (info->device_data == NULL)
	{
#ifdef DEBUG_PRINTK
		rtdm_printk("cifx rtdm driver error : device_data NULL pointer\n");
#endif /* DEBUG_PRINTK */
		return;
	}
	
	if (pxa_info != NULL) 
	{
		/* Disable all interrupts */
		iowrite32(0, device_data->mem[DPM_INDEX].internal_addr + DPM_HOST_INT_EN0);
	
		if (pxa_info && pxa_info->plx)
			iounmap((void *)pxa_info->plx);

		rtdm_free((void *)pxa_info);		
	}
	
	if (device_data->irq_handle != NULL)
	{
		if ((ret = rtdm_irq_free(device_data->irq_handle)) != 0)
		{
#ifdef DEBUG_PRINTK
			rtdm_printk("cifx rtdm driver error : rtdm_irq_free error\n");
#endif /* DEBUG_PRINTK */

			return;
		}
		else
		{
			rtdm_free(device_data->irq_handle);
		}
	}

	if ((ret = rtdm_dev_unregister(info, 1000)) != 0)
	{
#ifdef DEBUG_PRINTK
		switch(ret)
		{
			case -ENODEV :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device was not registered\n");
				break;
				
			case -EAGAIN :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error : the device is busy with open instances and 0 has been passed for poll_delay\n");
				break;			
			
			default :
			
				rtdm_printk("cifx rtdm driver error : rtdm_dev_unregister error\n");
				break;	
		}
#endif /* DEBUG_PRINTK */

		return;
	}

	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
	
	iounmap(device_data->mem[DPM_INDEX].internal_addr);
	if (device_data->mem[EXT_MEM_INDEX].internal_addr != 0)
		iounmap(device_data->mem[EXT_MEM_INDEX].internal_addr);

	rtdm_free(info->device_data);
	rtdm_free(info);
	
	if (cifx_num > 0)
		cifx_num--;
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_init			
*
*   \return None
*
*   \note   It simply registers the RTDM device. 
*			This function is called when the module is loaded.
*/
/*****************************************************************************/	
static int __init cifx_pci_init(void)
{
	return pci_register_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*!
*   \brief  cifx_pci_exit			
*
*   \return None
*
*   \note   It unregister the RTDM device. 
*			This function is called when the module is unloaded.
*/
/*****************************************************************************/	
static void __exit cifx_pci_exit(void)
{
	pci_unregister_driver(&cifx_pci_driver);
}

/*****************************************************************************/
/*! \}     cifx_pci_Core	                   				     			 */
/*****************************************************************************/

module_init(cifx_pci_init);
module_exit(cifx_pci_exit);

/* End of file : cifx_pci.c */

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-12 11:51 ` Jan Kiszka
@ 2013-02-13 14:09   ` Stéphane LOS
  2013-02-14 13:36     ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-13 14:09 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Xenomai

Le 12/02/2013 12:51, Jan Kiszka a écrit :
> On 2013-02-12 12:37, Stéphane LOS wrote:
>> Hello there,
>>
>> It seems we have managed to build an RTDM module and we can insmod it
>> and it shows up in the named devices list.
>>
>> If we forget to rmmod the module, the kernel crashes when stopping or
>> rebooting.
> So you have a bug in your driver that requires fixing. Is the device
> opened while you shutdown? What does the backtrace tell you you about
> the crash? If you share your code early, we could review it already.
>
> Jan
>
Yes, of course we have a bug. I think that we have plenty of them in 
fact. ;-)
I would like to share the code but it is a little early since we are 
trying to figure out what we have to do.
Something is written started from what we have found in the sources but 
we still have to learn.
The RTDM API documentation is good but we have very little knowledge on 
how RTDM drivers should be used with Xenomai.
We lack general information.
Since the following links are broken now :
http://www.xenomai.org/index.php/Weblinks#Installation_of_Xenomai_and_RTDM_Driver_Writing
I remember that there use to be here a documentation about the RTDM 
driver for CIF boards, it was years ago.
My colleague is actually working on the driver, I intervene here because 
I like writing in English and I am the support guy. ;-)

Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [Xenomai] Hilscher driver for cifX boards
  2013-02-12 11:37 Stéphane LOS
@ 2013-02-12 11:51 ` Jan Kiszka
  2013-02-13 14:09   ` Stéphane LOS
  0 siblings, 1 reply; 57+ messages in thread
From: Jan Kiszka @ 2013-02-12 11:51 UTC (permalink / raw)
  To: Stéphane LOS; +Cc: Xenomai

On 2013-02-12 12:37, Stéphane LOS wrote:
> Hello there,
> 
> It seems we have managed to build an RTDM module and we can insmod it
> and it shows up in the named devices list.
> 
> If we forget to rmmod the module, the kernel crashes when stopping or
> rebooting.

So you have a bug in your driver that requires fixing. Is the device
opened while you shutdown? What does the backtrace tell you you about
the crash? If you share your code early, we could review it already.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SDP-DE
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 57+ messages in thread

* [Xenomai] Hilscher driver for cifX boards
@ 2013-02-12 11:37 Stéphane LOS
  2013-02-12 11:51 ` Jan Kiszka
  0 siblings, 1 reply; 57+ messages in thread
From: Stéphane LOS @ 2013-02-12 11:37 UTC (permalink / raw)
  To: Xenomai

Hello there,

It seems we have managed to build an RTDM module and we can insmod it 
and it shows up in the named devices list.

If we forget to rmmod the module, the kernel crashes when stopping or 
rebooting.

Is there a preferred method to insmod / rmmod modules automatically with 
Xenomai ?

Thank you for your kind support.

-- 
Best Regards,
Cordialement,

Stéphane LOS
slos@hilscher.com
Support technique

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hilscher France
12, rue du 35ème Régiment d'Aviation
Miniparc du Chêne
69500 BRON
France
Tél. : +33 (0) 4 72 37 98 40
Fax  : +33 (0) 4 78 26 83 27
http ://www.hilscher.fr
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2013-03-19 13:42 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-07 14:53 [Xenomai] Hilscher driver for cifX boards Stéphane LOS
2013-02-07 16:11 ` Gilles Chanteperdrix
2013-02-08  9:07   ` Stéphane LOS
2013-02-08  9:18     ` Gilles Chanteperdrix
2013-02-08 11:28       ` Jan Kiszka
2013-02-08 11:35         ` Gilles Chanteperdrix
2013-02-08 11:46           ` Jan Kiszka
     [not found]         ` <5114FD7B.20902@hilscher.com>
2013-02-08 13:40           ` Jan Kiszka
2013-02-08 14:33             ` Stéphane LOS
2013-02-12 11:37 Stéphane LOS
2013-02-12 11:51 ` Jan Kiszka
2013-02-13 14:09   ` Stéphane LOS
2013-02-14 13:36     ` Stéphane LOS
2013-02-14 15:01       ` Stéphane LOS
2013-02-15 14:54         ` Jan Kiszka
2013-02-18 11:43           ` Stéphane LOS
2013-02-26  9:29 Jerome Poncin
2013-02-26 11:37 ` Jan Kiszka
2013-02-26 14:25   ` Jerome Poncin
2013-02-26 14:28     ` Jan Kiszka
2013-02-28  8:15       ` Jerome Poncin
2013-02-28 11:31         ` Jan Kiszka
2013-02-28 12:08           ` Jerome Poncin
2013-03-01 13:56             ` Jerome Poncin
2013-03-01 17:02               ` Jan Kiszka
2013-03-01 20:06               ` Gilles Chanteperdrix
2013-03-04  9:13               ` Jerome Poncin
2013-03-04 21:08                 ` Gilles Chanteperdrix
2013-03-05 10:45                   ` Jerome Poncin
2013-03-05 11:26                     ` Jan Kiszka
2013-03-05 12:21                       ` Gilles Chanteperdrix
2013-03-05 12:30                       ` Gilles Chanteperdrix
2013-03-05 15:42                       ` Jerome Poncin
2013-03-05 19:41                         ` Gilles Chanteperdrix
2013-03-06  8:10                           ` Jerome Poncin
2013-03-06  8:19                             ` Gilles Chanteperdrix
2013-03-06  8:55                               ` Jerome Poncin
2013-03-06 10:33                               ` Jerome Poncin
2013-03-06 12:04                                 ` Gilles Chanteperdrix
2013-03-06 13:58                                   ` Jerome Poncin
2013-03-06 15:28                                     ` Jan Kiszka
2013-03-06 21:05                                       ` Gilles Chanteperdrix
2013-03-07 15:33                                         ` Jerome Poncin
2013-03-08 10:17                                           ` Jerome Poncin
2013-03-08 12:22                                             ` Gilles Chanteperdrix
2013-03-12  9:10                                               ` Jerome Poncin
2013-03-12 12:21                                                 ` Gilles Chanteperdrix
2013-03-12 15:27                                                   ` Jerome Poncin
2013-03-12 19:38                                                     ` Gilles Chanteperdrix
2013-03-13 11:08                                                       ` Jerome Poncin
2013-03-15  9:09                                                         ` Jerome Poncin
2013-03-15 11:07                                                           ` Jan Kiszka
2013-03-15 13:04                                                             ` Jerome Poncin
2013-03-15 13:24                                                               ` Jan Kiszka
2013-03-18 10:02                                                                 ` Jerome Poncin
2013-03-19 13:42                                                                   ` Jerome Poncin
2013-03-06 20:42                                     ` Gilles Chanteperdrix

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.