From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- arch/cris/arch-v10/kernel/io_interface_mux.c | 1182 ++++++++++++++++++++++++++ 1 file changed, 1182 insertions(+) create mode 100644 arch/cris/arch-v10/kernel/io_interface_mux.c (limited to 'arch/cris/arch-v10/kernel/io_interface_mux.c') diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c new file mode 100644 index 000000000..ad64cd1c8 --- /dev/null +++ b/arch/cris/arch-v10/kernel/io_interface_mux.c @@ -0,0 +1,1182 @@ +/* IO interface mux allocator for ETRAX100LX. + * Copyright 2004-2007, Axis Communications AB + */ + + +/* C.f. ETRAX100LX Designer's Reference chapter 19.9 */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define DBG(s) + +/* Macro to access ETRAX 100 registers */ +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) + +enum io_if_group { + group_a = (1<<0), + group_b = (1<<1), + group_c = (1<<2), + group_d = (1<<3), + group_e = (1<<4), + group_f = (1<<5) +}; + +struct watcher +{ + void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available); + struct watcher *next; +}; + + +struct if_group +{ + enum io_if_group group; + /* name - the name of the group 'A' to 'F' */ + char *name; + /* used - a bit mask of all pins in the group in the order listed + * in the tables in 19.9.1 to 19.9.6. Note that no + * distinction is made between in, out and in/out pins. */ + unsigned int used; +}; + + +struct interface +{ + enum cris_io_interface ioif; + /* name - the name of the interface */ + char *name; + /* groups - OR'ed together io_if_group flags describing what pin groups + * the interface uses pins in. */ + unsigned char groups; + /* used - set when the interface is allocated. */ + unsigned char used; + char *owner; + /* group_a through group_f - bit masks describing what pins in the + * pin groups the interface uses. */ + unsigned int group_a; + unsigned int group_b; + unsigned int group_c; + unsigned int group_d; + unsigned int group_e; + unsigned int group_f; + + /* gpio_g_in, gpio_g_out, gpio_b - bit masks telling what pins in the + * GPIO ports the interface uses. This could be reconstucted using + * the group_X masks and a table of what pins the GPIO ports use, + * but that would be messy. */ + unsigned int gpio_g_in; + unsigned int gpio_g_out; + unsigned char gpio_b; +}; + +static struct if_group if_groups[6] = { + { + .group = group_a, + .name = "A", + .used = 0, + }, + { + .group = group_b, + .name = "B", + .used = 0, + }, + { + .group = group_c, + .name = "C", + .used = 0, + }, + { + .group = group_d, + .name = "D", + .used = 0, + }, + { + .group = group_e, + .name = "E", + .used = 0, + }, + { + .group = group_f, + .name = "F", + .used = 0, + } +}; + +/* The order in the array must match the order of enum + * cris_io_interface in io_interface_mux.h */ +static struct interface interfaces[] = { + /* Begin Non-multiplexed interfaces */ + { + .ioif = if_eth, + .name = "ethernet", + .groups = 0, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + { + .ioif = if_serial_0, + .name = "serial_0", + .groups = 0, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + /* End Non-multiplexed interfaces */ + { + .ioif = if_serial_1, + .name = "serial_1", + .groups = group_e, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0x0f, + .group_f = 0, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_2, + .name = "serial_2", + .groups = group_b, + + .group_a = 0, + .group_b = 0x0f, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_3, + .name = "serial_3", + .groups = group_c, + + .group_a = 0, + .group_b = 0, + .group_c = 0x0f, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_sync_serial_1, + .name = "sync_serial_1", + .groups = group_e | group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0x0f, + .group_f = 0x10, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x10 + }, + { + .ioif = if_sync_serial_3, + .name = "sync_serial_3", + .groups = group_c | group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0x0f, + .group_d = 0, + .group_e = 0, + .group_f = 0x80, + + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x80 + }, + { + .ioif = if_shared_ram, + .name = "shared_ram", + .groups = group_a, + + .group_a = 0x7f8ff, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff38, + .gpio_b = 0x00 + }, + { + .ioif = if_shared_ram_w, + .name = "shared_ram_w", + .groups = group_a | group_d, + + .group_a = 0x7f8ff, + .group_b = 0, + .group_c = 0, + .group_d = 0xff, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff38, + .gpio_b = 0x00 + }, + { + .ioif = if_par_0, + .name = "par_0", + .groups = group_a, + + .group_a = 0x7fbff, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_par_1, + .name = "par_1", + .groups = group_d, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0x7feff, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x3eff0000, + .gpio_g_out = 0x3eff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_par_w, + .name = "par_w", + .groups = group_a | group_d, + + .group_a = 0x7fbff, + .group_b = 0, + .group_c = 0, + .group_d = 0xff, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_scsi8_0, + .name = "scsi8_0", + .groups = group_a | group_b | group_f, + + .group_a = 0x7ffff, + .group_b = 0x0f, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0x10, + + .gpio_g_in = 0x0000ffff, + .gpio_g_out = 0x0000ffff, + .gpio_b = 0x10 + }, + { + .ioif = if_scsi8_1, + .name = "scsi8_1", + .groups = group_c | group_d | group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0x0f, + .group_d = 0x7ffff, + .group_e = 0, + .group_f = 0x80, + + .gpio_g_in = 0xffff0000, + .gpio_g_out = 0xffff0000, + .gpio_b = 0x80 + }, + { + .ioif = if_scsi_w, + .name = "scsi_w", + .groups = group_a | group_b | group_d | group_f, + + .group_a = 0x7ffff, + .group_b = 0x0f, + .group_c = 0, + .group_d = 0x601ff, + .group_e = 0, + .group_f = 0x90, + + .gpio_g_in = 0x01ffffff, + .gpio_g_out = 0x07ffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_ata, + .name = "ata", + .groups = group_a | group_b | group_c | group_d, + + .group_a = 0x7ffff, + .group_b = 0x0f, + .group_c = 0x0f, + .group_d = 0x7cfff, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0xf9ffffff, + .gpio_g_out = 0xffffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_csp, + .name = "csp", + .groups = group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0xfc, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xfc + }, + { + .ioif = if_i2c, + .name = "i2c", + .groups = group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0x03, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x03 + }, + { + .ioif = if_usb_1, + .name = "usb_1", + .groups = group_e | group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0x0f, + .group_f = 0x2c, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x2c + }, + { + .ioif = if_usb_2, + .name = "usb_2", + .groups = group_d, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0x33e00, + .group_f = 0, + + .gpio_g_in = 0x3e000000, + .gpio_g_out = 0x0c000000, + .gpio_b = 0x00 + }, + /* GPIO pins */ + { + .ioif = if_gpio_grp_a, + .name = "gpio_a", + .groups = group_a, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x0000ff3f, + .gpio_g_out = 0x0000ff3f, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_b, + .name = "gpio_b", + .groups = group_b, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_c, + .name = "gpio_c", + .groups = group_c, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_d, + .name = "gpio_d", + .groups = group_d, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x3fff0000, + .gpio_g_out = 0x3fff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_e, + .name = "gpio_e", + .groups = group_e, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_f, + .name = "gpio_f", + .groups = group_f, + + .group_a = 0, + .group_b = 0, + .group_c = 0, + .group_d = 0, + .group_e = 0, + .group_f = 0, + + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xff + } + /* Array end */ +}; + +static struct watcher *watchers = NULL; + +/* The pins that are free to use in the GPIO ports. */ +static unsigned int gpio_in_pins = 0xffffffff; +static unsigned int gpio_out_pins = 0xffffffff; +static unsigned char gpio_pb_pins = 0xff; +static unsigned char gpio_pa_pins = 0xff; + +/* Identifiers for the owners of the GPIO pins. */ +static enum cris_io_interface gpio_pa_owners[8]; +static enum cris_io_interface gpio_pb_owners[8]; +static enum cris_io_interface gpio_pg_owners[32]; + +static int cris_io_interface_init(void); + +static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group) +{ + return (groups & ~group->group); +} + + +static struct if_group *get_group(const unsigned char groups) +{ + int i; + for (i = 0; i < ARRAY_SIZE(if_groups); i++) { + if (groups & if_groups[i].group) { + return &if_groups[i]; + } + } + return NULL; +} + + +static void notify_watchers(void) +{ + struct watcher *w = watchers; + + DBG(printk("io_interface_mux: notifying watchers\n")); + + while (NULL != w) { + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + w = w->next; + } +} + + +int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id) +{ + int set_gen_config = 0; + int set_gen_config_ii = 0; + unsigned long int gens; + unsigned long int gens_ii; + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + int res = 0; + + (void)cris_io_interface_init(); + + DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id)); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_request_io_interface: Bad interface " + "%u submitted for %s\n", + ioif, + device_id); + return -EINVAL; + } + + local_irq_save(flags); + + if (interfaces[ioif].used) { + printk(KERN_CRIT "cris_io_interface: Cannot allocate interface " + "%s for %s, in use by %s\n", + interfaces[ioif].name, + device_id, + interfaces[ioif].owner); + res = -EBUSY; + goto exit; + } + + /* Check that all required pins in the used groups are free + * before allocating. */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + unsigned int if_group_use = 0; + + switch (grp->group) { + case group_a: + if_group_use = interfaces[ioif].group_a; + break; + case group_b: + if_group_use = interfaces[ioif].group_b; + break; + case group_c: + if_group_use = interfaces[ioif].group_c; + break; + case group_d: + if_group_use = interfaces[ioif].group_d; + break; + case group_e: + if_group_use = interfaces[ioif].group_e; + break; + case group_f: + if_group_use = interfaces[ioif].group_f; + break; + default: + BUG_ON(1); + } + + if (if_group_use & grp->used) { + printk(KERN_INFO "cris_request_io_interface: group " + "%s needed by %s not available\n", + grp->name, interfaces[ioif].name); + res = -EBUSY; + goto exit; + } + + group_set = clear_group_from_set(group_set, grp); + } + + /* Are the required GPIO pins available too? */ + if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != + interfaces[ioif].gpio_g_in) || + ((interfaces[ioif].gpio_g_out & gpio_out_pins) != + interfaces[ioif].gpio_g_out) || + ((interfaces[ioif].gpio_b & gpio_pb_pins) != + interfaces[ioif].gpio_b)) { + printk(KERN_CRIT "cris_request_io_interface: Could not get " + "required pins for interface %u\n", ioif); + res = -EBUSY; + goto exit; + } + + /* Check which registers need to be reconfigured. */ + gens = genconfig_shadow; + gens_ii = gen_config_ii_shadow; + + set_gen_config = 1; + switch (ioif) + { + /* Begin Non-multiplexed interfaces */ + case if_eth: + /* fall through */ + case if_serial_0: + set_gen_config = 0; + break; + /* End Non-multiplexed interfaces */ + case if_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async); + break; + case if_serial_2: + SETS(gens, R_GEN_CONFIG, ser2, select); + break; + case if_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async); + break; + case if_sync_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync); + break; + case if_sync_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync); + break; + case if_shared_ram: + SETS(gens, R_GEN_CONFIG, mio, select); + break; + case if_shared_ram_w: + SETS(gens, R_GEN_CONFIG, mio_w, select); + break; + case if_par_0: + SETS(gens, R_GEN_CONFIG, par0, select); + break; + case if_par_1: + SETS(gens, R_GEN_CONFIG, par1, select); + break; + case if_par_w: + SETS(gens, R_GEN_CONFIG, par0, select); + SETS(gens, R_GEN_CONFIG, par_w, select); + break; + case if_scsi8_0: + SETS(gens, R_GEN_CONFIG, scsi0, select); + break; + case if_scsi8_1: + SETS(gens, R_GEN_CONFIG, scsi1, select); + break; + case if_scsi_w: + SETS(gens, R_GEN_CONFIG, scsi0, select); + SETS(gens, R_GEN_CONFIG, scsi0w, select); + break; + case if_ata: + SETS(gens, R_GEN_CONFIG, ata, select); + break; + case if_csp: + /* fall through */ + case if_i2c: + set_gen_config = 0; + break; + case if_usb_1: + SETS(gens, R_GEN_CONFIG, usb1, select); + break; + case if_usb_2: + SETS(gens, R_GEN_CONFIG, usb2, select); + break; + case if_gpio_grp_a: + /* GPIO groups are only accounted, don't do configuration changes. */ + /* fall through */ + case if_gpio_grp_b: + /* fall through */ + case if_gpio_grp_c: + /* fall through */ + case if_gpio_grp_d: + /* fall through */ + case if_gpio_grp_e: + /* fall through */ + case if_gpio_grp_f: + set_gen_config = 0; + break; + default: + printk(KERN_INFO "cris_request_io_interface: Bad interface " + "%u submitted for %s\n", + ioif, device_id); + res = -EBUSY; + goto exit; + } + + /* All needed I/O pins and pin groups are free, allocate. */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + unsigned int if_group_use = 0; + + switch (grp->group) { + case group_a: + if_group_use = interfaces[ioif].group_a; + break; + case group_b: + if_group_use = interfaces[ioif].group_b; + break; + case group_c: + if_group_use = interfaces[ioif].group_c; + break; + case group_d: + if_group_use = interfaces[ioif].group_d; + break; + case group_e: + if_group_use = interfaces[ioif].group_e; + break; + case group_f: + if_group_use = interfaces[ioif].group_f; + break; + default: + BUG_ON(1); + } + grp->used |= if_group_use; + + group_set = clear_group_from_set(group_set, grp); + } + + interfaces[ioif].used = 1; + interfaces[ioif].owner = (char*)device_id; + + if (set_gen_config) { + volatile int i; + genconfig_shadow = gens; + *R_GEN_CONFIG = genconfig_shadow; + /* Wait 12 cycles before doing any DMA command */ + for(i = 6; i > 0; i--) + nop(); + } + if (set_gen_config_ii) { + gen_config_ii_shadow = gens_ii; + *R_GEN_CONFIG_II = gen_config_ii_shadow; + } + + DBG(printk(KERN_DEBUG "GPIO pins: available before: " + "g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk(KERN_DEBUG + "grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins &= ~interfaces[ioif].gpio_g_in; + gpio_out_pins &= ~interfaces[ioif].gpio_g_out; + gpio_pb_pins &= ~interfaces[ioif].gpio_b; + + DBG(printk(KERN_DEBUG "GPIO pins: available after: " + "g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + +exit: + local_irq_restore(flags); + if (res == 0) + notify_watchers(); + return res; +} + + +void cris_free_io_interface(enum cris_io_interface ioif) +{ + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + + (void)cris_io_interface_init(); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n", + ioif); + return; + } + local_irq_save(flags); + if (!interfaces[ioif].used) { + printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n", + ioif); + local_irq_restore(flags); + return; + } + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + unsigned int if_group_use = 0; + + switch (grp->group) { + case group_a: + if_group_use = interfaces[ioif].group_a; + break; + case group_b: + if_group_use = interfaces[ioif].group_b; + break; + case group_c: + if_group_use = interfaces[ioif].group_c; + break; + case group_d: + if_group_use = interfaces[ioif].group_d; + break; + case group_e: + if_group_use = interfaces[ioif].group_e; + break; + case group_f: + if_group_use = interfaces[ioif].group_f; + break; + default: + BUG_ON(1); + } + + if ((grp->used & if_group_use) != if_group_use) + BUG_ON(1); + grp->used = grp->used & ~if_group_use; + + group_set = clear_group_from_set(group_set, grp); + } + interfaces[ioif].used = 0; + interfaces[ioif].owner = NULL; + + DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins |= interfaces[ioif].gpio_g_in; + gpio_out_pins |= interfaces[ioif].gpio_g_out; + gpio_pb_pins |= interfaces[ioif].gpio_b; + + DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + + local_irq_restore(flags); + + notify_watchers(); +} + +/* Create a bitmask from bit 0 (inclusive) to bit stop_bit + (non-inclusive). stop_bit == 0 returns 0x0 */ +static inline unsigned int create_mask(const unsigned stop_bit) +{ + /* Avoid overflow */ + if (stop_bit >= 32) { + return 0xffffffff; + } + return (1<notify = notify; + w->next = watchers; + watchers = w; + + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + + return 0; +} + +void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available)) +{ + struct watcher *w = watchers, *prev = NULL; + + (void)cris_io_interface_init(); + + while ((NULL != w) && (w->notify != notify)){ + prev = w; + w = w->next; + } + if (NULL != w) { + if (NULL != prev) { + prev->next = w->next; + } else { + watchers = w->next; + } + kfree(w); + return; + } + printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify); +} + + +static int cris_io_interface_init(void) +{ + static int first = 1; + int i; + + if (!first) { + return 0; + } + first = 0; + + for (i = 0; i<8; i++) { + gpio_pa_owners[i] = if_unclaimed; + gpio_pb_owners[i] = if_unclaimed; + gpio_pg_owners[i] = if_unclaimed; + } + for (; i<32; i++) { + gpio_pg_owners[i] = if_unclaimed; + } + return 0; +} + + +module_init(cris_io_interface_init); + + +EXPORT_SYMBOL(cris_request_io_interface); +EXPORT_SYMBOL(cris_free_io_interface); +EXPORT_SYMBOL(cris_io_interface_allocate_pins); +EXPORT_SYMBOL(cris_io_interface_free_pins); +EXPORT_SYMBOL(cris_io_interface_register_watcher); +EXPORT_SYMBOL(cris_io_interface_delete_watcher); -- cgit v1.2.3-54-g00ecf