|  | /* | 
|  | * drivers/uio/uio_pdrv.c | 
|  | * | 
|  | * Copyright (C) 2008 by Digi International Inc. | 
|  | * All rights reserved. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or modify it | 
|  | * under the terms of the GNU General Public License version 2 as published by | 
|  | * the Free Software Foundation. | 
|  | */ | 
|  | #include <linux/platform_device.h> | 
|  | #include <linux/uio_driver.h> | 
|  | #include <linux/stringify.h> | 
|  |  | 
|  | #define DRIVER_NAME "uio" | 
|  |  | 
|  | struct uio_platdata { | 
|  | struct uio_info *uioinfo; | 
|  | }; | 
|  |  | 
|  | static int uio_pdrv_probe(struct platform_device *pdev) | 
|  | { | 
|  | struct uio_info *uioinfo = pdev->dev.platform_data; | 
|  | struct uio_platdata *pdata; | 
|  | struct uio_mem *uiomem; | 
|  | int ret = -ENODEV; | 
|  | int i; | 
|  |  | 
|  | if (!uioinfo || !uioinfo->name || !uioinfo->version) { | 
|  | dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__); | 
|  | goto err_uioinfo; | 
|  | } | 
|  |  | 
|  | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | 
|  | if (!pdata) { | 
|  | ret = -ENOMEM; | 
|  | dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__); | 
|  | goto err_alloc_pdata; | 
|  | } | 
|  |  | 
|  | pdata->uioinfo = uioinfo; | 
|  |  | 
|  | uiomem = &uioinfo->mem[0]; | 
|  |  | 
|  | for (i = 0; i < pdev->num_resources; ++i) { | 
|  | struct resource *r = &pdev->resource[i]; | 
|  |  | 
|  | if (r->flags != IORESOURCE_MEM) | 
|  | continue; | 
|  |  | 
|  | if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { | 
|  | dev_warn(&pdev->dev, "device has more than " | 
|  | __stringify(MAX_UIO_MAPS) | 
|  | " I/O memory resources.\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | uiomem->memtype = UIO_MEM_PHYS; | 
|  | uiomem->addr = r->start; | 
|  | uiomem->size = r->end - r->start + 1; | 
|  | ++uiomem; | 
|  | } | 
|  |  | 
|  | while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { | 
|  | uiomem->size = 0; | 
|  | ++uiomem; | 
|  | } | 
|  |  | 
|  | pdata->uioinfo->priv = pdata; | 
|  |  | 
|  | ret = uio_register_device(&pdev->dev, pdata->uioinfo); | 
|  |  | 
|  | if (ret) { | 
|  | kfree(pdata); | 
|  | err_alloc_pdata: | 
|  | err_uioinfo: | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | platform_set_drvdata(pdev, pdata); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int uio_pdrv_remove(struct platform_device *pdev) | 
|  | { | 
|  | struct uio_platdata *pdata = platform_get_drvdata(pdev); | 
|  |  | 
|  | uio_unregister_device(pdata->uioinfo); | 
|  |  | 
|  | kfree(pdata); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct platform_driver uio_pdrv = { | 
|  | .probe = uio_pdrv_probe, | 
|  | .remove = uio_pdrv_remove, | 
|  | .driver = { | 
|  | .name = DRIVER_NAME, | 
|  | .owner = THIS_MODULE, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static int __init uio_pdrv_init(void) | 
|  | { | 
|  | return platform_driver_register(&uio_pdrv); | 
|  | } | 
|  |  | 
|  | static void __exit uio_pdrv_exit(void) | 
|  | { | 
|  | platform_driver_unregister(&uio_pdrv); | 
|  | } | 
|  | module_init(uio_pdrv_init); | 
|  | module_exit(uio_pdrv_exit); | 
|  |  | 
|  | MODULE_AUTHOR("Uwe Kleine-Koenig"); | 
|  | MODULE_DESCRIPTION("Userspace I/O platform driver"); | 
|  | MODULE_LICENSE("GPL v2"); | 
|  | MODULE_ALIAS("platform:" DRIVER_NAME); |