📄 io_interface_mux.c
字号:
/* IO interface mux allocator for ETRAX100LX. * Copyright 2004, Axis Communications AB * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $ *//* C.f. ETRAX100LX Designer's Reference 20.9 */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/init.h>#include <asm/arch/svinto.h>#include <asm/io.h>#include <asm/arch/io_interface_mux.h>#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; unsigned char used; enum cris_io_interface owner;};struct interface{ enum cris_io_interface ioif; unsigned char groups; unsigned char used; char *owner; unsigned int gpio_g_in; unsigned int gpio_g_out; unsigned char gpio_b;};static struct if_group if_groups[6] = { { .group = group_a, .used = 0, }, { .group = group_b, .used = 0, }, { .group = group_c, .used = 0, }, { .group = group_d, .used = 0, }, { .group = group_e, .used = 0, }, { .group = group_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, .groups = 0, .gpio_g_in = 0, .gpio_g_out = 0, .gpio_b = 0 }, { .ioif = if_serial_0, .groups = 0, .gpio_g_in = 0, .gpio_g_out = 0, .gpio_b = 0 }, /* End Non-multiplexed interfaces */ { .ioif = if_serial_1, .groups = group_e, .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0x00 }, { .ioif = if_serial_2, .groups = group_b, .gpio_g_in = 0x000000c0, .gpio_g_out = 0x000000c0, .gpio_b = 0x00 }, { .ioif = if_serial_3, .groups = group_c, .gpio_g_in = 0xc0000000, .gpio_g_out = 0xc0000000, .gpio_b = 0x00 }, { .ioif = if_sync_serial_1, .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3 can be used simultaneously */ .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0x10 }, { .ioif = if_sync_serial_3, .groups = group_c | group_f, .gpio_g_in = 0xc0000000, .gpio_g_out = 0xc0000000, .gpio_b = 0x80 }, { .ioif = if_shared_ram, .groups = group_a, .gpio_g_in = 0x0000ff3e, .gpio_g_out = 0x0000ff38, .gpio_b = 0x00 }, { .ioif = if_shared_ram_w, .groups = group_a | group_d, .gpio_g_in = 0x00ffff3e, .gpio_g_out = 0x00ffff38, .gpio_b = 0x00 }, { .ioif = if_par_0, .groups = group_a, .gpio_g_in = 0x0000ff3e, .gpio_g_out = 0x0000ff3e, .gpio_b = 0x00 }, { .ioif = if_par_1, .groups = group_d, .gpio_g_in = 0x3eff0000, .gpio_g_out = 0x3eff0000, .gpio_b = 0x00 }, { .ioif = if_par_w, .groups = group_a | group_d, .gpio_g_in = 0x00ffff3e, .gpio_g_out = 0x00ffff3e, .gpio_b = 0x00 }, { .ioif = if_scsi8_0, .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1 can be used simultaneously */ .gpio_g_in = 0x0000ffff, .gpio_g_out = 0x0000ffff, .gpio_b = 0x10 }, { .ioif = if_scsi8_1, .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1 can be used simultaneously */ .gpio_g_in = 0xffff0000, .gpio_g_out = 0xffff0000, .gpio_b = 0x80 }, { .ioif = if_scsi_w, .groups = group_a | group_b | group_d | group_f, .gpio_g_in = 0x01ffffff, .gpio_g_out = 0x07ffffff, .gpio_b = 0x80 }, { .ioif = if_ata, .groups = group_a | group_b | group_c | group_d, .gpio_g_in = 0xf9ffffff, .gpio_g_out = 0xffffffff, .gpio_b = 0x80 }, { .ioif = if_csp, .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0xfc }, { .ioif = if_i2c, .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0x03 }, { .ioif = if_usb_1, .groups = group_e | group_f, .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0x2c }, { .ioif = if_usb_2, .groups = group_d, .gpio_g_in = 0x0e000000, .gpio_g_out = 0x3c000000, .gpio_b = 0x00 }, /* GPIO pins */ { .ioif = if_gpio_grp_a, .groups = group_a, .gpio_g_in = 0x0000ff3f, .gpio_g_out = 0x0000ff3f, .gpio_b = 0x00 }, { .ioif = if_gpio_grp_b, .groups = group_b, .gpio_g_in = 0x000000c0, .gpio_g_out = 0x000000c0, .gpio_b = 0x00 }, { .ioif = if_gpio_grp_c, .groups = group_c, .gpio_g_in = 0xc0000000, .gpio_g_out = 0xc0000000, .gpio_b = 0x00 }, { .ioif = if_gpio_grp_d, .groups = group_d, .gpio_g_in = 0x3fff0000, .gpio_g_out = 0x3fff0000, .gpio_b = 0x00 }, { .ioif = if_gpio_grp_e, .groups = group_e, .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0x00 }, { .ioif = if_gpio_grp_f, .groups = group_f, .gpio_g_in = 0x00000000, .gpio_g_out = 0x00000000, .gpio_b = 0xff } /* Array end */};static struct watcher *watchers = NULL;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;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; (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) { local_irq_restore(flags); printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n", device_id, interfaces[ioif].owner); return -EBUSY; } /* Check that all required groups are free before allocating, */ group_set = interfaces[ioif].groups; while (NULL != (grp = get_group(group_set))) { if (grp->used) { if (grp->group == group_f) { if ((if_sync_serial_1 == ioif) || (if_sync_serial_3 == ioif)) { if ((grp->owner != if_sync_serial_1) && (grp->owner != if_sync_serial_3)) { local_irq_restore(flags); return -EBUSY; } } else if ((if_scsi8_0 == ioif) || (if_scsi8_1 == ioif)) { if ((grp->owner != if_scsi8_0) && (grp->owner != if_scsi8_1)) { local_irq_restore(flags); return -EBUSY; } } } else { local_irq_restore(flags); return -EBUSY; } } 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)) { local_irq_restore(flags); printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n", ioif); return -EBUSY; } /* All needed I/O pins and pin groups are free, allocate. */ group_set = interfaces[ioif].groups; while (NULL != (grp = get_group(group_set))) { grp->used = 1; grp->owner = ioif; group_set = clear_group_from_set(group_set, grp); } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -