<!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;">&gt; I'd recommend getting the base
      address of the GPIO region as documented<br>
      &gt; in the Intel manuals, instead of what looks like throw-away
      testing code<br>
      &gt; from your vendor.<br>
      &gt;<br>
      &gt; Take a peak at drivers/watchdog/iTCO_wdt.c, as this watchdog
      timer is<br>
      &gt; 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;">&gt; Yes, precisely. I'd recommend
      just using standard shift/masking (which<br>
      &gt; looks like what you are already doing). Keep in mind,
      however,<br>
      &gt; you'll need some locking strategy to ensure that a
      read-modify-write<br>
      &gt; 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;">&gt; While I appreciate it being
      inlined this time, your mailer seemed to<br>
      &gt; have munged whitespace, such that the code is very difficult
      to read :(.<br>
      &gt; 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 &lt;linux/module.h&gt;<br>
    #include &lt;linux/types.h&gt;<br>
    #include &lt;asm-generic/io.h&gt;<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&nbsp; GPIO_BASE + 0x2;<br>
    #define PIN0_DIRECTION GPIO_BASE + 0x6;<br>
    #define PIN0_STATUS&nbsp;&nbsp;&nbsp; GPIO_BASE + 0xE;<br>
    #define PIN0_BIT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5;<br>
    <br>
    /* pins 1 to 7 (GPIO 33 to 39) correspond to the respective bit on
    these ports */<br>
    #define PINX_FUNCTION&nbsp; GPIO_BASE + 0x30;<br>
    #define PINX_DIRECTION GPIO_BASE + 0x34;<br>
    #define PINX_STATUS&nbsp;&nbsp;&nbsp; GPIO_BASE + 0x38;<br>
    <br>
    <br>
    static int jwnf98_gpio_direction_input(struct gpio_chip *gc,
    unsigned off)<br>
    {<br>
    &nbsp;&nbsp;&nbsp; unsigned long dir_add;<br>
    &nbsp;&nbsp;&nbsp; unsigned bit_off;<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; if (off)<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir_add = PINX_DIRECTION;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit_off = off;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir_add = PIN0_DIRECTION;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit_off = PIN0_BIT;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; byte = inb(dir_add);<br>
    &nbsp;&nbsp;&nbsp; byte |= (1 &lt;&lt; bit_off);<br>
    &nbsp;&nbsp;&nbsp; outb(byte, dir_add);<br>
    }<br>
    <br>
    static int jwnf98_gpio_direction_output(struct gpio_chip *gc,
    unsigned off, int val)<br>
    {<br>
    &nbsp;&nbsp;&nbsp; unsigned long dir_add;<br>
    &nbsp;&nbsp;&nbsp; unsigned long val_add;<br>
    &nbsp;&nbsp;&nbsp; unsigned bit_off;<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; if (off)<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir_add = PINX_DIRECTION;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val_add = PINX_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit_off = off;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir_add = PIN0_DIRECTION;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val_add = PIN0_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit_off = PIN0_BIT;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; byte = inb(dir_add);<br>
    &nbsp;&nbsp;&nbsp; byte &amp;= ~(1 &lt;&lt; bit_off);<br>
    &nbsp;&nbsp;&nbsp; outb(byte, dir_add);<br>
    &nbsp;&nbsp;&nbsp; if (val)<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte = inb(val_add);<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte |= (1 &lt;&lt; bit_off);<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outb(byte, val_add);<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte = inb(val_add);<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte &amp;= ~(1 &lt;&lt; bit_off);<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; outb(byte, val_add);<br>
    &nbsp;&nbsp;&nbsp; }<br>
    }<br>
    <br>
    static int jwnf98_gpio_get(struct gpio_chip *gc, unsigned off)<br>
    {<br>
    &nbsp;&nbsp;&nbsp; unsigned long add;<br>
    &nbsp;&nbsp;&nbsp; unsigned bit;<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; if (off)<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add = PINX_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit = off;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add = PIN0_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit = PIN0_BIT;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; byte = inb(add);<br>
    &nbsp;&nbsp;&nbsp; byte &amp;= (1 &lt;&lt; bit);<br>
    &nbsp;&nbsp;&nbsp; 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>
    &nbsp;&nbsp;&nbsp; unsigned long add;<br>
    &nbsp;&nbsp;&nbsp; unsigned bit;<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; if (off)<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add = PINX_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit = off;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp; {<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add = PIN0_STATUS;<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit = PIN0_BIT;<br>
    &nbsp;&nbsp;&nbsp; }<br>
    &nbsp;&nbsp;&nbsp; byte = inb(add);<br>
    &nbsp;&nbsp;&nbsp; if (val)<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte |= (1 &lt;&lt; bit);<br>
    &nbsp;&nbsp;&nbsp; else<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; byte &amp;= ~(1 &lt;&lt; bit);<br>
    &nbsp;&nbsp;&nbsp; outb(byte, add);<br>
    }<br>
    <br>
    static struct gpio_chip gpio_pins = {<br>
    &nbsp;&nbsp;&nbsp; .label = "jwnf98_gpio",<br>
    &nbsp;&nbsp;&nbsp; .owner = THIS_MODULE,<br>
    &nbsp;&nbsp;&nbsp; .direction_input&nbsp; = jwnf98_gpio_direction_input,<br>
    &nbsp;&nbsp;&nbsp; .get = jwnf98_gpio_get,<br>
    &nbsp;&nbsp;&nbsp; .direction_output = jwnf98_gpio_direction_output,<br>
    &nbsp;&nbsp;&nbsp; .set = jwnf98_gpio_set,<br>
    &nbsp;&nbsp;&nbsp; .dbg_show = jwnf98_gpio_dbg_show,<br>
    &nbsp;&nbsp;&nbsp; .can_sleep = 0,<br>
    };<br>
    <br>
    static int __init jwnf98_gpio_init(void)<br>
    {<br>
    &nbsp;&nbsp;&nbsp; /*<br>
    &nbsp;&nbsp;&nbsp; Do preliminar work here:<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Request ports? DONE.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Create the chip here instead of let it be static? How? NOT
    NEEDED.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Enable gpio function for each pin? DONE.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Something else?<br>
    &nbsp;&nbsp;&nbsp; */<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; request_region(PIN0_FUNCTION,&nbsp; 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PIN0_DIRECTION, 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PIN0_STATUS,&nbsp;&nbsp;&nbsp; 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PIN0_BIT,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PINX_FUNCTION,&nbsp; 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PINX_DIRECTION, 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; request_region(PINX_STATUS,&nbsp;&nbsp;&nbsp; 1, "jwnf98_gpio");<br>
    &nbsp;&nbsp;&nbsp; /*<br>
    &nbsp;&nbsp;&nbsp; Should we check that the requested memory is available? How?<br>
    &nbsp;&nbsp;&nbsp; */<br>
    &nbsp;&nbsp;&nbsp; byte = inb(PIN0_FUNCTION);<br>
    &nbsp;&nbsp;&nbsp; byte |= (1 &lt;&lt; PIN0_BIT);<br>
    &nbsp;&nbsp;&nbsp; outb(byte, add);<br>
    &nbsp;&nbsp;&nbsp; byte = inb(PINX_FUNCTION);<br>
    &nbsp;&nbsp;&nbsp; byte |= ~1;<br>
    &nbsp;&nbsp;&nbsp; outb(byte, add);<br>
    }<br>
    <br>
    static void __exit jwnf98_gpio_exit(void)<br>
    {<br>
    &nbsp;&nbsp;&nbsp; /*<br>
    &nbsp;&nbsp;&nbsp; Do cleanup work here:<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Release ports? DONE.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Delete the chip if it was created on init function<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; instead of being static? How? NOT NEEDED.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Disable gpio function for each pin? DONE.<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - Something else?<br>
    &nbsp;&nbsp;&nbsp; */<br>
    &nbsp;&nbsp;&nbsp; uint8_t byte;<br>
    &nbsp;&nbsp;&nbsp; byte = inb(PIN0_FUNCTION);<br>
    &nbsp;&nbsp;&nbsp; byte &amp;= ~(1 &lt;&lt; PIN0_BIT);<br>
    &nbsp;&nbsp;&nbsp; outb(byte, add);<br>
    &nbsp;&nbsp;&nbsp; byte = inb(PINX_FUNCTION);<br>
    &nbsp;&nbsp;&nbsp; byte &amp;= 1;<br>
    &nbsp;&nbsp;&nbsp; outb(byte, add);<br>
    &nbsp;&nbsp;&nbsp; release_region(PIN0_FUNCTION,&nbsp; 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PIN0_DIRECTION, 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PIN0_STATUS,&nbsp;&nbsp;&nbsp; 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PIN0_BIT,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PINX_FUNCTION,&nbsp; 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PINX_DIRECTION, 1);<br>
    &nbsp;&nbsp;&nbsp; release_region(PINX_STATUS,&nbsp;&nbsp;&nbsp; 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>
    &nbsp;&nbsp;&nbsp; /* Needed macros. */<br>
    &nbsp;&nbsp;&nbsp; /* Vendor and device IDs of LPC device. */<br>
    &nbsp;&nbsp;&nbsp; #define LPC_VENDOR_ID 0x8086<br>
    &nbsp;&nbsp;&nbsp; #define LPC_DEVICE_ID 0x5031<br>
    &nbsp;&nbsp;&nbsp; /* Offset into low pin count (LPC) config space of the GPIO base
    address. */<br>
    &nbsp;&nbsp;&nbsp; #define GPIO_BAR_OFFSET 0x48<br>
    &nbsp;&nbsp;&nbsp; #define GPIO_BAR_BITMASK 0x0000ff80<br>
    &nbsp; <br>
    &nbsp;&nbsp;&nbsp; /* Code in the init function */<br>
    &nbsp;&nbsp;&nbsp; struct pci_dev *pdev = NULL;<br>
    &nbsp;&nbsp;&nbsp; /* Get dev struct for the LPC device. */<br>
    &nbsp;&nbsp;&nbsp; /* The GPIO BAR is located in the LPC device config space. */<br>
    &nbsp;&nbsp;&nbsp; pdev = pci_get_device(LPC_VENDOR_ID, LPC_DEVICE_ID, NULL);<br>
    &nbsp;&nbsp;&nbsp; /* Get base address from the LPC configuration space. */<br>
    &nbsp;&nbsp;&nbsp; /* Where shoud we store this address? In a static global
    variable?<br>
    &nbsp;&nbsp;&nbsp; unsigned int gpio_base;<br>
    &nbsp;&nbsp;&nbsp; pci_read_config_dword(pdev, GPIO_BAR_OFFSET, gpio_base);<br>
    &nbsp;&nbsp;&nbsp; /* Clear all but address bits. */<br>
    &nbsp;&nbsp;&nbsp; gpio_base &amp;= GPIO_BAR_BITMASK;<br>
    &nbsp;&nbsp;&nbsp; /* release reference to device */<br>
    &nbsp;&nbsp;&nbsp; pci_dev_put(pdev);<br>
    &nbsp; <br>
    -- <br>
    Joan Pau Beltran<br>
    <br>
    <br>
  </body>
</html>