Re: GPIO driver module for Jetway NF98 board

2012-01-23 Thread Joan Pau Beltran

Now that the code compiles, I need some help to debug it.
I used the kernel headers shipped with my distribution (Ubuntu), namely 
(from uname -r)
   2.6.38-13-generic

Everything compiles fine, without any warning.

But calling insmod, immediately triggers this error (from dmesg):

[  798.129707] generic-usb 0003:413C:2101.0002: input,hidraw0: USB HID 
v1.11 Keyboard [Dell Dell Smart Card Reader Keyboard] on 
usb-:00:1a.0-1.2/input0
[ 1414.832761] BUG: unable to handle kernel NULL pointer dereference at 
0502
[ 1414.832880] IP: [a00300e4] jwnf98_gpio_init+0xe4/0x1000 
[gpio_jwnf98]
[ 1414.832982] PGD 20a704067 PUD 21a601067 PMD 0
[ 1414.833036] Oops:  [#1] SMP
[ 1414.833077] last sysfs file: 
/sys/devices/pci:00/:00:19.0/net/eth0/statistics/collisions
[ 1414.833152] CPU 3
[ 1414.833172] Modules linked in: gpio_jwnf98(+) btrfs zlib_deflate 
libcrc32c ufs qnx4 hfsplus hfs minix ntfs vfat msdos fat jfs xfs 
exportfs reiserfs ppdev snd_hda_codec_hdmi snd_hda_codec_via 
snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_seq_midi snd_rawmidi 
snd_seq_midi_event lm78 hwmon_vid snd_seq snd_timer snd_seq_device i915 
drm_kms_helper psmouse drm i2c_algo_bit snd video soundcore 
snd_page_alloc serio_raw lp parport intel_ips usbhid hid firewire_ohci 
e1000e firewire_core crc_itu_t
[ 1414.833725]
[ 1414.833744] Pid: 28764, comm: insmod Not tainted 2.6.38-13-generic 
#54~lucid1-Ubuntu To be filled by O.E.M. To be filled by O.E.M./To be 
filled by O.E.M.
[ 1414.833877] RIP: 0010:[a00300e4]  [a00300e4] 
jwnf98_gpio_init+0xe4/0x1000 [gpio_jwnf98]
[ 1414.833965] RSP: 0018:880208adbf18  EFLAGS: 00010206
[ 1414.834011] RAX: 8801e8e8f900 RBX: a04cf080 RCX: 
8801e8e8f328
[ 1414.834071] RDX: 0538 RSI: 0538 RDI: 
81a19438
[ 1414.834131] RBP: 880208adbf18 R08:  R09: 
8801e8e8f900
[ 1414.834191] R10: 0004 R11: 0001 R12: 

[ 1414.834251] R13: a003 R14: 0003 R15: 
4000
[ 1414.834312] FS:  7fbb2f5a5700() GS:8800cb38() 
knlGS:
[ 1414.834380] CS:  0010 DS:  ES:  CR0: 80050033
[ 1414.834430] CR2: 0502 CR3: 0002089b2000 CR4: 
06e0
[ 1414.834490] DR0:  DR1:  DR2: 

[ 1414.834549] DR3:  DR6: 0ff0 DR7: 
0400
[ 1414.834610] Process insmod (pid: 28764, threadinfo 880208ada000, 
task 88021bad16e0)
[ 1414.834678] Stack:
[ 1414.834698]  880208adbf48 81002053 a04cf080 

[ 1414.834775]  024a7010 0003 880208adbf78 
810a3d4b
[ 1414.834851]  7fff75d0d9da 7fff75d0d9da 024a7030 
19db
[ 1414.834927] Call Trace:
[ 1414.834958]  [81002053] do_one_initcall+0x43/0x190
[ 1414.835011]  [810a3d4b] sys_init_module+0xfb/0x250
[ 1414.835062]  [8100c082] system_call_fastpath+0x16/0x1b
[ 1414.835114] Code: c7 c7 c0 93 a1 81 e8 5c d8 03 e1 45 31 c0 48 c7 c1 
24 e0 4c a0 ba 01 00 00 00 be 38 05 00 00 48 c7 c7 c0 93 a1 81 e8 3c d8 
03 e1 8a 04 25 02 05 00 00 48 c7 c7 00 f0 4c a0 83 c8 20 88 04 25 02
[ 1414.842138] RIP  [a00300e4] jwnf98_gpio_init+0xe4/0x1000 
[gpio_jwnf98]
[ 1414.845597]  RSP 880208adbf18
[ 1414.849064] CR2: 0502
[ 1414.921662] ---[ end trace d6d694e0e28fc4ad ]---

I am not aware of any pointer dereference in the code, so it is dificult 
to me
to figure out what is wrong.

Fortunately, the system does not become unresponsive (what a nice 
kernel!!!).
The gpio_jwnf98 is listed in lsmod,
but no chip directory appears under /sys/class/gpio.

Finally, the module can not be removed, rmmod outputs:

ERROR: Module gpio_jwnf98 is in use

Thanks again for all the help.

-- 
Joan Pau Beltran


___
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies


Re: GPIO driver module for Jetway NF98 board

2012-01-18 Thread Joan Pau Beltran
  instead of being static? How? NOT NEEDED.
- Disable gpio function for each pin? DONE.
- Something else?
*/
uint8_t byte;
byte = inb(PIN0_FUNCTION);
byte = ~(1  PIN0_BIT);
outb(byte, add);
byte = inb(PINX_FUNCTION);
byte = 1;
outb(byte, add);
release_region(PIN0_FUNCTION,  1);
release_region(PIN0_DIRECTION, 1);
release_region(PIN0_STATUS,1);
release_region(PIN0_BIT,   1);
release_region(PINX_FUNCTION,  1);
release_region(PINX_DIRECTION, 1);
release_region(PINX_STATUS,1);
}

module_init(jwnf98_gpio_init);
module_exit(jwnf98_gpio_exit);

MODULE_DESCRIPTION(Jetway NF98 GPIO driver);
MODULE_LICENSE(GPL);


As suggested, an alternative of the #define GPIO_BASE will be to try 
this code

in the init function:

/* Needed macros. */
/* Vendor and device IDs of LPC device. */
#define LPC_VENDOR_ID 0x8086
#define LPC_DEVICE_ID 0x5031
/* Offset into low pin count (LPC) config space of the GPIO base 
address. */

#define GPIO_BAR_OFFSET 0x48
#define GPIO_BAR_BITMASK 0xff80

/* Code in the init function */
struct pci_dev *pdev = NULL;
/* Get dev struct for the LPC device. */
/* The GPIO BAR is located in the LPC device config space. */
pdev = pci_get_device(LPC_VENDOR_ID, LPC_DEVICE_ID, NULL);
/* Get base address from the LPC configuration space. */
/* Where shoud we store this address? In a static global variable?
unsigned int gpio_base;
pci_read_config_dword(pdev, GPIO_BAR_OFFSET, gpio_base);
/* Clear all but address bits. */
gpio_base = GPIO_BAR_BITMASK;
/* release reference to device */
pci_dev_put(pdev);

--
Joan Pau Beltran


___
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies


Re: GPIO driver module for Jetway NF98 board

2012-01-18 Thread Joan Pau Beltran
 that?
 */
}

module_init(jwnf98_gpio_init);
module_exit(jwnf98_gpio_exit);

MODULE_DESCRIPTION(Jetway NF98 GPIO driver);
MODULE_LICENSE(GPL);

-- 
Joan Pau Beltran


___
Kernelnewbies mailing list
Kernelnewbies@kernelnewbies.org
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies


Re: GPIO driver module for Jetway NF98 board

2011-12-28 Thread Joan Pau Beltran
Thank you very much for your response.
It brings up a lot of useful information.

Al 22/12/11 01:15, En/na Josh Cartwright ha escrit:
 On Wed, Dec 21, 2011 at 06:34:58PM +0100, Joan Pau Beltran wrote:
 Hi everyone,

 I did not find any existing driver for the GPIO port of the Jetway
 NF98 mini-itx board, so I would like to write a module for that,
 using the gpiolib interface.

 Since the board documentation does not include any information about
 the GPIOs, I contacted the Jetway support team. However, the only
 answer was the attached code for Windows (NF98GPIO.c).
 As you can see, it seems clear how to set the pin states for output,
 but not how to read them in input mode. I asked again and the
 response was (literally):
 input sample code:
 {
 data= ISA_RW(GPIO_BASE[pin]+0x2,highlowpin,1,~(1pin));
 }
 //final exit SIO
 outp(INDEX_PORT,0xaa);
 return data;
 It makes no sense, and it is very upsetting.
 I would try to read from the same address used for output, but this
 is just an idea to be tested.
 I think you're on the right track. In researching this board a little
 more, I was able to uncover some information.  For the sake of
 learning, I've included my steps to discovery here:

  From Jetway's website (http://www.jetwaycomputer.com/NF98.html), I found
 that the chipset used in the board is an Intel QM57.

 Searching for datasheets for the Intel QM57 brought me to Intel's site
 (http://www.intel.com/content/www/us/en/chipsets/5-chipset-3400-chipset-datasheet.html).
 Searching the document for GPIO, I found section 5.15.4, GPIO Registers
 Lockdown.  The content of the text portion of the section didn't seem
 all that relevant, but there is a description of a register set that
 seems to match up with the values in your attached example:

Relevant information also appears in sections:
13.1.14 GPIOBASE—GPIO Base Address Register (LPC I/F—D31:F0)
13.1.15 GC—GPIO Control Register (LPC I/F—D31:F0)
13.10 General Purpose I/O Registers
Where the functionality of each register is described in detail.
 Searching for the symbolic names brings up this document, which looks
 like it may describe in more detail how to use this GPIO interface:

 http://download.intel.com/embedded/chipsets/appnote/322174.pdf


After looking at both documents, can you please confirm these ideas:
1.- The GPIO functionality of the jwnf98 comes from a hardware device in 
the chipset called LPC (Low Pin Cout) controller managed through the LPC 
Interface Bridge registers (section 9.1 page 366). This LPC controller 
provides other functionalities, too.
2.- The LPC resides in a PCI bus.
3.- GPIO is managed accessing the registers of the LPC. We should read 
from and write to these registers according to the notes in 13.10 
(GPIO_USE_SEL, GPIO_IO_SEL and GPIO_LVL). Not all the GPIOs are 
available, only the ones given in the Jetway code.
4.- The GPIO registers of the LPC are mapped to some I/O port, starting 
at the address specified in the GPIOBASE register. From the first 
paragraph in section 13.10, page 546:
 The control for the general purpose I/O signals is handled through a 
 128-byte I/O
 space. The base offset for this space is selected by the GPIOBASE 
 register.
5.- From Jetway code, it seems that the base address in the GPIOBASE 
register described in 13.1.14 is set by the manufacturer to 0x500. 
Conversely, the Intel code gets that base address reading the GPIOBASE 
register. Note that specific pci functions are used for that. If Tech 
Support info is ok, I do not need to do that, and can simply request the 
needed i/o ports taking as base offset 0x500.

If the above points are ok, I have some doubts related with my previous 
questions:
 1. How should I request/release the ports mentioned in the attached
 file? Should I use the request_region/release_region functions from
 linux/ioport.h? In such case, what should I do with the returned
 struct resource?
I think I should userequest_region/release_region from linux/ioport.h, 
and simply ignore the returned resource, is it ok?

 3. Should/could I use the test_bit, set_bit, clear_bit functions to
 get, set the bit in the needed read/write functions I am writing? Or
 should I use the sequence 'inb - mask the value properly - outb' ?
 Nope, as far as I know these bitops only work with memory operands.
Is this because we use port-based i/o instead of memory-mapped i/o?

Here it goes the code again.
The main question is, should the gpio_chip be statically allocated, or 
it should be created in the init function and destroyed in the exit 
function? If the latter, how to do that?

Thank you very much!

#include linux/module.h
#include linux/types.h
#include asm-generic/io.h

#define GPIO_BASE 0x500;

/* pin 0 (GPIO 21) is controlled by an specific bit of a different set 
of ports: */
#define PIN0_FUNCTION GPIO_BASE + 0x2;
#define PIN0_DIRECTION GPIO_BASE + 0x6;
#define PIN0_STATUS GPIO_BASE + 0xE;
#define PIN0_BIT 5;

/* pins 1 to 7 (GPIO 33 to 39) correspond to the respective bit

GPIO driver module for Jetway NF98 board

2011-12-21 Thread Joan Pau Beltran

Hi everyone,

I did not find any existing driver for the GPIO port of the Jetway NF98 
mini-itx board, so I would like to write a module for that, using the 
gpiolib interface.


Since the board documentation does not include any information about the 
GPIOs, I contacted the Jetway support team. However, the only answer was 
the attached code for Windows (NF98GPIO.c).
As you can see, it seems clear how to set the pin states for output, but 
not how to read them in input mode. I asked again and the response was 
(literally):

input sample code:
{
data= ISA_RW(GPIO_BASE[pin]+0x2,highlowpin,1,~(1pin));
}
//final exit SIO
outp(INDEX_PORT,0xaa);
return data;

It makes no sense, and it is very upsetting.
I would try to read from the same address used for output, but this is 
just an idea to be tested.


Since I have not written any kernel module before, after reading the 
pertinent documentation about memory management, i/o port access, and 
gpiolib, I have some questions.


1. How should I request/release the ports mentioned in the attached 
file? Should I use the request_region/release_region functions from 
linux/ioport.h? In such case, what should I do with the returned struct 
resource?


2. I suppose that I should use the same addresses given by the support 
team, although their code is for windows. Is it ok?


3. Should/could I use the test_bit, set_bit, clear_bit functions to get, 
set the bit in the needed read/write functions I am writing? Or should I 
use the sequence 'inb - mask the value properly - outb' ?



The second file attached is an skeleton of the module I am trying to 
write, any comments or suggestions are welcome.


Thanks in advance!

--
Joan Pau Beltran

#include linux/module.h
#include linux/types.h
#include asm-generic/io.h

#define GPIO_BASE 0x500;

// pin 0 (GPIO 21) is controlled by an specific bit of a different set of ports:
#define PIN0_FUNCTION  GPIO_BASE + 0x2;
#define PIN0_DIRECTION GPIO_BASE + 0x6;
#define PIN0_STATUSGPIO_BASE + 0xE;
#define PIN0_BIT   5;

  // pins 1 to 7 (GPIO 33 to 39) correspond to the respective bit on these ports
#define PINX_FUNCTION  GPIO_BASE + 0x30;
#define PINX_DIRECTION GPIO_BASE + 0x34;
#define PINX_STATUSGPIO_BASE + 0x38;


static int jwnf98_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
	unsigned long dir_add;
	unsigned bit_off;
	u8 byte;
	if (off)
	{
		dir_add = PINX_DIRECTION;
		bit_off = off;
	}
	else
	{
		dir_add = PIN0_DIRECTION;
		bit_off = PIN0_BIT;
	}
	byte = inb(dir_add);
	byte |= (1  bit_off);
	outb(byte, dir_add);
}

static int jwnf98_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val)
{
	unsigned long dir_add;
	unsigned long val_add;
	unsigned bit_off;
	u8 byte;
	if (off)
	{
		dir_add = PINX_DIRECTION;
		val_add = PINX_STATUS;
		bit_off = off;
	}
	else
	{
		dir_add = PIN0_DIRECTION;
		val_add = PIN0_STATUS;
		bit_off = PIN0_BIT;
	}
	byte = inb(dir_add);
	byte = ~(1  bit_off);
	outb(byte, dir_add);
	if (val)
	{
		byte = inb(val_add);
		byte |= (1  bit_off);
		outb(byte, val_add);
	}
	else
	{
		byte = inb(val_add);
		byte |= (1  bit_off);
		outb(byte, val_add);
	}
}

static int jwnf98_gpio_get(struct gpio_chip *gc, unsigned off)
{
/* 
  Nothing here, waiting for support team answer.
  Maybe read from the same address than output?
*/
}

static void jwnf98_gpio_set(struct gpio_chip *gc, unsigned off, int val)
{
	unsigned long add;
	unsigned bit;
	u8 byte;
	if (off)
	{
		add = PINX_STATUS;
		bit = off;
	}
	else
	{
		add = PIN0_STATUS;
		bit = PIN0_BIT;
	}
	byte = inb(add);
	if (val)
		byte |= (1  bit);
	else
		byte = ~(1  bit);
	outb(byte, add);
}

static struct gpio_chip gpio_pins = {
	.label = jwnf98,
	.owner = THIS_MODULE,
	.direction_input  = jwnf98_gpio_direction_input,
	.get = jwnf98_gpio_get,
	.direction_output = jwnf98_gpio_direction_output,
	.set = jwnf98_gpio_set,
	.dbg_show = jwnf98_gpio_dbg_show,
	.can_sleep = 0,
};

static int __init jwnf98_gpio_init(void)
{
	/* 
	Do preliminar work here:
		- Request ports?
		- Create the chip here instead of let it be static? How?
		- Something else?
	*/
}

static void __exit jwnf98_gpio_exit(void)
{
	/* 
	Do cleanup work here:
		- Release ports?
		- Delete the chip if it was created on init function 
		  instead of being static? How?
		- Something else?
	*/
}

module_init(jwnf98_gpio_init);
module_exit(jwnf98_gpio_exit);

MODULE_DESCRIPTION(Jetway NF98 GPIO driver);
MODULE_LICENSE(GPL);
/* GPIO_CON
    _ _ _ 
GPIO21 --|1	  2|--GPIO36
GPIO33 --|3		4|--GPIO37
GPIO34 --|5   6|--GPIO38
GPIO35 --|7		8|--GPIO39
			-|9	 10|--OVCC
			|		  - - -			|	
			
GPIO21 GPIO_Base + offset_2_bit_5 Set 1 For Gpio Funtion
   GPIO_Base + offset_6_bit_5 Set 0/1 For Output/input	
   GPIO_Base + offset_E_bit_5 Set 0/1 For Low/High Only in Output Mode
   
GPIO32+n GPIO_Base + offset_30_bit_(1+n) Set 1 For Gpio Function  
   	 GPIO_Base