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
[email protected]
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 <[email protected]>
*
* 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");
_______________________________________________
Xenomai mailing list
[email protected]
http://www.xenomai.org/mailman/listinfo/xenomai