<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
<title></title>
</head>
<body text="#000000" bgcolor="#ffffff">
<br>
<br>
Al 29/12/11 18:53, En/na Josh Cartwright ha escrit:<br>
<span style="white-space: pre;">> I'd recommend getting the base
address of the GPIO region as documented<br>
> in the Intel manuals, instead of what looks like throw-away
testing code<br>
> from your vendor.<br>
><br>
> Take a peak at drivers/watchdog/iTCO_wdt.c, as this watchdog
timer is<br>
> also accessed through the LPC device. It might give you a few
ideas.</span><br>
<br>
I inspected the file, but did not understand how to relate that code
to my case.<br>
<br>
<br>
<span style="white-space: pre;">> Yes, precisely. I'd recommend
just using standard shift/masking (which<br>
> looks like what you are already doing). Keep in mind,
however,<br>
> you'll need some locking strategy to ensure that a
read-modify-write<br>
> cycle happens atomically.</span><br>
<br>
Is the blocking really needed, given the fact that the region is
already requested?<br>
I expected that requesting the region prevents interferences like
that.<br>
If not, how should I do that?<br>
<br>
<br>
<span style="white-space: pre;">> While I appreciate it being
inlined this time, your mailer seemed to<br>
> have munged whitespace, such that the code is very difficult
to read :(.<br>
> You may want to see Documentation/email-clients.txt</span><br>
<br>
Really sorry, here it goes again, hoping it is ok this time.<br>
<br>
#include <linux/module.h><br>
#include <linux/types.h><br>
#include <asm-generic/io.h><br>
<br>
/* TODO: Look how to get the GPIO base address from the LPC
interface.*/<br>
#define GPIO_BASE 0x500;<br>
<br>
/* pin 0 (GPIO 21) is controlled by an specific bit of a different
set of ports: */<br>
#define PIN0_FUNCTION GPIO_BASE + 0x2;<br>
#define PIN0_DIRECTION GPIO_BASE + 0x6;<br>
#define PIN0_STATUS GPIO_BASE + 0xE;<br>
#define PIN0_BIT 5;<br>
<br>
/* pins 1 to 7 (GPIO 33 to 39) correspond to the respective bit on
these ports */<br>
#define PINX_FUNCTION GPIO_BASE + 0x30;<br>
#define PINX_DIRECTION GPIO_BASE + 0x34;<br>
#define PINX_STATUS GPIO_BASE + 0x38;<br>
<br>
<br>
static int jwnf98_gpio_direction_input(struct gpio_chip *gc,
unsigned off)<br>
{<br>
unsigned long dir_add;<br>
unsigned bit_off;<br>
uint8_t byte;<br>
if (off)<br>
{<br>
dir_add = PINX_DIRECTION;<br>
bit_off = off;<br>
}<br>
else<br>
{<br>
dir_add = PIN0_DIRECTION;<br>
bit_off = PIN0_BIT;<br>
}<br>
byte = inb(dir_add);<br>
byte |= (1 << bit_off);<br>
outb(byte, dir_add);<br>
}<br>
<br>
static int jwnf98_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)<br>
{<br>
unsigned long dir_add;<br>
unsigned long val_add;<br>
unsigned bit_off;<br>
uint8_t byte;<br>
if (off)<br>
{<br>
dir_add = PINX_DIRECTION;<br>
val_add = PINX_STATUS;<br>
bit_off = off;<br>
}<br>
else<br>
{<br>
dir_add = PIN0_DIRECTION;<br>
val_add = PIN0_STATUS;<br>
bit_off = PIN0_BIT;<br>
}<br>
byte = inb(dir_add);<br>
byte &= ~(1 << bit_off);<br>
outb(byte, dir_add);<br>
if (val)<br>
{<br>
byte = inb(val_add);<br>
byte |= (1 << bit_off);<br>
outb(byte, val_add);<br>
}<br>
else<br>
{<br>
byte = inb(val_add);<br>
byte &= ~(1 << bit_off);<br>
outb(byte, val_add);<br>
}<br>
}<br>
<br>
static int jwnf98_gpio_get(struct gpio_chip *gc, unsigned off)<br>
{<br>
unsigned long add;<br>
unsigned bit;<br>
uint8_t byte;<br>
if (off)<br>
{<br>
add = PINX_STATUS;<br>
bit = off;<br>
}<br>
else<br>
{<br>
add = PIN0_STATUS;<br>
bit = PIN0_BIT;<br>
}<br>
byte = inb(add);<br>
byte &= (1 << bit);<br>
return !!byte; /* Is the double negation !! needed? */<br>
}<br>
<br>
static void jwnf98_gpio_set(struct gpio_chip *gc, unsigned off, int
val)<br>
{<br>
unsigned long add;<br>
unsigned bit;<br>
uint8_t byte;<br>
if (off)<br>
{<br>
add = PINX_STATUS;<br>
bit = off;<br>
}<br>
else<br>
{<br>
add = PIN0_STATUS;<br>
bit = PIN0_BIT;<br>
}<br>
byte = inb(add);<br>
if (val)<br>
byte |= (1 << bit);<br>
else<br>
byte &= ~(1 << bit);<br>
outb(byte, add);<br>
}<br>
<br>
static struct gpio_chip gpio_pins = {<br>
.label = "jwnf98_gpio",<br>
.owner = THIS_MODULE,<br>
.direction_input = jwnf98_gpio_direction_input,<br>
.get = jwnf98_gpio_get,<br>
.direction_output = jwnf98_gpio_direction_output,<br>
.set = jwnf98_gpio_set,<br>
.dbg_show = jwnf98_gpio_dbg_show,<br>
.can_sleep = 0,<br>
};<br>
<br>
static int __init jwnf98_gpio_init(void)<br>
{<br>
/*<br>
Do preliminar work here:<br>
- Request ports? DONE.<br>
- Create the chip here instead of let it be static? How? NOT
NEEDED.<br>
- Enable gpio function for each pin? DONE.<br>
- Something else?<br>
*/<br>
uint8_t byte;<br>
request_region(PIN0_FUNCTION, 1, "jwnf98_gpio");<br>
request_region(PIN0_DIRECTION, 1, "jwnf98_gpio");<br>
request_region(PIN0_STATUS, 1, "jwnf98_gpio");<br>
request_region(PIN0_BIT, 1, "jwnf98_gpio");<br>
request_region(PINX_FUNCTION, 1, "jwnf98_gpio");<br>
request_region(PINX_DIRECTION, 1, "jwnf98_gpio");<br>
request_region(PINX_STATUS, 1, "jwnf98_gpio");<br>
/*<br>
Should we check that the requested memory is available? How?<br>
*/<br>
byte = inb(PIN0_FUNCTION);<br>
byte |= (1 << PIN0_BIT);<br>
outb(byte, add);<br>
byte = inb(PINX_FUNCTION);<br>
byte |= ~1;<br>
outb(byte, add);<br>
}<br>
<br>
static void __exit jwnf98_gpio_exit(void)<br>
{<br>
/*<br>
Do cleanup work here:<br>
- Release ports? DONE.<br>
- Delete the chip if it was created on init function<br>
instead of being static? How? NOT NEEDED.<br>
- Disable gpio function for each pin? DONE.<br>
- Something else?<br>
*/<br>
uint8_t byte;<br>
byte = inb(PIN0_FUNCTION);<br>
byte &= ~(1 << PIN0_BIT);<br>
outb(byte, add);<br>
byte = inb(PINX_FUNCTION);<br>
byte &= 1;<br>
outb(byte, add);<br>
release_region(PIN0_FUNCTION, 1);<br>
release_region(PIN0_DIRECTION, 1);<br>
release_region(PIN0_STATUS, 1);<br>
release_region(PIN0_BIT, 1);<br>
release_region(PINX_FUNCTION, 1);<br>
release_region(PINX_DIRECTION, 1);<br>
release_region(PINX_STATUS, 1);<br>
}<br>
<br>
module_init(jwnf98_gpio_init);<br>
module_exit(jwnf98_gpio_exit);<br>
<br>
MODULE_DESCRIPTION("Jetway NF98 GPIO driver");<br>
MODULE_LICENSE("GPL");<br>
<br>
<br>
As suggested, an alternative of the #define GPIO_BASE will be to try
this code<br>
in the init function:<br>
<br>
/* Needed macros. */<br>
/* Vendor and device IDs of LPC device. */<br>
#define LPC_VENDOR_ID 0x8086<br>
#define LPC_DEVICE_ID 0x5031<br>
/* Offset into low pin count (LPC) config space of the GPIO base
address. */<br>
#define GPIO_BAR_OFFSET 0x48<br>
#define GPIO_BAR_BITMASK 0x0000ff80<br>
<br>
/* Code in the init function */<br>
struct pci_dev *pdev = NULL;<br>
/* Get dev struct for the LPC device. */<br>
/* The GPIO BAR is located in the LPC device config space. */<br>
pdev = pci_get_device(LPC_VENDOR_ID, LPC_DEVICE_ID, NULL);<br>
/* Get base address from the LPC configuration space. */<br>
/* Where shoud we store this address? In a static global
variable?<br>
unsigned int gpio_base;<br>
pci_read_config_dword(pdev, GPIO_BAR_OFFSET, gpio_base);<br>
/* Clear all but address bits. */<br>
gpio_base &= GPIO_BAR_BITMASK;<br>
/* release reference to device */<br>
pci_dev_put(pdev);<br>
<br>
-- <br>
Joan Pau Beltran<br>
<br>
<br>
</body>
</html>