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



Al 29/12/11 18:53, En/na Josh Cartwright ha escrit:

 I'd recommend getting the base address of the GPIO region as documented
 in the Intel manuals, instead of what looks like throw-away testing code
 from your vendor.

 Take a peak at drivers/watchdog/iTCO_wdt.c, as this watchdog timer is
 also accessed through the LPC device. It might give you a few ideas.


I inspected the file, but did not understand how to relate that code to 
my case.




 Yes, precisely. I'd recommend just using standard shift/masking (which
 looks like what you are already doing). Keep in mind, however,
 you'll need some locking strategy to ensure that a read-modify-write
 cycle happens atomically.


Is the blocking really needed, given the fact that the region is already 
requested?

I expected that requesting the region prevents interferences like that.
If not, how should I do that?



 While I appreciate it being inlined this time, your mailer seemed to
 have munged whitespace, such that the code is very difficult to read :(.
 You may want to see Documentation/email-clients.txt


Really sorry, here it goes again, hoping it is ok this time.

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

/* TODO: Look how to get the GPIO base address from the LPC interface.*/
#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;
uint8_t 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;
uint8_t 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)
{
unsigned long add;
unsigned bit;
uint8_t byte;
if (off)
{
add = PINX_STATUS;
bit = off;
}
else
{
add = PIN0_STATUS;
bit = PIN0_BIT;
}
byte = inb(add);
byte = (1  bit);
return !!byte; /* Is the double negation !! needed? */
}

static void jwnf98_gpio_set(struct gpio_chip *gc, unsigned off, int val)
{
unsigned long add;
unsigned bit;
uint8_t 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_gpio,
.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? DONE.
- Create the chip here instead of let it be static? How? NOT 
NEEDED.

- Enable gpio function for each pin? DONE.
- Something else?
*/
uint8_t byte;
request_region(PIN0_FUNCTION,  1, jwnf98_gpio);
request_region(PIN0_DIRECTION, 1, jwnf98_gpio);
request_region(PIN0_STATUS,1, jwnf98_gpio);
request_region(PIN0_BIT,   1, jwnf98_gpio);
request_region(PINX_FUNCTION,  1, jwnf98_gpio);
request_region(PINX_DIRECTION, 1, jwnf98_gpio);
request_region(PINX_STATUS,1, jwnf98_gpio);
/*
Should we check that the requested memory is available? How?
*/
byte = inb(PIN0_FUNCTION);
byte |= (1  PIN0_BIT);
outb(byte, add);
byte = inb(PINX_FUNCTION);
byte |= ~1;
outb(byte, add);
}

static void __exit jwnf98_gpio_exit(void)
{
/*
Do cleanup work here:
- Release ports? DONE.
- Delete the chip if it was created on init function
  

Re: GPIO driver module for Jetway NF98 board

2012-01-18 Thread Joan Pau Beltran

Sorry for the noise, but the last code was from a primitive version with
several typos and errors. Sorry for the noise.

Here it goes the fixed code:

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


/* TODO: Look how to get the GPIO base address from the LPC interface.*/
#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;
 uint8_t 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);
 return 0;
}

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;
 uint8_t 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);
 }
 return 0;
}

static int jwnf98_gpio_get(struct gpio_chip *gc, unsigned off)
{
 unsigned long add;
 unsigned bit;
 uint8_t byte;
 if (off)
 {
 add = PINX_STATUS;
 bit = off;
 }
 else
 {
 add = PIN0_STATUS;
 bit = PIN0_BIT;
 }
 byte = inb(add);
 byte = (1  bit);
 return !!byte; /* Is the double negation !! needed? */
}

static void jwnf98_gpio_set(struct gpio_chip *gc, unsigned off, int val)
{
 unsigned long add;
 unsigned bit;
 uint8_t 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 jwnf98_gpio_chip = {
 .label = jwnf98_gpio,
 .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 = NULL,
 .can_sleep = 0,
};

static int __init jwnf98_gpio_init(void)
{
 /*
 Do preliminar work here:
 - Request ports? DONE.
 - Create the chip here instead of let it be static? How? NOT 
NEEDED.
 - Enable gpio function for each pin? DONE.
 - Something else?
 */
 uint8_t byte;
 request_region(PIN0_FUNCTION,  1, jwnf98_gpio);
 request_region(PIN0_DIRECTION, 1, jwnf98_gpio);
 request_region(PIN0_STATUS,1, jwnf98_gpio);
 request_region(PIN0_BIT,   1, jwnf98_gpio);
 request_region(PINX_FUNCTION,  1, jwnf98_gpio);
 request_region(PINX_DIRECTION, 1, jwnf98_gpio);
 request_region(PINX_STATUS,1, jwnf98_gpio);
 /*
 Should we check that the requested memory is available? How?
 */
 byte = inb(PIN0_FUNCTION);
 byte |= (1  PIN0_BIT);
 outb(byte, PIN0_FUNCTION);
 byte = inb(PINX_FUNCTION);
 byte |= ~1;
 outb(byte, PINX_FUNCTION);
 /*
 Should we add the gpio_chip here with gpiochip_add?
 */
 return gpiochip_add(jwnf98_gpio_chip);
}

static void __exit jwnf98_gpio_exit(void)
{
 /*
 Do cleanup work here:
 - Release ports? DONE.
 - Delete the chip if it was created on init function
   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, PIN0_FUNCTION);
 byte = inb(PINX_FUNCTION);
 byte = 1;
 outb(byte, PIN0_FUNCTION);
 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);
 /*
 Should we remove the gpio_chip here? How to do that?
 */
}

Re: GPIO driver module for Jetway NF98 board

2011-12-29 Thread Josh Cartwright
On Wed, Dec 28, 2011 at 06:03:32PM +0100, Joan Pau Beltran wrote:
 Thank you very much for your response.
 It brings up a lot of useful information.

Great, glad it helped!

*snip*

 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:
  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.

Yes, that is how I understand it, too.

 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.

I'd recommend getting the base address of the GPIO region as documented
in the Intel manuals, instead of what looks like throw-away testing code
from your vendor.

Take a peak at drivers/watchdog/iTCO_wdt.c, as this watchdog timer is
also accessed through the LPC device.  It might give you a few ideas.

 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?

I think that would be fine (there are other drivers that currently do
this).

   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?

Yes, precisely.  I'd recommend just using standard shift/masking (which
looks like what you are already doing).  Keep in mind, however,
you'll need some locking strategy to ensure that a read-modify-write
cycle happens atomically.

 Here it goes the code again.

While I appreciate it being inlined this time, your mailer seemed to
have munged whitespace, such that the code is very difficult to read :(.
You may want to see Documentation/email-clients.txt.

 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?

Having one statically allocated gpio_chip object assumes that there will
be only one of these chips installed in a system.  I think that is a
safe assumption to make, so you should be okay.

-- 
 joshc

___
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 on 

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 + 

Re: GPIO driver module for Jetway NF98 board

2011-12-21 Thread Josh Cartwright
(resend, sorry for spam)

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:

   00h: GPIO_USE_SEL[31:0]
   04h: GP_IO_SEL[31:0]
   0Ch: GP_LVL[31:0]
   28h: GPI_NMI_EN[15:0]
   2Ch: GPI_INV[31:0]
   30h: GPIO_USE_SEL2[63:32]
   34h: GPI_IO_SEL2[63:32]
   38h: GP_LVL2[63:32]
   40h: GPIO_USE_SEL3[95:64]
   44h: GPI_IO_SEL3[95:64]
   48h: GP_LVL3[95:64]
   60h: GP_RST_SEL[31:0]
   64h: GP_RST_SEL2[63:32]
   68h: GP_RST_SEL3[95:64]

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

 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?

The above document seemed to insinuate that the actual IO region used
for GPIO access isn't statically allocated, but rather allocated during
PCI enumeration for a LPC device.  If this is the case, you have an
additional question you need answered:

   - What is the best way to get the base address for accessing these
 GPIOs?

(the example code provided in the above document uses pci_get_device
which sounds clunky...)

Actually, with some further grepping I found that a lot of this
infrastructure may already be available to you.  See
drivers/mfd/lpc_sch.c and drivers/gpio/sch_gpio.c.  Not sure what it
would take to get it working with your setup, but it should give you a
good starting point.

 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.

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

(in the future, please inline any code you'd like reviewed)

Good luck!

-- 
   joshc

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