Doxygen+Sphinx+Breathe+Exhale - python-sphinx

Currently, I am working on project documentation. When I include source file and header file in conf.py the HTML generated successfully. But when I want to use source file only to documentation HTML file, there has something wrong on it. Such as following,
My conf.py content as below,
# Setup the exhale extension
exhale_args = {
# These arguments are required
"containmentFolder": "./api",
"rootFileName": "library_root.rst",
"rootFileTitle": "Library API",
"doxygenStripFromPath": "..",
# Suggested optional arguments
"createTreeView": True,
# TIP: if using the sphinx-bootstrap-theme, you need
# "treeViewIsBootstrap": True,
"exhaleExecutesDoxygen": True,
"exhaleDoxygenStdin": textwrap.dedent('''
EXTRACT_ALL = YES
SOURCE_BROWSER = YES
EXTRACT_STATIC = YES
OPTIMIZE_OUTPUT_FOR_C = YES
HIDE_SCOPE_NAMES = YES
QUIET = YES
INPUT = ../include ../src
FILE_PATTERNS = *.c *.h
EXAMPLE_RECURSIVE = YES
GENERATE_TREEVIEW = YES
''')
}
The source file and header file with success result
[Source File]
/**
* #brief Fills the data buffer
* #param[in] Data buffer
* #return pointer to the data buffer
**/
char* at_test_action(void* data)
{
char* ptr = (char*) data;
sprintf( ptr, "AT\r\n" );
return ptr;
}
[Header File]
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
char* at_test_action(void* data);
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
The source file and header file with fail result
[Source File]
/**
* #brief Fills the data buffer
* #param[in] Data buffer
* #return pointer to the data buffer
**/
char* at_test_action(void* data)
{
char* ptr = (char*) data;
sprintf( ptr, "AT\r\n" );
return ptr;
}
[Header File]
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
// char* at_test_action(void* data);
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
And I can use Doxygen without header file to generate result which I want.
Thank you very much.
2020.01.31 Update (UTC Time: 02:51)
Because of duplicate documentation, I want to add below comment into header file.
http://doxygen.10944.n7.nabble.com/Remove-detailed-documentation-from-header-td3679.html
#cond INCLUDE_THIS_SECTION_IN_DOXYGEN_OUTPUT
/* #endcond */
[Header File]
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
/* #cond INCLUDE_THIS_SECTION_IN_DOXYGEN_OUTPUT */
char* at_test_action(void* data);
/* #endcond */
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
[Source File]
/**
* \brief Fills the data buffer
* \param[in] data data buffer for content preparation
* \return pointer to the data buffer
**/
char* at_test_action(void* data)
{
char* ptr = (char*) data;
sprintf( ptr, "AT\r\n" );
return ptr;
}
Without above #cond the Doxygen result as following. Actually, in Doxygen representation is good for me.
But when change to Sphinx representation, user will see two same functions and list at sidebar without any detail information to distinguish it:
I am new for those tools, if there has stupid questions or the information is not enough, please let me know. Thank you very much.

One problem is the incorrect usage of the #param statement with doxygen. The syntax is \param '['dir']' <parameter-name> { parameter description }.
In your example the parameter name would be Data whilst the parameter in fact is data. As far as I can guess your intended use is #param[in] data Data buffer.

Related

How can I get a Win32 HANDLE for a StorageFile or StorageFolder in UWP?

I know I can use Win32 APIs for accessing files within my own local data folder (eg, see this answered question) but I need to access files outside of my app (eg, from the Pictures Library) and the libraries I'm trying to use are all based on Win32 file HANDLEs and / or they rely on using relative filenames.
Since the only way to get at files in the Pictures Library (or to get files / folders returned from a picker) is via StorageFile objects, how can I re-use my existing code? Do I have to re-write it all to be asynchronous and rely on the WinRT storage APIs?
Starting in the "Anniversary Update" (aka "RS1" or build 10.0.14393) you are able to get a Win32 HANDLE from a StorageItem (file or folder) and to create new named files (returning a HANDLE) from within a StorageFolder. You do this using the new IStorageFolderHandleAccess and IStorageItemHandleAccess APIs.
Note: These APIs have been accidentally placed inside the WINAPI_PARTITION_DESKTOP partition (they're not desktop-specific; they're available to UWPs). This will be addressed in future SDK updates.
To use one of these new COM interfaces, you simply QI the StorageFile or StorageFolder for the interface. If the interface isn't supported, it means your app is running on a down-level OS (or perhaps the Storage Item isn't actually backed by a real file, but is rather a pseudo-file). You can use these interfaces from C++ (C++/CX or WRL) or from C#.
Here's a simple example of using a FolderPicker to have the user pick a location on their disk (which returns a brokered StorageFolder object) and then using Win32 APIs ReadFile and WriteFile to read and write a file from that location.
As noted above, we have to copy the declarations for the interface into our own code because the real SDK versions are in the wrong API partition. (I would advise against modifying the SDK files to solve the problem). So first up is our own header file, eg StorageHandleAccess.h, that copies the declarations from the SDK file WindowsStorageCOM.h:
#pragma once
// These are copied from WindowsStorageCOM.h
// You can remove this header file once the real file has been updated
// to fix the WINAPI_PARTITION_DESKTOP block
typedef interface IOplockBreakingHandler IOplockBreakingHandler;
typedef interface IStorageItemHandleAccess IStorageItemHandleAccess;
typedef interface IStorageFolderHandleAccess IStorageFolderHandleAccess;
#ifdef __cplusplus
extern "C" {
#endif
typedef /* [v1_enum] */
enum HANDLE_OPTIONS
{
HO_NONE = 0,
HO_OPEN_REQUIRING_OPLOCK = 0x40000,
HO_DELETE_ON_CLOSE = 0x4000000,
HO_SEQUENTIAL_SCAN = 0x8000000,
HO_RANDOM_ACCESS = 0x10000000,
HO_NO_BUFFERING = 0x20000000,
HO_OVERLAPPED = 0x40000000,
HO_WRITE_THROUGH = 0x80000000
} HANDLE_OPTIONS;
DEFINE_ENUM_FLAG_OPERATORS(HANDLE_OPTIONS);
typedef /* [v1_enum] */
enum HANDLE_ACCESS_OPTIONS
{
HAO_NONE = 0,
HAO_READ_ATTRIBUTES = 0x80,
HAO_READ = 0x120089,
HAO_WRITE = 0x120116,
HAO_DELETE = 0x10000
} HANDLE_ACCESS_OPTIONS;
DEFINE_ENUM_FLAG_OPERATORS(HANDLE_ACCESS_OPTIONS);
typedef /* [v1_enum] */
enum HANDLE_SHARING_OPTIONS
{
HSO_SHARE_NONE = 0,
HSO_SHARE_READ = 0x1,
HSO_SHARE_WRITE = 0x2,
HSO_SHARE_DELETE = 0x4
} HANDLE_SHARING_OPTIONS;
DEFINE_ENUM_FLAG_OPERATORS(HANDLE_SHARING_OPTIONS);
typedef /* [v1_enum] */
enum HANDLE_CREATION_OPTIONS
{
HCO_CREATE_NEW = 0x1,
HCO_CREATE_ALWAYS = 0x2,
HCO_OPEN_EXISTING = 0x3,
HCO_OPEN_ALWAYS = 0x4,
HCO_TRUNCATE_EXISTING = 0x5
} HANDLE_CREATION_OPTIONS;
EXTERN_C const IID IID_IOplockBreakingHandler;
MIDL_INTERFACE("826ABE3D-3ACD-47D3-84F2-88AAEDCF6304")
IOplockBreakingHandler : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE OplockBreaking(void) = 0;
};
EXTERN_C const IID IID_IStorageItemHandleAccess;
MIDL_INTERFACE("5CA296B2-2C25-4D22-B785-B885C8201E6A")
IStorageItemHandleAccess : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Create(
/* [in] */ HANDLE_ACCESS_OPTIONS accessOptions,
/* [in] */ HANDLE_SHARING_OPTIONS sharingOptions,
/* [in] */ HANDLE_OPTIONS options,
/* [optional][in] */ __RPC__in_opt IOplockBreakingHandler *oplockBreakingHandler,
/* [system_handle][retval][out] */ __RPC__deref_out_opt HANDLE *interopHandle) = 0;
};
EXTERN_C const IID IID_IStorageFolderHandleAccess;
MIDL_INTERFACE("DF19938F-5462-48A0-BE65-D2A3271A08D6")
IStorageFolderHandleAccess : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Create(
/* [string][in] */ __RPC__in_string LPCWSTR fileName,
/* [in] */ HANDLE_CREATION_OPTIONS creationOptions,
/* [in] */ HANDLE_ACCESS_OPTIONS accessOptions,
/* [in] */ HANDLE_SHARING_OPTIONS sharingOptions,
/* [in] */ HANDLE_OPTIONS options,
/* [optional][in] */ __RPC__in_opt IOplockBreakingHandler *oplockBreakingHandler,
/* [system_handle][retval][out] */ __RPC__deref_out_opt HANDLE *interopHandle) = 0;
};
#ifdef __cplusplus
}
#endif
Next up is a simple usage of the API. This example takes a StorageFolder, a filename, and a creation flag (open or create) and tries to open (or create) the named file, reads (or writes) some text from (to) the file, and writes some output to the Debug console.
The code isn't particularly useful in a real-world setting, but illustrates how to use the API. This can be used in a blank C++ XAML project to replace the MainPage.xaml.cpp file (you should only need to update the namespace):
#include "pch.h"
#include "MainPage.xaml.h"
#include <ppltasks.h>
// TODO: Replace with your namespace
#error Replace this with your real namespace
using namespace FileHandleFromStorageFolder;
// Uncomment out this line and delete the next line once the SDK is fixed
//#include <WindowsStorageCOM.h>
#include "StorageHandleAccess.h"
// For ComPtr<>
#include <wrl\client.h>
// For HandleT<>
#include <wrl\wrappers\corewrappers.h>
__declspec(noreturn) inline void ThrowWithHRESULT(HRESULT hr, const wchar_t* message)
{
using namespace Platform;
throw ref new Exception(hr, ref new String(message));
}
__declspec(noreturn) inline void ThrowWithGetLastError(const wchar_t* message)
{
using namespace Platform;
throw ref new Exception(HRESULT_FROM_WIN32(GetLastError()), ref new String(message));
}
// Test is a simple test function. Pass in one of the HANDLE_CREATION_OPTIONS values
// (eg, HCO_CREATE_ALWAYS or HCO_OPEN_ALWAYS) and the function will try and either
// write to the file (if it's empty) or read from it (if it's not).
void Test(Windows::Storage::StorageFolder^ folder, const wchar_t* filename, HANDLE_CREATION_OPTIONS options)
{
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
// Get an IUnknown from the ref class, and then QI for IStorageFolderHandleAccess
ComPtr<IUnknown> abiPointer(reinterpret_cast<IUnknown*>(folder));
ComPtr<IStorageFolderHandleAccess> handleAccess;
HRESULT hr = abiPointer.As(&handleAccess);
if (FAILED(hr))
ThrowWithHRESULT(hr, L"Can't QI");
// Standard RAII wrapper for HANDLEs that represent files
HandleT<HandleTraits::FileHandleTraits>win32fileHandle;
// This is roughly equivalent of calling CreateFile2
hr = handleAccess->Create(filename, options,
HANDLE_ACCESS_OPTIONS::HAO_WRITE | HANDLE_ACCESS_OPTIONS::HAO_READ,
HANDLE_SHARING_OPTIONS::HSO_SHARE_NONE, HANDLE_OPTIONS::HO_NONE, nullptr,
win32fileHandle.GetAddressOf());
if (FAILED(hr))
ThrowWithHRESULT(hr, L"Can't access file");
// From here, it's standard Win32 code - nothing WinRT specific at all
LARGE_INTEGER size{ 0 };
if (FALSE == GetFileSizeEx(win32fileHandle.Get(), &size))
ThrowWithGetLastError(L"Can't get file size");
static const DWORD BUFFER_SIZE = 500;
char buffer[BUFFER_SIZE];
DWORD bytesUsed{ 0 };
if (size.QuadPart == 0)
{
const static auto str = "Hello, world\r\n";
if (FALSE == WriteFile(win32fileHandle.Get(), str, strlen(str), &bytesUsed, nullptr))
ThrowWithGetLastError(L"Can't write to file");
sprintf_s(buffer, ARRAYSIZE(buffer), "Wrote %d bytes to file\r\n", bytesUsed);
OutputDebugStringA(buffer);
}
else
{
if (FALSE == ReadFile(win32fileHandle.Get(), buffer, ARRAYSIZE(buffer) - 1, &bytesUsed, nullptr))
ThrowWithGetLastError(L"Can't read from file");
buffer[bytesUsed] = 0;
OutputDebugStringA(buffer);
}
}
// Trivial driver that gets a StorageFolder and then creates a file
// inside it, writes some text, then re-opens it to read text.
void TestWrapper()
{
using namespace Windows::Storage;
using namespace Windows::Storage::Pickers;
auto picker = ref new FolderPicker();
picker->FileTypeFilter->Append(L".txt");
picker->SuggestedStartLocation = PickerLocationId::Desktop;
concurrency::create_task(picker->PickSingleFolderAsync()).then([]
(StorageFolder^ folder)
{
if (folder != nullptr)
{
// Create and then read back a simple file
Test(folder, L"win32handletest.txt", HANDLE_CREATION_OPTIONS::HCO_CREATE_ALWAYS);
Test(folder, L"win32handletest.txt", HANDLE_CREATION_OPTIONS::HCO_OPEN_ALWAYS);
}
}
);
}
MainPage::MainPage()
{
InitializeComponent();
TestWrapper();
}

What is the modern version of `procfs1.c` for Linux 2.6.x kernels?

I have been following the Linux 2.6 Kernel Module Programming Guide, when I ran into the first example from Chapter 5, called procfs1.c.
It would not compile out of the box, and after checking various related questions, it still took me quite some time to figure out the correct changes to make it compile and work as intended.
Therefore, I am posting my updated code for people in the future. I am running kernel 2.6.32-279.el6.x86_64.
Here is an updated version of the example that works with kernel version 2.6.32-279.el6.x86_64.
/*
* procfs1.c - create a "file" in /proc
*
*/
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "helloworld"
/**
* This structure hold information about the /proc file
*
*/
struct proc_dir_entry *Our_Proc_File;
static ssize_t procfile_read(struct file *filp,
char *buffer,
size_t length,
loff_t * offset)
{
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);
if (*offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
ret = sprintf(buffer, "HelloWorld!\n");
*offset = ret;
}
return ret;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = procfile_read,
};
int init_module()
{
Our_Proc_File = proc_create(procfs_name, S_IFREG | S_IRUGO, NULL, &fops);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
procfs_name);
return -ENOMEM;
}
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "/proc/%s created\n", procfs_name);
return 0; /* everything is ok */
}
void cleanup_module()
{
remove_proc_entry(procfs_name, NULL);
printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}

Function Interposing on OSX Mavericks

I followed the directions exactly as they are on this site here
http://www.newosxbook.com/src.jl?tree=listings&file=4-5-interpose.c
Here is the code from that page
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <malloc/malloc.h> // for malloc_printf()
// Note: Compile with GCC, not cc (important)
//
//
// This is the expected interpose structure
typedef struct interpose_s { void *new_func;
void *orig_func; } interpose_t;
// Our prototypes - requires since we are putting them in
// the interposing_functions, below
void *my_malloc(int size); // matches real malloc()
void my_free (void *); // matches real free()
static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_free, (void *)free },
{ (void *)my_malloc, (void *)malloc }
};
void *
my_malloc (int size) {
// In our function we have access to the real malloc() -
// and since we don’t want to mess with the heap ourselves,
// just call it
//
void *returned = malloc(size);
// call malloc_printf() because the real printf() calls malloc()
// // internally - and would end up calling us, recursing ad infinitum
malloc_printf ( "+ %p %d\n", returned, size); return (returned);
}
void
my_free (void *freed) {
// Free - just print the address, then call the real free()
malloc_printf ( "- %p\n", freed); free(freed);
}
#if 0
From output 4-11:
morpheus#Ergo(~)$ gcc -dynamiclib l.c -o libMTrace.dylib -Wall // compile to dylib
morpheus#Ergo(~)$ DYLD_INSERT_LIBRARIES=libMTrace.dylib ls // force insert into ls
ls(24346) malloc: + 0x100100020 88
ls(24346) malloc: + 0x100800000 4096
ls(24346) malloc: + 0x100801000 2160
ls(24346) malloc: - 0x100800000
ls(24346) malloc: + 0x100801a00 3312 ... // etc.
#endif
Is there something different about the latest version of OSX or the code written here? It did not seem to intercept anything.
add attribute((used)) before the interposing_functions definition, and it will work, as follow:
// Note: Compile with GCC, not cc (important)
//
//
// This is the expected interpose structure
typedef struct interpose_s { void *new_func;
void *orig_func; } interpose_t;
// Our prototypes - requires since we are putting them in
// the interposing_functions, below
void *my_malloc(int size); // matches real malloc()
void my_free (void *); // matches real free()
__attribute__((used)) static const interpose_t interposing_functions[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_free, (void *)free },
{ (void *)my_malloc, (void *)malloc }
};
void *
my_malloc (int size) {
....
It's not a feature of Mavericks, it's a feature of clang. If you use jtool , from the same website, you'll see the generated dylib has no _DATA._interpose, which is required for DYLD to work the interposition magic.
Incidentally, this question is best asked in that book's own forum. That's probably what it's there for.

Error C2491: Function declared in header and defined in C++

I have been trying to build a device adapter for a open-source software called Micro-manager to control a microscope and there are some problems that I am facing, there are these two files (one header and the other CPP) that are already present in the open source package of Micro-Manager.
//MoudluleInterface.h
#ifndef _MODULE_INTERFACE_H_
#define _MODULE_INTERFACE_H_
#ifdef WIN32
#ifdef MODULE_EXPORTS
#define MODULE_API __declspec(dllexport)
#else
#define MODULE_API __declspec(dllimport)
#endif
#else
#define MODULE_API
#endif
#define MM_MODULE_ERR_OK 1000
#define MM_MODULE_ERR_WRONG_INDEX 1001
#define MM_MODULE_ERR_BUFFER_TOO_SMALL 1002
///////////////////////////////////////////////////////////////////////////////
// header version
// NOTE: If any of the exported module API calls changes, the interface version
// must be incremented
// new version 5 supports device discoverability
#define MODULE_INTERFACE_VERSION 7
#ifdef WIN32
const char* const LIB_NAME_PREFIX = "mmgr_dal_";
#else
const char* const LIB_NAME_PREFIX = "libmmgr_dal_";
#endif
#include "MMDevice.h"
///////////////////////////////////////////////////////////////////////////////
// Exported module interface
///////////////////////////////////////////////////////////////////////////////
extern "C" {
MODULE_API MM::Device* CreateDevice(const char* name);
MODULE_API void DeleteDevice(MM::Device* pDevice);
MODULE_API long GetModuleVersion();
MODULE_API long GetDeviceInterfaceVersion();
MODULE_API unsigned GetNumberOfDevices();
MODULE_API bool GetDeviceName(unsigned deviceIndex, char* name, unsigned bufferLength);
MODULE_API bool GetDeviceDescription(const char* deviceName, char* name, unsigned bufferLength);
And here is a part of the CPP file which defines these functions
//ModuleInterface.cpp
#define _CRT_SECURE_NO_DEPRECATE
#include "ModuleInterface.h"
#include <vector>
#include <string>
typedef std::pair<std::string, std::string> DeviceInfo;
std::vector<DeviceInfo> g_availableDevices;
int FindDeviceIndex(const char* deviceName)
{
for (unsigned i=0; i<g_availableDevices.size(); i++)
if (g_availableDevices[i].first.compare(deviceName) == 0)
return i;
return -1;
}
MODULE_API long GetModuleVersion()
{
return MODULE_INTERFACE_VERSION;
}
MODULE_API long GetDeviceInterfaceVersion()
{
return DEVICE_INTERFACE_VERSION;
}
MODULE_API unsigned GetNumberOfDevices()
{
return (unsigned) g_availableDevices.size();
}
MODULE_API bool GetDeviceName(unsigned deviceIndex, char* name, unsigned bufLen)
{
if (deviceIndex >= g_availableDevices.size())
return false;
Now the problem is it gives me an error C2491 (definition of dllimport function not allowed)
I did research about this and it usually is when a function is defined when it is supposed to be declared, I have already defined the function in ModuleInterface.h and then used it in ModuleInterface.cpp but it still shows the same error.
Can there be some other possibility for this error to occur? Or is there something wrong with the code?
You're not supposed to repeat your MODULE_API declaration in the definition, having it as part of the declaration is good enough. Remove the use of MODULE_API from the .cpp file and the code should compile.

How to create proc entry under /proc/driver?

I want to create a file under a /proc/driver directory. I would like to use a macro like proc_root_driver (or something else provided) rather than use "driver/MODULE_NAME" explicitly. I use create_proc_entry :
struct proc_dir_entry *simpleproc_fops_entry;
simpleproc_fops_entry = create_proc_entry(MODULE_NAME, 0400, NULL /* proc_root_dir */);
After googling, I found suggestion to use proc_root_driver, but when I use it, I get the error
proc_root_driver undeclared in this function
And also, proc_root_driver is not available in linux/proc_fs.h.
I have tried to declare structure like this:
struct proc_dir_entry proc_root;
struct proc_dir_entry *proc_root_driver = &proc_root;
The compilation errors gone, but the file didn't appear under /proc/driver or /proc. How can I make create an entry in /proc?
Looking at proc_fs.h, proc_root_driver is defined as :
extern struct proc_dir_entry *proc_root_driver;
so long as CONFIG_PROC_FS is enabled. If you have CONFIG_PROC_FS selected when you configure your kernel, you should be able to use it as you suggested yourself i.e. :
#include <linux/proc_fs.h>
struct proc_dir_entry * procfile
procfile = create_proc_entry("myprocfile", 0400, proc_root_driver);
If this does not work, check that you have CONFIG_PROC_FS set. To make sure, you can compile your source file with the -E option and check that the create_proc_entry call includes a non NULL parameter as the last parameter. If it is NULL, or the call is not there at all, then CONFIG_PROC_FS is not enabled.
/* proc entries for ayyaz */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#ifdef CONFIG_PROC_FS
/*====================================================================*/
/* Support for /proc/ayyaz */
static struct proc_dir_entry *proc_ayyaz;
DEFINE_MUTEX(ayyaz_table_mutex);
/*====================================================================*/
/* Init code */
static int ayyaz_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
int len, l, i;
off_t begin = 0;
mutex_lock(&ayyaz_table_mutex);
len = sprintf(page, "hello ayyaz here\n");
mutex_unlock(&ayyaz_table_mutex);
if (off >= len+begin)
return 0;
*start = page + (off-begin);
return ((count < begin+len-off) ? count : begin+len-off);
}
static int __init init_ayyaz(void)
{
if ((proc_ayyaz = create_proc_entry( "ayyaz_maps", 0, NULL )))
proc_ayyaz->read_proc = ayyaz_read_proc;
return 0;
}
static void __exit cleanup_ayyaz(void)
{
if (proc_ayyaz)
remove_proc_entry( "ayyaz", NULL);
}
module_init(init_ayyaz);
module_exit(cleanup_ayyaz);
#else
#error "Please add CONFIG_PROC_FS=y in your .config "
#endif /* CONFIG_PROC_FS */
MODULE_LICENSE("proprietary");
MODULE_AUTHOR("Md.Ayyaz A Mulla <md.ayyaz#gmail.com>");
MODULE_DESCRIPTION("proc files for ayyaz");
Compile this driver. If it compiles sucessfully, then you will see /proc/ayyaz.
#define PROC_ENTRY_NAME "driver/XX"
static struct proc_dir_entry *proc_XX;
static int XX_read_proc (char *page, char **start, off_t off, int count,
int *eof, void *data_unused)
{
return 0;
}
static int XX_write_proc (struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
return 0;
}
static int __init XX_add_driver(void)
{
if ((proc_flash = XX_entry(PROC_ENTRY_NAME, 0, NULL))) {
proc_XX->read_proc = XX_read_proc;
proc_XX->write_proc = XX_write_proc;
}
...
}
static void __exit XX_remove(void)
{
if (proc_flash)
remove_proc_entry(PROC_ENTRY_NAME, NULL);
return;
}
Then you can find the /proc/driver/XX entry.

Resources