Re: GPIO driver module for Jetway NF98 board
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
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
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
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
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