diff options
Diffstat (limited to 'drivers/char')
101 files changed, 5805 insertions, 1532 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 5fed698d6..f18158004 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -124,6 +124,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT + tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG @@ -143,6 +144,7 @@ if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then tristate 'NetWinder flash support' CONFIG_NWFLASH fi +dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then @@ -206,7 +208,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then fi comment 'Video Adapters' if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT $CONFIG_SOUND + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT fi dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV if [ "$CONFIG_ALL_PPC" = "y" ]; then diff --git a/drivers/char/Makefile b/drivers/char/Makefile index f75dabd18..cf145729a 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -56,7 +56,7 @@ ifeq ($(ARCH),m68k) ifdef CONFIG_AMIGA KEYBD = amikeyb.o else - KEYBD = + KEYBD = endif SERIAL = endif @@ -65,7 +65,6 @@ ifeq ($(ARCH),arm) KEYMAP = KEYBD = CONSOLE = - SERIAL = endif ifeq ($(ARCH),sh) @@ -73,6 +72,11 @@ ifeq ($(ARCH),sh) KEYBD = CONSOLE = SERIAL = + ifeq ($(CONFIG_SH_HP600),y) + KEYMAP = defkeymap.o + KEYBD = scan_keyb.o hp600_keyb.o + CONSOLE = console.o + endif ifeq ($(CONFIG_SERIAL),y) SERIAL = generic_serial.o sh-sci.o else @@ -134,40 +138,22 @@ obj-$(CONFIG_SYNCLINK) += synclink.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_SX) += sx.o - -# If either SX or RIO is in the kernel, generic_serial goes in the -# kernel, and the module is no longer required. The "in kernel" case -# is last to be able to override the module case.... This is an -# example of the new "makefile automatically figures out the -# dependencies".... -- REW - -GS=n -ifeq ($(CONFIG_RIO),m) - M_OBJS += generic_serial.o - MOD_SUB_DIRS += rio - GS = m -endif -ifeq ($(CONFIG_SX),m) - GS = m - M_OBJS += sx.o -endif +# After much ado, we found that an object can safely be declared as +# both a module and into the kernel. Below that is filtered out. +# So this should simply provide the wanted functionality! +obj-$(CONFIG_SX) += sx.o generic_serial.o +obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o + ifeq ($(CONFIG_RIO),y) - L_OBJS += rio/rio.o generic_serial.o SUB_DIRS += rio - MOD_SUB_DIRS += rio - GS = y -endif - -ifeq ($(CONFIG_SX),y) - L_OBJS += sx.o - GS = y +else + ifeq ($(CONFIG_RIO),m) + MOD_SUB_DIRS += rio + endif endif -obj-$(GS) += generic_serial.o - obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o obj-$(CONFIG_PRINTER) += lp.o @@ -200,6 +186,7 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_PCWATCHDOG) += pcwd.o obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o obj-$(CONFIG_ADBMOUSE) += adbmouse.o @@ -217,6 +204,7 @@ obj-$(CONFIG_VIDEO_DEV) += videodev.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_DS1620) += ds1620.o +obj-$(CONFIG_INTEL_RNG) += i810_rng.o # # for external dependencies in arm/config.in and video/config.in @@ -238,6 +226,7 @@ else L_TUNERS=m endif endif +obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_ZR36120) += zoran.o ifeq ($(CONFIG_VIDEO_ZR36120),y) @@ -336,10 +325,6 @@ endif obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o -ifeq ($(CONFIG_DZ),y) - L_OBJS += dz.o -endif - ifeq ($(CONFIG_DRM),y) SUB_DIRS += drm ALL_SUB_DIRS += drm diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c index 9d86479dc..eaa9e6bae 100644 --- a/drivers/char/acquirewdt.c +++ b/drivers/char/acquirewdt.c @@ -125,7 +125,6 @@ static int acq_open(struct inode *inode, struct file *file) spin_unlock(&acq_lock); return -EBUSY; } - MOD_INC_USE_COUNT; /* * Activate */ @@ -150,7 +149,6 @@ static int acq_close(struct inode *inode, struct file *file) acq_is_open=0; spin_unlock(&acq_lock); } - MOD_DEC_USE_COUNT; return 0; } @@ -175,6 +173,7 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations acq_fops = { + owner: THIS_MODULE, read: acq_read, write: acq_write, ioctl: acq_ioctl, diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c index a33693c14..a4108cf0e 100644 --- a/drivers/char/adbmouse.c +++ b/drivers/char/adbmouse.c @@ -132,20 +132,22 @@ static void adb_mouse_interrupt(unsigned char *buf, int nb) static int release_mouse(struct inode *inode, struct file *file) { adb_mouse_interrupt_hook = NULL; - MOD_DEC_USE_COUNT; + /* + * FIXME?: adb_mouse_interrupt_hook may still be executing + * on another CPU. + */ return 0; } static int open_mouse(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; adb_mouse_interrupt_hook = adb_mouse_interrupt; return 0; } static struct busmouse adb_mouse = { - ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 7 + ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7 }; static int __init adb_mouse_init(void) diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 21a638fe2..355a9a8d1 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -31,6 +31,7 @@ enum aper_size_type { U8_APER_SIZE, U16_APER_SIZE, U32_APER_SIZE, + LVL2_APER_SIZE, FIXED_APER_SIZE }; @@ -63,6 +64,12 @@ typedef struct _aper_size_info_32 { u32 size_value; } aper_size_info_32; +typedef struct _aper_size_info_lvl2 { + int size; + int num_entries; + u32 size_value; +} aper_size_info_lvl2; + typedef struct _aper_size_info_fixed { int size; int num_entries; @@ -124,10 +131,12 @@ struct agp_bridge_data { #define A_SIZE_8(x) ((aper_size_info_8 *) x) #define A_SIZE_16(x) ((aper_size_info_16 *) x) #define A_SIZE_32(x) ((aper_size_info_32 *) x) +#define A_SIZE_LVL2(x) ((aper_size_info_lvl2 *) x) #define A_SIZE_FIX(x) ((aper_size_info_fixed *) x) #define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i) #define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i) #define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i) +#define A_IDXLVL2() (A_SIZE_LVL2(agp_bridge.aperture_sizes) + i) #define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i) #define MAXKEY (4096 * 32) @@ -151,6 +160,9 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_INTEL_810_0 #define PCI_DEVICE_ID_INTEL_810_0 0x7120 #endif +#ifndef PCI_DEVICE_ID_INTEL_840_0 +#define PCI_DEVICE_ID_INTEL_840_0 0x1a21 +#endif #ifndef PCI_DEVICE_ID_INTEL_810_DC100_0 #define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122 #endif @@ -190,6 +202,10 @@ struct agp_bridge_data { #define INTEL_NBXCFG 0x50 #define INTEL_ERRSTS 0x91 +/* intel i840 registers */ +#define INTEL_I840_MCHCFG 0x50 +#define INTEL_I840_ERRSTS 0xc8 + /* intel i810 registers */ #define I810_GMADDR 0x10 #define I810_MMADDR 0x14 diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index 274c9a86b..dcc8176f9 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -315,6 +315,9 @@ static int agp_return_size(void) case U32_APER_SIZE: current_size = A_SIZE_32(temp)->size; break; + case LVL2_APER_SIZE: + current_size = A_SIZE_LVL2(temp)->size; + break; case FIXED_APER_SIZE: current_size = A_SIZE_FIX(temp)->size; break; @@ -539,6 +542,11 @@ static int agp_generic_create_gatt_table(void) int i; void *temp; + /* The generic routines can't handle 2 level gatt's */ + if (agp_bridge.size_type == LVL2_APER_SIZE) { + return -EINVAL; + } + table = NULL; i = agp_bridge.aperture_size_idx; temp = agp_bridge.current_size; @@ -566,6 +574,7 @@ static int agp_generic_create_gatt_table(void) break; /* This case will never really happen. */ case FIXED_APER_SIZE: + case LVL2_APER_SIZE: default: size = page_order = num_entries = 0; break; @@ -590,6 +599,7 @@ static int agp_generic_create_gatt_table(void) * happen. */ case FIXED_APER_SIZE: + case LVL2_APER_SIZE: default: agp_bridge.current_size = agp_bridge.current_size; @@ -663,6 +673,10 @@ static int agp_generic_free_gatt_table(void) case FIXED_APER_SIZE: page_order = A_SIZE_FIX(temp)->page_order; break; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + break; default: page_order = 0; break; @@ -706,6 +720,10 @@ static int agp_generic_insert_memory(agp_memory * mem, case FIXED_APER_SIZE: num_entries = A_SIZE_FIX(temp)->num_entries; break; + case LVL2_APER_SIZE: + /* The generic routines can't deal with 2 level gatt's */ + return -EINVAL; + break; default: num_entries = 0; break; @@ -1126,6 +1144,38 @@ static int intel_configure(void) return 0; } +static int intel_840_configure(void) +{ + u32 temp; + u16 temp2; + aper_size_info_16 *current_size; + + current_size = A_SIZE_16(agp_bridge.current_size); + + /* aperture size */ + pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, + (char)current_size->size_value); + + /* address to map to */ + pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); + agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + + /* attbase - aperture base */ + pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, + agp_bridge.gatt_bus_addr); + + /* agpctrl */ + pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); + + /* mcgcfg */ + pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); + pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, + temp2 | (1 << 9)); + /* clear any possible error conditions */ + pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); + return 0; +} + static unsigned long intel_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ @@ -1179,6 +1229,34 @@ static int __init intel_generic_setup (struct pci_dev *pdev) (void) pdev; /* unused */ } +static int __init intel_840_setup (struct pci_dev *pdev) +{ + agp_bridge.masks = intel_generic_masks; + agp_bridge.num_of_masks = 1; + agp_bridge.aperture_sizes = (void *) intel_generic_sizes; + agp_bridge.size_type = U16_APER_SIZE; + agp_bridge.num_aperture_sizes = 7; + agp_bridge.dev_private_data = NULL; + agp_bridge.needs_scratch_page = FALSE; + agp_bridge.configure = intel_840_configure; + agp_bridge.fetch_size = intel_fetch_size; + agp_bridge.cleanup = intel_cleanup; + agp_bridge.tlb_flush = intel_tlbflush; + agp_bridge.mask_memory = intel_mask_memory; + agp_bridge.agp_enable = agp_generic_agp_enable; + agp_bridge.cache_flush = global_cache_flush; + agp_bridge.create_gatt_table = agp_generic_create_gatt_table; + agp_bridge.free_gatt_table = agp_generic_free_gatt_table; + agp_bridge.insert_memory = agp_generic_insert_memory; + agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.alloc_by_type = agp_generic_alloc_by_type; + agp_bridge.free_by_type = agp_generic_free_by_type; + + return 0; + + (void) pdev; /* unused */ +} + #endif /* CONFIG_AGP_INTEL */ #ifdef CONFIG_AGP_VIA @@ -1403,19 +1481,180 @@ static int __init sis_generic_setup (struct pci_dev *pdev) #ifdef CONFIG_AGP_AMD +typedef struct _amd_page_map { + unsigned long *real; + unsigned long *remapped; +} amd_page_map; + static struct _amd_irongate_private { volatile u8 *registers; + amd_page_map **gatt_pages; + int num_tables; } amd_irongate_private; +static int amd_create_page_map(amd_page_map *page_map) +{ + int i; + + page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); + if (page_map->real == NULL) { + return -ENOMEM; + } + set_bit(PG_reserved, &mem_map[MAP_NR(page_map->real)].flags); + CACHE_FLUSH(); + page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + PAGE_SIZE); + if (page_map->remapped == NULL) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(page_map->real)].flags); + free_page((unsigned long) page_map->real); + page_map->real = NULL; + return -ENOMEM; + } + CACHE_FLUSH(); + + for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { + page_map->remapped[i] = agp_bridge.scratch_page; + } + + return 0; +} + +static void amd_free_page_map(amd_page_map *page_map) +{ + iounmap(page_map->remapped); + clear_bit(PG_reserved, + &mem_map[MAP_NR(page_map->real)].flags); + free_page((unsigned long) page_map->real); +} + +static void amd_free_gatt_pages(void) +{ + int i; + amd_page_map **tables; + amd_page_map *entry; + + tables = amd_irongate_private.gatt_pages; + for(i = 0; i < amd_irongate_private.num_tables; i++) { + entry = tables[i]; + if (entry != NULL) { + if (entry->real != NULL) { + amd_free_page_map(entry); + } + kfree(entry); + } + } + kfree(tables); +} + +static int amd_create_gatt_pages(int nr_tables) +{ + amd_page_map **tables; + amd_page_map *entry; + int retval = 0; + int i; + + tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *), + GFP_KERNEL); + if (tables == NULL) { + return -ENOMEM; + } + memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1)); + for (i = 0; i < nr_tables; i++) { + entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL); + if (entry == NULL) { + retval = -ENOMEM; + break; + } + memset(entry, 0, sizeof(amd_page_map)); + tables[i] = entry; + retval = amd_create_page_map(entry); + if (retval != 0) break; + } + amd_irongate_private.num_tables = nr_tables; + amd_irongate_private.gatt_pages = tables; + + if (retval != 0) amd_free_gatt_pages(); + + return retval; +} + +/* Since we don't need contigious memory we just try + * to get the gatt table once + */ + +#define GET_PAGE_DIR_OFF(addr) (addr >> 22) +#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \ + GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr)) +#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) +#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\ + GET_PAGE_DIR_IDX(addr)]->remapped) + +static int amd_create_gatt_table(void) +{ + aper_size_info_lvl2 *value; + amd_page_map page_dir; + unsigned long addr; + int retval; + u32 temp; + int i; + + value = A_SIZE_LVL2(agp_bridge.current_size); + retval = amd_create_page_map(&page_dir); + if (retval != 0) { + return retval; + } + + retval = amd_create_gatt_pages(value->num_entries / 1024); + if (retval != 0) { + amd_free_page_map(&page_dir); + return retval; + } + + agp_bridge.gatt_table_real = page_dir.real; + agp_bridge.gatt_table = page_dir.remapped; + agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real); + + /* Get the address for the gart region. + * This is a bus address even on the alpha, b/c its + * used to program the agp master not the cpu + */ + + pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); + agp_bridge.gart_bus_addr = addr; + + /* Calculate the agp offset */ + for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] = + virt_to_bus(amd_irongate_private.gatt_pages[i]->real); + page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001; + } + + return 0; +} + +static int amd_free_gatt_table(void) +{ + amd_page_map page_dir; + + page_dir.real = agp_bridge.gatt_table_real; + page_dir.remapped = agp_bridge.gatt_table; + + amd_free_gatt_pages(); + amd_free_page_map(&page_dir); + return 0; +} + static int amd_irongate_fetch_size(void) { int i; u32 temp; - aper_size_info_32 *values; + aper_size_info_lvl2 *values; pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp); temp = (temp & 0x0000000e); - values = A_SIZE_32(agp_bridge.aperture_sizes); + values = A_SIZE_LVL2(agp_bridge.aperture_sizes); for (i = 0; i < agp_bridge.num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge.previous_size = @@ -1431,12 +1670,11 @@ static int amd_irongate_fetch_size(void) static int amd_irongate_configure(void) { - aper_size_info_32 *current_size; - unsigned long addr; + aper_size_info_lvl2 *current_size; u32 temp; u16 enable_reg; - current_size = A_SIZE_32(agp_bridge.current_size); + current_size = A_SIZE_LVL2(agp_bridge.current_size); /* Get the memory mapped registers */ pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp); @@ -1451,7 +1689,7 @@ static int amd_irongate_configure(void) pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80); /* Set indexing mode */ - pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02); + pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00); /* Write the enable register */ enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); @@ -1467,28 +1705,16 @@ static int amd_irongate_configure(void) /* Flush the tlb */ OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001); - /* Get the address for the gart region */ - pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); - addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); -#ifdef __alpha__ - /* ??? Presumably what is wanted is the bus address as seen - from the CPU side, since it appears that this value is - exported to userland via an ioctl. The terminology below - is confused, mixing `physical address' with `bus address', - as x86 folk are wont to do. */ - addr = virt_to_phys(ioremap(addr, 0)); -#endif - agp_bridge.gart_bus_addr = addr; return 0; } static void amd_irongate_cleanup(void) { - aper_size_info_32 *previous_size; + aper_size_info_lvl2 *previous_size; u32 temp; u16 enable_reg; - previous_size = A_SIZE_32(agp_bridge.previous_size); + previous_size = A_SIZE_LVL2(agp_bridge.previous_size); enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE); enable_reg = (enable_reg & ~(0x0004)); @@ -1521,15 +1747,76 @@ static unsigned long amd_irongate_mask_memory(unsigned long addr, int type) return addr | agp_bridge.masks[0].mask; } -static aper_size_info_32 amd_irongate_sizes[7] = +static int amd_insert_memory(agp_memory * mem, + off_t pg_start, int type) { - {2048, 524288, 9, 0x0000000c}, - {1024, 262144, 8, 0x0000000a}, - {512, 131072, 7, 0x00000008}, - {256, 65536, 6, 0x00000006}, - {128, 32768, 5, 0x00000004}, - {64, 16384, 4, 0x00000002}, - {32, 8192, 3, 0x00000000} + int i, j, num_entries; + unsigned long *cur_gatt; + unsigned long addr; + + num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) { + return -EINVAL; + } + + j = pg_start; + while (j < (pg_start + mem->page_count)) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) { + return -EBUSY; + } + j++; + } + + if (mem->is_flushed == FALSE) { + CACHE_FLUSH(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i]; + } + agp_bridge.tlb_flush(mem); + return 0; +} + +static int amd_remove_memory(agp_memory * mem, off_t pg_start, + int type) +{ + int i; + unsigned long *cur_gatt; + unsigned long addr; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + for (i = pg_start; i < (mem->page_count + pg_start); i++) { + addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr; + cur_gatt = GET_GATT(addr); + cur_gatt[GET_GATT_OFF(addr)] = + (unsigned long) agp_bridge.scratch_page; + } + + agp_bridge.tlb_flush(mem); + return 0; +} + +static aper_size_info_lvl2 amd_irongate_sizes[7] = +{ + {2048, 524288, 0x0000000c}, + {1024, 262144, 0x0000000a}, + {512, 131072, 0x00000008}, + {256, 65536, 0x00000006}, + {128, 32768, 0x00000004}, + {64, 16384, 0x00000002}, + {32, 8192, 0x00000000} }; static gatt_mask amd_irongate_masks[] = @@ -1542,7 +1829,7 @@ static int __init amd_irongate_setup (struct pci_dev *pdev) agp_bridge.masks = amd_irongate_masks; agp_bridge.num_of_masks = 1; agp_bridge.aperture_sizes = (void *) amd_irongate_sizes; - agp_bridge.size_type = U32_APER_SIZE; + agp_bridge.size_type = LVL2_APER_SIZE; agp_bridge.num_aperture_sizes = 7; agp_bridge.dev_private_data = (void *) &amd_irongate_private; agp_bridge.needs_scratch_page = FALSE; @@ -1553,10 +1840,10 @@ static int __init amd_irongate_setup (struct pci_dev *pdev) agp_bridge.mask_memory = amd_irongate_mask_memory; agp_bridge.agp_enable = agp_generic_agp_enable; agp_bridge.cache_flush = global_cache_flush; - agp_bridge.create_gatt_table = agp_generic_create_gatt_table; - agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.create_gatt_table = amd_create_gatt_table; + agp_bridge.free_gatt_table = amd_free_gatt_table; + agp_bridge.insert_memory = amd_insert_memory; + agp_bridge.remove_memory = amd_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; @@ -1755,6 +2042,12 @@ static struct { "Intel", "440GX", intel_generic_setup }, + { PCI_DEVICE_ID_INTEL_840_0, + PCI_VENDOR_ID_INTEL, + INTEL_I840, + "Intel", + "i840", + intel_840_setup }, { 0, PCI_VENDOR_ID_INTEL, INTEL_GENERIC, diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c index 199d5c079..e67beef38 100644 --- a/drivers/char/agp/agpgart_fe.c +++ b/drivers/char/agp/agpgart_fe.c @@ -687,7 +687,6 @@ static int agp_release(struct inode *inode, struct file *file) } agp_remove_file_private(priv); kfree(priv); - MOD_DEC_USE_COUNT; AGP_UNLOCK(); return 0; } @@ -697,19 +696,17 @@ static int agp_open(struct inode *inode, struct file *file) int minor = MINOR(inode->i_rdev); agp_file_private *priv; agp_client *client; + int rc = -ENXIO; AGP_LOCK(); - if (minor != AGPGART_MINOR) { - AGP_UNLOCK(); - return -ENXIO; - } + if (minor != AGPGART_MINOR) + goto err_out; + priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL); + if (priv == NULL) + goto err_out_nomem; - if (priv == NULL) { - AGP_UNLOCK(); - return -ENOMEM; - } memset(priv, 0, sizeof(agp_file_private)); set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; @@ -726,9 +723,14 @@ static int agp_open(struct inode *inode, struct file *file) } file->private_data = (void *) priv; agp_insert_file_private(priv); - MOD_INC_USE_COUNT; AGP_UNLOCK(); return 0; + +err_out_nomem: + rc = -ENOMEM; +err_out: + AGP_UNLOCK(); + return rc; } @@ -1059,6 +1061,7 @@ ioctl_out: static struct file_operations agp_fops = { + owner: THIS_MODULE, llseek: agp_lseek, read: agp_read, write: agp_write, diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c index 0cdfc264a..b7b6c3cc2 100644 --- a/drivers/char/amigamouse.c +++ b/drivers/char/amigamouse.c @@ -151,7 +151,6 @@ static int release_mouse(struct inode * inode, struct file * file) #if AMIGA_OLD_INT AMI_MSE_INT_OFF(); #endif - MOD_DEC_USE_COUNT; return 0; } @@ -162,10 +161,6 @@ static int release_mouse(struct inode * inode, struct file * file) static int open_mouse(struct inode * inode, struct file * file) { - /* Lock module first - request_irq might sleep */ - - MOD_INC_USE_COUNT; - /* * use VBL to poll mouse deltas */ @@ -173,7 +168,6 @@ static int open_mouse(struct inode * inode, struct file * file) if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0, "Amiga mouse", mouse_interrupt)) { printk(KERN_INFO "Installing Amiga mouse failed.\n"); - MOD_DEC_USE_COUNT; return -EIO; } @@ -184,7 +178,7 @@ static int open_mouse(struct inode * inode, struct file * file) } static struct busmouse amigamouse = { - AMIGAMOUSE_MINOR, "amigamouse", open_mouse, release_mouse, 7 + AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7 }; static int __init amiga_mouse_init(void) diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c index 41bb7ac15..15e21be68 100644 --- a/drivers/char/amikeyb.c +++ b/drivers/char/amikeyb.c @@ -186,8 +186,8 @@ static void amikeyb_rep(unsigned long ignore) kbd_pt_regs = NULL; + init_timer(&amikeyb_rep_timer); amikeyb_rep_timer.expires = jiffies + key_repeat_rate; - amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); handle_scancode(rep_scancode, 1); @@ -254,8 +254,8 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) } else { del_timer(&amikeyb_rep_timer); rep_scancode = keycode; + init_timer(&amikeyb_rep_timer); amikeyb_rep_timer.expires = jiffies + key_repeat_delay; - amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); } handle_scancode(keycode, !break_flag); diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index b41ec9229..29614cfd9 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -2104,6 +2104,13 @@ int __init rs_init(void) if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) return -ENODEV; + /* + * We request SERDAT and SERPER only, because the serial registers are + * too spreaded over the custom register space + */ + if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]")) + return -EBUSY; + init_bh(SERIAL_BH, do_serial_bh); IRQ_ports = NULL; @@ -2254,6 +2261,7 @@ void cleanup_module(void) free_page((unsigned long) tmp_buf); tmp_buf = NULL; } + release_mem_region(CUSTOM_PHYSADDR+0x30, 4); } #endif /* MODULE */ diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index d5091ff4d..3fc7005ed 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -226,6 +226,7 @@ int __init applicom_init(void) continue; } + /* &ac_open as dev_id? David, could you pass me this joint? */ if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) { printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c index a188320c2..ce0843725 100644 --- a/drivers/char/atarimouse.c +++ b/drivers/char/atarimouse.c @@ -39,53 +39,50 @@ extern int atari_mouse_buttons; static void atari_mouse_interrupt(char *buf) { - int buttons; + int buttons; -/* ikbd_mouse_disable(); */ +/* ikbd_mouse_disable(); */ - buttons = ((buf[0] & 1) + buttons = ((buf[0] & 1) | ((buf[0] & 2) << 1) | (atari_mouse_buttons & 2)); - atari_mouse_buttons = buttons; + atari_mouse_buttons = buttons; - busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7); -/* ikbd_mouse_rel_pos(); */ + busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7); +/* ikbd_mouse_rel_pos(); */ } static int release_mouse(struct inode *inode, struct file *file) { - ikbd_mouse_disable(); - - atari_mouse_interrupt_hook = NULL; - MOD_DEC_USE_COUNT; - return 0; + ikbd_mouse_disable(); + atari_mouse_interrupt_hook = NULL; + return 0; } static int open_mouse(struct inode *inode, struct file *file) { - atari_mouse_buttons = 0; - ikbd_mouse_y0_top (); - ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]); - ikbd_mouse_rel_pos(); - MOD_INC_USE_COUNT; - atari_mouse_interrupt_hook = atari_mouse_interrupt; - return 0; + atari_mouse_buttons = 0; + ikbd_mouse_y0_top (); + ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]); + ikbd_mouse_rel_pos(); + atari_mouse_interrupt_hook = atari_mouse_interrupt; + return 0; } static struct busmouse atarimouse = { - ATARIMOUSE_MINOR, "atarimouse", open_mouse, release_mouse, 0 + ATARIMOUSE_MINOR, "atarimouse", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init atari_mouse_init(void) { - if (!MACH_IS_ATARI) - return -ENODEV; - msedev = register_busmouse(&atarimouse); - if (msedev < 0) - printk(KERN_WARNING "Unable to register Atari mouse driver.\n"); - else - printk(KERN_INFO "Atari mouse installed.\n"); - return msedev < 0 ? msedev : 0; + if (!MACH_IS_ATARI) + return -ENODEV; + msedev = register_busmouse(&atarimouse); + if (msedev < 0) + printk(KERN_WARNING "Unable to register Atari mouse driver.\n"); + else + printk(KERN_INFO "Atari mouse installed.\n"); + return msedev < 0 ? msedev : 0; } diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c index 223793374..e515d0fa5 100644 --- a/drivers/char/atixlmouse.c +++ b/drivers/char/atixlmouse.c @@ -86,25 +86,19 @@ static int release_mouse(struct inode * inode, struct file * file) { ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ free_irq(ATIXL_MOUSE_IRQ, NULL); - MOD_DEC_USE_COUNT; return 0; } static int open_mouse(struct inode * inode, struct file * file) { - /* Lock module as request_irq may sleep */ - MOD_INC_USE_COUNT; if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL)) - { - MOD_DEC_USE_COUNT; return -EBUSY; - } ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ return 0; } static struct busmouse atixlmouse = { - ATIXL_BUSMOUSE, "atixl", open_mouse, release_mouse, 0 + ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init atixl_busmouse_init(void) diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index dd9ca78c6..e1cc54e3b 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -64,7 +64,6 @@ static struct bttv bttvs[BTTV_MAX]; /* insmod args */ MODULE_PARM(triton1,"i"); -MODULE_PARM(remap,"1-4i"); MODULE_PARM(radio,"1-4i"); MODULE_PARM(card,"1-4i"); MODULE_PARM(pll,"1-4i"); @@ -76,6 +75,7 @@ MODULE_PARM(autoload,"i"); MODULE_PARM(gbuffers,"i"); MODULE_PARM(gbufsize,"i"); +EXPORT_SYMBOL(bttv_get_cardinfo); EXPORT_SYMBOL(bttv_get_id); EXPORT_SYMBOL(bttv_gpio_enable); EXPORT_SYMBOL(bttv_read_gpio); @@ -91,7 +91,6 @@ static unsigned int bigendian=1; static unsigned int bigendian=0; #endif static int triton1=0; -static unsigned long remap[BTTV_MAX]; static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1}; @@ -123,8 +122,19 @@ static unsigned int autoload = 0; /* gpio ports (IR for example) */ /* see bttv.h for comments */ +int bttv_get_cardinfo(unsigned int card, int *type, int *cardid) +{ + if (card >= bttv_num) { + return -1; + } + *type = bttvs[card].type; + *cardid = bttvs[card].cardid; + return 0; +} + int bttv_get_id(unsigned int card) { + printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n"); if (card >= bttv_num) { return -1; } @@ -180,7 +190,7 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data) return 0; } -WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card) +wait_queue_head_t* bttv_get_gpio_queue(unsigned int card) { struct bttv *btv; @@ -467,7 +477,7 @@ static struct i2c_client i2c_client_template = { NULL }; -static int __init init_bttv_i2c(struct bttv *btv) +static int __devinit init_bttv_i2c(struct bttv *btv) { /* i2c bit_adapter */ memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); @@ -489,7 +499,7 @@ static int __init init_bttv_i2c(struct bttv *btv) } /* read I2C */ -static int __init I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) +static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { unsigned char buffer = 0; @@ -514,7 +524,7 @@ static int __init I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) } /* write I2C */ -static int __init I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, +static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, unsigned char b2, int both) { unsigned char buffer[2]; @@ -531,7 +541,7 @@ static int __init I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b } /* read EEPROM */ -static void __init readee(struct bttv *btv, unsigned char *eedata, int addr) +static void __devinit readee(struct bttv *btv, unsigned char *eedata, int addr) { int i; @@ -558,7 +568,7 @@ static struct HAUPPAUGE_TUNER int id; char *name; } -hauppauge_tuner[] __initdata = +hauppauge_tuner[] __devinitdata = { { TUNER_ABSENT, "" }, { TUNER_ABSENT, "External" }, @@ -606,7 +616,7 @@ hauppauge_tuner[] __initdata = { TUNER_ABSENT, "Temic 4046FM5" }, }; -static void __init hauppauge_eeprom(struct bttv *btv) +static void __devinit hauppauge_eeprom(struct bttv *btv) { if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { @@ -615,11 +625,9 @@ static void __init hauppauge_eeprom(struct bttv *btv) printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr, hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type); } - - return; } -static void __init hauppauge_boot_msp34xx(struct bttv *btv) +static void __devinit hauppauge_boot_msp34xx(struct bttv *btv) { int i; @@ -655,7 +663,7 @@ static void __init hauppauge_boot_msp34xx(struct bttv *btv) /* This is basically the same procedure as * used by Alessandro Rubini in his pxc200 * driver, but using BTTV functions */ -static void __init init_PXC200(struct bttv *btv) +static void __devinit init_PXC200(struct bttv *btv) { static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, @@ -705,7 +713,7 @@ static struct CARD { unsigned id; int cardnr; char *name; -} cards[] __initdata = { +} cards[] __devinitdata = { { 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" }, { 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, { 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" }, @@ -813,7 +821,7 @@ static struct tvcard tvcards[] = /* 0x10 */ { "Pixelview PlayTV (bt878)", - 3, 1, 0, 2, 0x01fe00, { 2, 0, 1, 1}, + 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1}, { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, 1,1,1,1,0,0,0,1, PLL_28, -1 }, { "Leadtek WinView 601", @@ -910,10 +918,18 @@ static struct tvcard tvcards[] = { "ProVideo PV951", /* pic16c54 */ 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, 0,0,0,0,0,0,0,0, PLL_28, 1 }, + { "Little OnAir TV", + 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1}, + {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, + + { "Sigma TVII-FM", + 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0, + 0,0,0,0,0,0,0,0, PLL_NONE, -1 }, }; #define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) -static void __init dump_eeprom(struct bttv *btv,int addr) +static void __devinit dump_eeprom(struct bttv *btv,int addr) { int i; @@ -930,7 +946,7 @@ static void __init dump_eeprom(struct bttv *btv,int addr) } } -static int __init idcard_eeprom(struct bttv *btv) +static int __devinit idcard_eeprom(struct bttv *btv) { unsigned id; int i,n; @@ -943,6 +959,7 @@ static int __init idcard_eeprom(struct bttv *btv) return -1; /* look for the card */ + btv->cardid = id; for (n = -1, i = 0; cards[i].id != 0; i++) if (cards[i].id == id) n = i; @@ -1203,7 +1220,7 @@ static void make_vbitab(struct bttv *btv) unsigned int *po=(unsigned int *) btv->vbi_odd; unsigned int *pe=(unsigned int *) btv->vbi_even; - if (debug) + if (debug > 1) printk("bttv%d: vbi1: po=%08lx pe=%08lx\n", btv->nr,virt_to_bus(po), virt_to_bus(pe)); @@ -1225,7 +1242,7 @@ static void make_vbitab(struct bttv *btv) *(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16)); *(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); - if (debug) + if (debug > 1) printk("bttv%d: vbi2: po=%08lx pe=%08lx\n", btv->nr,virt_to_bus(po), virt_to_bus(pe)); } @@ -1302,7 +1319,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned long vadr=(unsigned long) vbuf; int shift, csize; - if (debug) + if (debug > 1) printk("bttv%d: prisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1399,7 +1416,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: prisc2: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1424,7 +1441,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, if (palette>=VIDEO_PALETTE_PLANAR) return make_prisctab(btv, ro, re, vbuf, width, height, palette); - if (debug) + if (debug > 1) printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1476,7 +1493,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, *(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16)); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); @@ -1494,7 +1511,7 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int int W, l, r; int i; - if (debug) + if (debug > 1) printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y); /* bitmap is fixed width, 128 bytes (1024 pixels represented) */ @@ -1559,7 +1576,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) inter=(btv->win.interlace&1)^1; width=btv->win.width; height=btv->win.height; - if (debug) + if (debug > 1) printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); if(width > 1023) @@ -1573,7 +1590,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) printk("bttv%d: clip: ro=%08lx re=%08lx\n", btv->nr,virt_to_bus(ro), virt_to_bus(re)); - if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { + if ((clipmap=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); *(ro++)=cpu_to_le32(btv->bus_vbi_even); @@ -1668,7 +1685,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) *(re++)=cpu_to_le32(BT848_RISC_JUMP); *(re++)=cpu_to_le32(btv->bus_vbi_odd); - if (debug) + if (debug > 1) printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n", btv->nr,btv->picture.palette,width,height,bpl,bpp); } @@ -1734,9 +1751,6 @@ static void bt848_set_geo(struct bttv *btv, u16 ewidth, eheight, owidth, oheight; u16 format, bswap; struct tvnorm *tvn; - unsigned long flags; - - spin_lock_irqsave(&btv->s_lock, flags); tvn=&tvnorms[btv->win.norm]; @@ -1789,8 +1803,6 @@ static void bt848_set_geo(struct bttv *btv, btwrite(format, BT848_COLOR_FMT); btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); - - spin_unlock_irqrestore(&btv->s_lock, flags); } @@ -1847,7 +1859,6 @@ static void bt848_set_winsize(struct bttv *btv) /* * Grab into virtual memory. - * Currently only does double buffering. Do we need more? */ static int vgrab(struct bttv *btv, struct video_mmap *mp) @@ -1904,16 +1915,16 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) btv->gbuf[mp->frame].ro = 0; #endif - if (btv->gq_in == btv->gq_out) { + if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) { btv->gq_start = 1; btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } btv->gqueue[btv->gq_in++] = mp->frame; btv->gq_in = btv->gq_in % MAX_GBUFFERS; - spin_unlock_irqrestore(&btv->s_lock, flags); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); + spin_unlock_irqrestore(&btv->s_lock, flags); return 0; } @@ -1927,39 +1938,43 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in { struct bttv *btv= (struct bttv *)v; int q,todo; + DECLARE_WAITQUEUE(wait, current); /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { - unsigned long flags; - if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) return -EFAULT; todo-=q; buf+=q; - spin_lock_irqsave(&btv->s_lock, flags); + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { - spin_unlock_irqrestore(&btv->s_lock, flags); + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } - spin_unlock_irqrestore(&btv->s_lock, flags); - interruptible_sleep_on(&btv->vbiq); + schedule(); if(signal_pending(current)) { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; + if(todo==count) return -EINTR; else return count-todo; } - } else - spin_unlock_irqrestore(&btv->s_lock, flags); + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; } if (todo) { @@ -1980,9 +1995,11 @@ static inline void burst(int on) static void bt848_restart(struct bttv *btv) { + unsigned long irq_flags; + if (verbose) printk("bttv%d: resetting chip\n",btv->nr); - btwrite(~0x0UL, BT848_INT_STAT); + btwrite(0xfffffUL, BT848_INT_STAT); btand(~15, BT848_GPIO_DMA_CTL); btwrite(0, BT848_SRESET); btwrite(virt_to_bus(btv->risc_jmp+2), @@ -1994,8 +2011,10 @@ static void bt848_restart(struct bttv *btv) btv->errors = 0; btv->needs_restart = 0; + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_geo(btv,0); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } /* @@ -2042,13 +2061,16 @@ static int bttv_open(struct video_device *dev, int flags) static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; down(&btv->lock); btv->user--; + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->scr_on = 0; btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * A word of warning. At this point the chip @@ -2133,9 +2155,11 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data) static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { struct bttv *btv=(struct bttv *)dev; + unsigned long irq_flags; int i,ret = 0; - if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); + if (debug > 1) + printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd); switch (cmd) { case VIDIOCGCAP: @@ -2206,7 +2230,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if (btv->win.norm != v.norm) { btv->win.norm = v.norm; make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } up(&btv->lock); return 0; @@ -2248,7 +2274,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) down(&btv->lock); set_pll(btv); make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); } return 0; @@ -2289,12 +2317,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; + down(&btv->lock); if(vw.flags || vw.width < 16 || vw.height < 16) { - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); return -EINVAL; } if (btv->win.bpp < 4) @@ -2302,18 +2331,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } - down(&btv->lock); if (btv->needs_restart) bt848_restart(btv); btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; - + + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,0); - bt848_set_winsize(btv); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * Do any clips. @@ -2337,11 +2365,12 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return -EFAULT; } } - down(&btv->lock); make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; } @@ -2370,13 +2399,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) return -EINVAL; if (btv->win.width==0 || btv->win.height==0) return -EINVAL; - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); if (v == 1 && btv->win.vidadr != 0) btv->scr_on = 1; if (v == 0) btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); return 0; } case VIDIOCGFBUF: @@ -2500,9 +2529,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE, 1); - up(&btv->lock); call_i2c_clients(btv,cmd,&v); - down(&btv->lock); if (btv->type == BTTV_TERRATV) { unsigned int con = 0; @@ -2554,6 +2581,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) } case VIDIOCSYNC: + { + DECLARE_WAITQUEUE(wait, current); + if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; if (i < 0 || i >= gbuffers) @@ -2563,13 +2593,20 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ret = -EINVAL; break; case GBUFFER_GRABBING: + add_wait_queue(&btv->capq, &wait); + current->state = TASK_INTERRUPTIBLE; while(btv->gbuf[i].stat==GBUFFER_GRABBING) { if (debug) printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); - interruptible_sleep_on(&btv->capq); - if(signal_pending(current)) + schedule(); + if(signal_pending(current)) { + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; return -EINTR; + } } + remove_wait_queue(&btv->capq, &wait); + current->state = TASK_RUNNING; /* fall throuth */ case GBUFFER_DONE: case GBUFFER_ERROR: @@ -2584,6 +2621,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) up(&btv->lock); } return ret; + } case BTTV_FIELDNR: if(copy_to_user((void *) arg, (void *) &btv->last_field, @@ -2602,7 +2640,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) btv->pll.pll_ofreq = p.pll_ofreq; btv->pll.pll_crystal = p.pll_crystal; up(&btv->lock); - break; } @@ -2749,12 +2786,11 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count, { struct bttv *btv=(struct bttv *)(v-2); int q,todo; + DECLARE_WAITQUEUE(wait, current); todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { - unsigned long flags; - if (btv->needs_restart) { down(&btv->lock); bt848_restart(btv); @@ -2765,27 +2801,31 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count, todo-=q; buf+=q; - spin_lock_irqsave(&btv->s_lock, flags); + add_wait_queue(&btv->vbiq, &wait); + current->state = TASK_INTERRUPTIBLE; if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { - spin_unlock_irqrestore(&btv->s_lock, flags); + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(count==todo) return -EWOULDBLOCK; return count-todo; } - spin_unlock_irqrestore(&btv->s_lock, flags); - interruptible_sleep_on(&btv->vbiq); + schedule(); if(signal_pending(current)) { + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; if(todo==count) return -EINTR; else return count-todo; } - } else - spin_unlock_irqrestore(&btv->s_lock, flags); + } + remove_wait_queue(&btv->vbiq, &wait); + current->state = TASK_RUNNING; } if (todo) { @@ -2813,15 +2853,18 @@ static unsigned int vbi_poll(struct video_device *dev, struct file *file, static int vbi_open(struct video_device *dev, int flags) { struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; MOD_INC_USE_COUNT; - down(&btv->lock); if (btv->needs_restart) bt848_restart(btv); + set_pll(btv); btv->vbip=VBIBUF_SIZE; + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->vbi_on = 1; bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; @@ -2830,12 +2873,12 @@ static int vbi_open(struct video_device *dev, int flags) static void vbi_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)(dev-2); + unsigned long irq_flags; - down(&btv->lock); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->vbi_on = 0; bt848_set_risc_jmps(btv,-1); - up(&btv->lock); - + spin_unlock_irqrestore(&btv->s_lock, irq_flags); MOD_DEC_USE_COUNT; } @@ -3018,7 +3061,7 @@ static struct video_device radio_template= #define TRITON_PEER_CONCURRENCY (1<<3) -static void __init handle_chipset(void) +static void __devinit handle_chipset(void) { struct pci_dev *dev = NULL; @@ -3050,7 +3093,7 @@ static void __init handle_chipset(void) /* can tda9855.c handle this too maybe? */ -static void __init init_tda9840(struct bttv *btv) +static void __devinit init_tda9840(struct bttv *btv) { /* Horrible Hack */ I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ @@ -3066,12 +3109,11 @@ static void __init init_tda9840(struct bttv *btv) /* Figure out card and tuner type */ -static void __init idcard(struct bttv *btv) +static void __devinit idcard(struct bttv *btv) { int type,eeprom = 0; btwrite(0, BT848_GPIO_OUT_EN); - DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", btv->nr, btread(BT848_GPIO_DATA))); /* Default the card to the user-selected one. */ if (card[btv->nr] >= 0 && card[btv->nr] < TVCARDS) @@ -3114,7 +3156,6 @@ static void __init idcard(struct bttv *btv) (btv->id==848 && btv->revision==0x12) ? "A" : "", tvcards[btv->type].name); printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name); - /* board specific initialisations */ if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { @@ -3228,10 +3269,6 @@ static void __init idcard(struct bttv *btv) static void bt848_set_risc_jmps(struct bttv *btv, int flags) { - unsigned long irq_flags; - - spin_lock_irqsave(&btv->s_lock, irq_flags); - if (-1 == flags) { /* defaults */ flags = 0; @@ -3241,8 +3278,9 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) flags |= 0x0c; } - if (debug) printk("bttv%d: set_risc_jmp %08lx:", - btv->nr,virt_to_bus(btv->risc_jmp)); + if (debug > 1) + printk("bttv%d: set_risc_jmp %08lx:", + btv->nr,virt_to_bus(btv->risc_jmp)); /* Sync to start of odd field */ btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC @@ -3252,24 +3290,29 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) /* Jump to odd vbi sub */ btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); if (flags&8) { - if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); + if (debug > 1) + printk(" ev=%08lx",virt_to_bus(btv->vbi_odd)); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); } /* Jump to odd sub */ btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); if (0 != btv->risc_cap_odd) { - if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); + if (debug > 1) + printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd); flags |= 3; btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd); } else if (flags&2) { - if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); + if (debug > 1) + printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd)); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6)); } @@ -3282,24 +3325,29 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); if (flags&4) { - if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); + if (debug > 1) + printk(" ov=%08lx",virt_to_bus(btv->vbi_even)); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10)); } /* Jump to even sub */ btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20)); if (0 != btv->risc_cap_even) { - if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); + if (debug > 1) + printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even); flags |= 3; btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even); } else if (flags&1) { - if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); + if (debug > 1) + printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even)); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even)); } else { - if (debug) printk(" -----------"); + if (debug > 1) + printk(" -----------"); btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12)); } @@ -3311,18 +3359,17 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags) btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); /* enable cpaturing and DMA */ - if (debug) printk(" flags=0x%x dma=%s\n", - flags,(flags&0x0f) ? "on" : "off"); + if (debug > 1) + printk(" flags=0x%x dma=%s\n", + flags,(flags&0x0f) ? "on" : "off"); btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); else bt848_dma(btv, 0); - - spin_unlock_irqrestore(&btv->s_lock, irq_flags); } -static int __init init_video_dev(struct bttv *btv) +static int __devinit init_video_dev(struct bttv *btv) { memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); @@ -3349,9 +3396,10 @@ static int __init init_video_dev(struct bttv *btv) return 1; } -static int __init init_bt848(struct bttv *btv) +static int __devinit init_bt848(struct bttv *btv) { int j; + unsigned long irq_flags; btv->user=0; init_MUTEX(&btv->lock); @@ -3412,14 +3460,13 @@ static int __init init_bt848(struct bttv *btv) return -1; if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL))) return -1; - DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp)); btv->vbi_odd=btv->risc_jmp+16; btv->vbi_even=btv->vbi_odd+256; btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12); btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); - btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE); + btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE); if (!btv->vbibuf) return -1; if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL))) @@ -3475,7 +3522,7 @@ static int __init init_bt848(struct bttv *btv) btwrite(0x00, BT848_O_SCLOOP); /* clear interrupt status */ - btwrite(~0x0UL, BT848_INT_STAT); + btwrite(0xfffffUL, BT848_INT_STAT); /* set interrupt mask */ btwrite(btv->triton1| @@ -3489,8 +3536,10 @@ static int __init init_bt848(struct bttv *btv) BT848_INT_MASK); make_vbitab(btv); + spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); - + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + /* * Now add the template and register the device unit. */ @@ -3505,7 +3554,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) u32 dstat; int count,i; struct bttv *btv; - + unsigned long irq_flags; + btv=(struct bttv *)dev_id; count=0; while (1) @@ -3515,6 +3565,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) astat=stat&btread(BT848_INT_MASK); if (!astat) return; + btwrite(astat,BT848_INT_STAT); IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat)); IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat)); @@ -3550,15 +3601,18 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btread(BT848_RISC_COUNT)); btv->errors++; if (btv->errors < BTTV_ERRORS) { + spin_lock_irqsave(&btv->s_lock, irq_flags); btand(~15, BT848_GPIO_DMA_CTL); btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); bt848_set_geo(btv,0); bt848_set_risc_jmps(btv,-1); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } else { if (verbose) printk("bttv%d: aiee: error loops\n",btv->nr); /* cancel all outstanding grab requests */ + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gq_in = 0; btv->gq_out = 0; btv->gq_grab = -1; @@ -3569,8 +3623,9 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btv->risc_cap_odd = 0; btv->risc_cap_even = 0; bt848_set_risc_jmps(btv,0); - btv->needs_restart = 1; + spin_unlock_irqrestore(&btv->s_lock, irq_flags); + wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); } @@ -3596,6 +3651,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (debug) printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab); do_gettimeofday(&btv->gbuf[btv->gq_grab].tv); + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE; btv->gq_grab = -1; if (btv->gq_in != btv->gq_out) @@ -3618,22 +3674,25 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); } + spin_unlock_irqrestore(&btv->s_lock, irq_flags); wake_up_interruptible(&btv->capq); break; } if (stat&(8<<28)) { + spin_lock_irqsave(&btv->s_lock, irq_flags); btv->gq_start = 0; btv->gq_grab = btv->gqueue[btv->gq_out++]; btv->gq_out = btv->gq_out % MAX_GBUFFERS; if (debug) - printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab); + printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab); btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro; btv->risc_cap_even = btv->gbuf[btv->gq_grab].re; bt848_set_risc_jmps(btv,-1); bt848_set_geo(btv,0); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); + spin_unlock_irqrestore(&btv->s_lock, irq_flags); } } if (astat&BT848_INT_OCERR) @@ -3676,9 +3735,6 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) { IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); } - - btwrite(astat,BT848_INT_STAT); - count++; if (count > 10) printk (KERN_WARNING "bttv%d: irq loop %d\n", @@ -3698,11 +3754,11 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) * Scan for a Bt848 card, request the irq and map the io memory */ -static void __init bttv_remove(struct pci_dev *pci_dev) +static void __devinit bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; - struct bttv *btv = pci_dev->driver_data; + struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); /* unregister i2c_bus */ i2c_bit_del_bus(&btv->i2c_adap); @@ -3767,7 +3823,7 @@ static void __init bttv_remove(struct pci_dev *pci_dev) } -static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) +static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int result; unsigned char command; @@ -3788,20 +3844,17 @@ static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pc btv->vbi_even=NULL; init_waitqueue_head(&btv->vbiq); init_waitqueue_head(&btv->capq); - init_waitqueue_head(&btv->capqo); - init_waitqueue_head(&btv->capqe); btv->vbip=VBIBUF_SIZE; - - init_waitqueue_head(&btv->gpioq); btv->s_lock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&btv->gpioq); btv->shutdown=0; btv->id=dev->device; btv->irq=dev->irq; - btv->bt848_adr=pci_resource_start(dev, 0); + btv->bt848_adr=pci_resource_start(dev,0); if (pci_enable_device(dev)) return -EIO; - if (!request_mem_region(btv->bt848_adr, + if (!request_mem_region(pci_resource_start(dev,0), pci_resource_len(dev,0), "bttv")) { return -EBUSY; @@ -3871,24 +3924,23 @@ static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pc } } - dev->driver_data = btv; + PCI_SET_DRIVER_DATA(dev,btv); if(init_bt848(btv) < 0) { bttv_remove(dev); return -EIO; } - bttv_num++; return 0; fail: - release_mem_region(btv->bt848_adr, + release_mem_region(pci_resource_start(btv->dev,0), pci_resource_len(btv->dev,0)); return result; } -static struct pci_device_id bttv_pci_tbl[] __initdata = { +static struct pci_device_id bttv_pci_tbl[] __devinitdata = { {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849, @@ -3903,13 +3955,13 @@ static struct pci_device_id bttv_pci_tbl[] __initdata = { MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); static struct pci_driver bttv_pci_driver = { - name:"bttv", - id_table:bttv_pci_tbl, - probe:bttv_probe, - remove:bttv_remove, + name: "bttv", + id_table: bttv_pci_tbl, + probe: bttv_probe, + remove: bttv_remove, }; -static int __init bttv_init_module(void) +int bttv_init_module(void) { bttv_num = 0; @@ -3930,10 +3982,10 @@ static int __init bttv_init_module(void) return pci_module_init(&bttv_pci_driver); } -static void __exit bttv_cleanup_module(void) +void bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); - return; + return; } module_init(bttv_init_module); diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index 3f4229fe8..9189bfa77 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -21,7 +21,12 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,28) +#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,31) + +#ifndef PCI_GET_DRIVER_DATA +# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) +# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) +#endif /* PCI_GET_DRIVER_DATA */ #include <linux/types.h> #include <linux/wait.h> @@ -32,12 +37,13 @@ #include "audiochip.h" #include "bt848.h" -#define WAIT_QUEUE wait_queue_head_t - -/* returns card type, +/* returns card type + card ID (for bt878-based ones) for possible values see lines below beginning with #define BTTV_UNKNOWN returns negative value if error ocurred */ +extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid); + +/* obsolete, use bttv_get_cardinfo instead */ extern int bttv_get_id(unsigned int card); /* sets GPOE register (BT848_GPIO_OUT_EN) to new value: @@ -68,7 +74,7 @@ extern int bttv_write_gpio(unsigned int card, WARNING: because there is no buffer for GPIO data, one MUST process data ASAP */ -extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card); +extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card); #ifndef O_NONCAP @@ -130,6 +136,7 @@ struct bttv { struct video_picture picture; /* Current picture params */ struct video_audio audio_dev; /* Current audio params */ + spinlock_t s_lock; struct semaphore lock; int user; int capuser; @@ -143,8 +150,6 @@ struct bttv { int tuner_type; int channel; - - spinlock_t s_lock; unsigned int nr; unsigned short id; @@ -160,6 +165,7 @@ struct bttv { struct bttv_window win; int fb_color_ctl; int type; /* card type */ + int cardid; int audio; /* audio mode */ int audio_chip; /* set to one of the chips supported by bttv.c */ int radio; @@ -169,10 +175,8 @@ struct bttv { u32 *vbi_even; u32 bus_vbi_even; u32 bus_vbi_odd; - WAIT_QUEUE vbiq; - WAIT_QUEUE capq; - WAIT_QUEUE capqo; - WAIT_QUEUE capqe; + wait_queue_head_t vbiq; + wait_queue_head_t capq; int vbip; u32 *risc_scr_odd; @@ -198,7 +202,7 @@ struct bttv { int errors; int needs_restart; - WAIT_QUEUE gpioq; + wait_queue_head_t gpioq; int shutdown; }; #endif @@ -277,6 +281,8 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #define BTTV_STB2 0x28 #define BTTV_AVPHONE98 0x29 #define BTTV_PV951 0x2a +#define BTTV_ONAIR_TV 0x2b +#define BTTV_SIGMA_TVII_FM 0x2c #define PLL_NONE 0 #define PLL_28 1 diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index 1b09081c1..bc8345cff 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -110,8 +110,7 @@ void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons) if (changed) { wake_up(&mse->wait); - if (mse->fasyncptr) - kill_fasync(mse->fasyncptr, SIGIO, POLL_IN); + kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN); } } @@ -171,13 +170,13 @@ static int busmouse_release(struct inode *inode, struct file *file) busmouse_fasync(-1, file, 0); if (--mse->active == 0) { - if (mse->ops && - mse->ops->release) - ret = mse->ops->release(inode, file); - + if (mse->ops) { + if (mse->ops->release) + ret = mse->ops->release(inode, file); + if (mse->ops->owner) + __MOD_DEC_USE_COUNT(mse->ops->owner); + } mse->ready = 0; - - MOD_DEC_USE_COUNT; } return ret; @@ -192,16 +191,20 @@ static int busmouse_open(struct inode *inode, struct file *file) mousedev = DEV_TO_MOUSE(inode->i_rdev); if (mousedev >= NR_MICE) return -EINVAL; - + down(&mouse_sem); mse = busmouse_data[mousedev]; if (!mse) /* shouldn't happen, but... */ goto end; - if (mse->ops && - mse->ops->open) + if (mse->ops && mse->ops->owner) + __MOD_INC_USE_COUNT(mse->ops->owner); + if (mse->ops && mse->ops->open) { ret = mse->ops->open(inode, file); + if (ret && mse->ops->owner) + __MOD_DEC_USE_COUNT(mse->ops->owner); + } if (ret) goto end; @@ -211,8 +214,6 @@ static int busmouse_open(struct inode *inode, struct file *file) if (mse->active++) goto end; - MOD_INC_USE_COUNT; - spin_lock_irq(&mse->lock); mse->ready = 0; @@ -333,6 +334,7 @@ static unsigned int busmouse_poll(struct file *file, poll_table *wait) struct file_operations busmouse_fops= { + owner: THIS_MODULE, read: busmouse_read, write: busmouse_write, poll: busmouse_poll, diff --git a/drivers/char/busmouse.h b/drivers/char/busmouse.h index 641e66d49..487c4820d 100644 --- a/drivers/char/busmouse.h +++ b/drivers/char/busmouse.h @@ -11,6 +11,7 @@ struct busmouse { int minor; const char *name; + struct module *owner; int (*open)(struct inode * inode, struct file * file); int (*release)(struct inode * inode, struct file * file); int init_button_state; diff --git a/drivers/char/buz.c b/drivers/char/buz.c index cbf085e9e..299a4f8ca 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -48,6 +48,7 @@ #include <linux/types.h> #include <linux/wrapper.h> #include <linux/spinlock.h> +#include <linux/vmalloc.h> #include <linux/videodev.h> diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c index 1e0582bdf..fa96cc925 100644 --- a/drivers/char/c-qcam.c +++ b/drivers/char/c-qcam.c @@ -12,9 +12,15 @@ * probe=1 -- use IEEE-1284 autoprobe data only (default) * probe=2 -- probe aggressively for cameras * + * force_rgb=1 -- force data format to RGB (default is BGR) + * * The parport parameter controls which parports will be scanned. * Scanning all parports causes some printers to print a garbage page. * -- March 14, 1999 Billy Donahue <billy@escape.com> + * + * Fixed data format to BGR, added force_rgb parameter. Added missing + * parport_unregister_driver() on module removal. + * -- May 28, 2000 Claudio Matsuoka <claudio@conectiva.com> */ #include <linux/module.h> @@ -62,6 +68,7 @@ struct qcam_device { static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 }; static int probe = 2; +static int force_rgb = 0; static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i) { @@ -278,6 +285,7 @@ static void qc_setup(struct qcam_device *q) static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes) { unsigned int bytes = 0; + qcam_set_ack(q, 0); if (q->bidirectional) { @@ -285,6 +293,8 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u while (bytes < nbytes) { unsigned int lo1, hi1, lo2, hi2; + unsigned char r, g, b; + if (qcam_await_ready2(q, 1)) return bytes; lo1 = parport_read_data(q->pport) >> 1; hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; @@ -293,17 +303,30 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u lo2 = parport_read_data(q->pport) >> 1; hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10; qcam_set_ack(q, 0); - buf[bytes++] = (lo1 | ((hi1 & 1)<<7)); - buf[bytes++] = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); - buf[bytes++] = (lo2 | ((hi2 & 1)<<7)); + r = (lo1 | ((hi1 & 1)<<7)); + g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1); + b = (lo2 | ((hi2 & 1)<<7)); + if (force_rgb) { + buf[bytes++] = r; + buf[bytes++] = g; + buf[bytes++] = b; + } else { + buf[bytes++] = b; + buf[bytes++] = g; + buf[bytes++] = r; + } } } else { /* It's a unidirectional port */ + int i = 0, n = bytes; + unsigned char rgb[3]; + while (bytes < nbytes) { unsigned int hi, lo; + if (qcam_await_ready1(q, 1)) return bytes; hi = (parport_read_status(q->pport) & 0xf0); qcam_set_ack(q, 1); @@ -311,7 +334,23 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u lo = (parport_read_status(q->pport) & 0xf0); qcam_set_ack(q, 0); /* flip some bits */ - buf[bytes++] = (hi | (lo >> 4)) ^ 0x88; + rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88; + if (i >= 2) { +get_fragment: + if (force_rgb) { + buf[n++] = rgb[0]; + buf[n++] = rgb[1]; + buf[n++] = rgb[2]; + } else { + buf[n++] = rgb[2]; + buf[n++] = rgb[1]; + buf[n++] = rgb[0]; + } + } + } + if (i) { + i = 0; + goto get_fragment; } } return bytes; @@ -408,8 +447,13 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) if (current->need_resched) schedule(); } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e)); - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } qcam_set_ack(q, 0); if (qcam_await_ready1(q, 1)) { @@ -437,8 +481,13 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len) schedule(); } while (l && tmpbuf[0] == 0x7e); l = qcam_read_bytes(q, tmpbuf+1, 2); - if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) - printk("qcam: bad EOF\n"); + if (force_rgb) { + if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf) + printk("qcam: bad EOF\n"); + } else { + if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe) + printk("qcam: bad EOF\n"); + } } qcam_write_data(q, 0); @@ -829,19 +878,24 @@ static int __init cqcam_init (void) return parport_register_driver(&cqcam_driver); } -MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); -MODULE_DESCRIPTION(BANNER); -MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method \n\ -probe=<0|1|2> # for camera detection method"); -MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); -MODULE_PARM(probe, "i"); - static void __exit cqcam_cleanup (void) { unsigned int i; + for (i = 0; i < num_cams; i++) close_cqcam(qcams[i]); + + parport_unregister_driver(&cqcam_driver); } +MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); +MODULE_DESCRIPTION(BANNER); +MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\ +probe=<0|1|2> for camera detection method\n\ +force_rgb=<0|1> for RGB data format (default BGR)"); +MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i"); +MODULE_PARM(probe, "i"); +MODULE_PARM(force_rgb, "i"); + module_init(cqcam_init); module_exit(cqcam_cleanup); diff --git a/drivers/char/console.c b/drivers/char/console.c index 4e69f8f4b..4b33e7433 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -2290,10 +2290,13 @@ static void con_start(struct tty_struct *tty) static void con_flush_chars(struct tty_struct *tty) { + unsigned long flags; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; pm_access(pm_con); + spin_lock_irqsave(&console_lock, flags); set_cursor(vt->vc_num); + spin_unlock_irqrestore(&console_lock, flags); } /* diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 48047a637..cf4bb1f83 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1,7 +1,8 @@ #undef BLOCKMOVE #define Z_WAKE +#undef Z_EXT_CHARS_IN_BUFFER static char rcsid[] = -"$Revision: 2.3.2.6 $$Date: 2000/05/05 13:56:05 $"; +"$Revision: 2.3.2.7 $$Date: 2000/06/01 18:26:34 $"; /* * linux/drivers/char/cyclades.c @@ -24,6 +25,12 @@ static char rcsid[] = * This version supports shared IRQ's (only for PCI boards). * * $Log: cyclades.c,v $ + * Revision 2.3.2.7 2000/06/01 18:26:34 ivan + * Request PLX I/O region, although driver doesn't use it, to avoid + * problems with other drivers accessing it. + * Removed count for on-board buffer characters in cy_chars_in_buffer + * (Cyclades-Z only). + * * Revision 2.3.2.6 2000/05/05 13:56:05 ivan * Driver now reports physical instead of virtual memory addresses. * Masks were added to some Cyclades-Z read accesses. @@ -636,6 +643,7 @@ static char rcsid[] = #include <linux/ptrace.h> #include <linux/cyclades.h> #include <linux/mm.h> +#include <linux/ioport.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> @@ -882,9 +890,8 @@ static void cyz_poll(unsigned long); static long cyz_polling_cycle = CZ_DEF_POLL; static int cyz_timeron = 0; -static struct timer_list -cyz_timerlist = { - NULL, NULL, 0, 0, cyz_poll +static struct timer_list cyz_timerlist = { + function: cyz_poll }; #else /* CONFIG_CYZ_INTR */ static void cyz_rx_restart(unsigned long); @@ -3122,12 +3129,15 @@ cy_chars_in_buffer(struct tty_struct *tty) card = info->card; channel = (info->line) - (cy_card[card].first_line); +#ifdef Z_EXT_CHARS_IN_BUFFER if (!IS_CYC_Z(cy_card[card])) { +#endif /* Z_EXT_CHARS_IN_BUFFER */ #ifdef CY_DEBUG_IO printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ #endif return info->xmit_cnt; +#ifdef Z_EXT_CHARS_IN_BUFFER } else { static volatile struct FIRM_ID *firm_id; static volatile struct ZFW_CTRL *zfw_ctrl; @@ -3156,6 +3166,7 @@ cy_chars_in_buffer(struct tty_struct *tty) #endif return (info->xmit_cnt + char_count); } +#endif /* Z_EXT_CHARS_IN_BUFFER */ } /* cy_chars_in_buffer */ @@ -4856,7 +4867,7 @@ cy_detect_pci(void) struct pci_dev *pdev = NULL; unsigned char cyy_rev_id; unsigned char cy_pci_irq = 0; - uclong cy_pci_phys0, cy_pci_phys2; + uclong cy_pci_phys0, cy_pci_phys1, cy_pci_phys2; uclong cy_pci_addr0, cy_pci_addr2; unsigned short i,j,cy_pci_nchan, plx_ver; unsigned short device_id,dev_index = 0; @@ -4885,6 +4896,7 @@ cy_detect_pci(void) /* read PCI configuration area */ cy_pci_irq = pdev->irq; cy_pci_phys0 = pci_resource_start(pdev, 0); + cy_pci_phys1 = pci_resource_start(pdev, 1); cy_pci_phys2 = pci_resource_start(pdev, 2); pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); @@ -4907,6 +4919,11 @@ cy_detect_pci(void) pdev->resource[2].flags &= ~IORESOURCE_IO; } + /* Although we don't use this I/O region, we should + request it from the kernel anyway, to avoid problems + with other drivers accessing it. */ + request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y"); + #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", @@ -5054,6 +5071,12 @@ cy_detect_pci(void) "Ignoring it...\n"); pdev->resource[2].flags &= ~IORESOURCE_IO; } + + /* Although we don't use this I/O region, we should + request it from the kernel anyway, to avoid problems + with other drivers accessing it. */ + request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z"); + if (mailbox == ZE_V1) { #if !defined(__alpha__) cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c index f663790db..8d8766b85 100644 --- a/drivers/char/dn_keyb.c +++ b/drivers/char/dn_keyb.c @@ -357,17 +357,14 @@ static void dn_keyb_process_mouse_event(unsigned char mouse_data) { mouse_dy+=mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2]; wake_up_interruptible(&mouse_wait); if (mouse_dx < -2048) - mouse_dx = -2048; - else - if (mouse_dx > 2048) - mouse_dx = 2048; - if (mouse_dy < -2048) - mouse_dy = -2048; - else - if (mouse_dy > 2048) - mouse_dy = 2048; - if (mouse_fasyncptr) - kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN); + mouse_dx = -2048; + else if (mouse_dx > 2048) + mouse_dx = 2048; + if (mouse_dy < -2048) + mouse_dy = -2048; + else if (mouse_dy > 2048) + mouse_dy = 2048; + kill_fasync(&mouse_fasyncptr, SIGIO, POLL_IN); } mouse_byte_count=0; /* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */ @@ -450,20 +447,8 @@ void write_keyb_cmd(u_short length, u_char *cmd) { } -static int release_mouse(struct inode * inode, struct file * file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -static int open_mouse(struct inode * inode, struct file * file) -{ - MOD_INC_USE_COUNT; - return 0; -} - static struct busmouse apollo_mouse = { - APOLLO_MOUSE_MINOR, "apollomouse", open_mouse, release_mouse,7 + APOLLO_MOUSE_MINOR, "apollomouse", THIS_MODULE, NULL, NULL, 7 }; int __init dn_keyb_init(void){ diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index ff70792d7..1c68f0cd2 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -39,6 +39,17 @@ else endif endif +ifeq ($(CONFIG_DRM_FFB),y) + OX_OBJS += ffb_drv.o + O_OBJS += ffb_context.o +else + ifeq ($(CONFIG_DRM_FFB),m) + MIX_OBJC += ffb_drv.o + MI_OBJS += ffb_context.o + M_OBJS += ffb.o + endif +endif + O_OBJS += $(L_OBJS) include $(TOPDIR)/Rules.make @@ -48,3 +59,6 @@ gamma.o : gamma_drv.o gamma_dma.o $(L_OBJS) tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS) $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS) + +ffb.o: ffb_drv.o ffb_context.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ffb_drv.o ffb_context.o $(L_OBJS) diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c index 4e8c50c59..3d4c40222 100644 --- a/drivers/char/drm/bufs.c +++ b/drivers/char/drm/bufs.c @@ -72,11 +72,13 @@ int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd, switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: +#ifndef __sparc__ if (map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory)) { drm_free(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } +#endif #ifdef CONFIG_MTRR if (map->type == _DRM_FRAME_BUFFER || (map->flags & _DRM_WRITE_COMBINING)) { @@ -478,8 +480,10 @@ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, -EFAULT); if (request.count >= dma->buf_count) { + down(¤t->mm->mmap_sem); virtual = do_mmap(filp, 0, dma->byte_count, PROT_READ|PROT_WRITE, MAP_SHARED, 0); + up(¤t->mm->mmap_sem); if (virtual > -1024UL) { /* Real error */ retcode = (signed long)virtual; diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 4d003ba2c..b39fec3f7 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -433,9 +433,9 @@ typedef struct drm_device { /* Context support */ int irq; /* Interrupt used by board */ - __volatile__ int context_flag; /* Context swapping flag */ - __volatile__ int interrupt_flag;/* Interruption handler flag */ - __volatile__ int dma_flag; /* DMA dispatch flag */ + __volatile__ long context_flag; /* Context swapping flag */ + __volatile__ long interrupt_flag;/* Interruption handler flag */ + __volatile__ long dma_flag; /* DMA dispatch flag */ struct timer_list timer; /* Timer for delaying ctx switch */ wait_queue_head_t context_wait; /* Processes waiting on ctx switch */ int last_checked; /* Last context checked for DMA */ diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c new file mode 100644 index 000000000..a10b59898 --- /dev/null +++ b/drivers/char/drm/ffb_context.c @@ -0,0 +1,530 @@ +/* $Id: ffb_context.c,v 1.3 2000/06/09 03:46:53 davem Exp $ + * ffb_context.c: Creator/Creator3D DRI/DRM context switching. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + * + * Almost entirely stolen from tdfx_context.c, see there + * for authors. + */ + +#include <linux/sched.h> +#include <asm/upa.h> + +#include "drmP.h" + +#include "ffb_drv.h" + +static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int i; + + for (i = 0; i < FFB_MAX_CTXS; i++) { + if (fpriv->hw_state[i] == NULL) + break; + } + if (i == FFB_MAX_CTXS) + return -1; + + fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL); + if (fpriv->hw_state[i] == NULL) + return -1; + + fpriv->hw_state[i]->is_2d_only = is_2d_only; + + /* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */ + return i + 1; +} + +static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + ctx->drawop = upa_readl(&ffb->drawop); + ctx->ppc = upa_readl(&ffb->ppc); + ctx->wid = upa_readl(&ffb->wid); + ctx->fg = upa_readl(&ffb->fg); + ctx->bg = upa_readl(&ffb->bg); + ctx->xclip = upa_readl(&ffb->xclip); + ctx->fbc = upa_readl(&ffb->fbc); + ctx->rop = upa_readl(&ffb->rop); + ctx->cmp = upa_readl(&ffb->cmp); + ctx->matchab = upa_readl(&ffb->matchab); + ctx->magnab = upa_readl(&ffb->magnab); + ctx->pmask = upa_readl(&ffb->pmask); + ctx->xpmask = upa_readl(&ffb->xpmask); + ctx->lpat = upa_readl(&ffb->lpat); + ctx->fontxy = upa_readl(&ffb->fontxy); + ctx->fontw = upa_readl(&ffb->fontw); + ctx->fontinc = upa_readl(&ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + ctx->ucsr = upa_readl(&ffb->ucsr); + return; + } + + /* Fetch drawop. */ + ctx->drawop = upa_readl(&ffb->drawop); + + /* If we were saving the vertex registers, this is where + * we would do it. We would save 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Capture rendering attributes. */ + + ctx->ppc = upa_readl(&ffb->ppc); /* Pixel Processor Control */ + ctx->wid = upa_readl(&ffb->wid); /* Current WID */ + ctx->fg = upa_readl(&ffb->fg); /* Constant FG color */ + ctx->bg = upa_readl(&ffb->bg); /* Constant BG color */ + ctx->consty = upa_readl(&ffb->consty); /* Constant Y */ + ctx->constz = upa_readl(&ffb->constz); /* Constant Z */ + ctx->xclip = upa_readl(&ffb->xclip); /* X plane clip */ + ctx->dcss = upa_readl(&ffb->dcss); /* Depth Cue Scale Slope */ + ctx->vclipmin = upa_readl(&ffb->vclipmin); /* Primary XY clip, minimum */ + ctx->vclipmax = upa_readl(&ffb->vclipmax); /* Primary XY clip, maximum */ + ctx->vclipzmin = upa_readl(&ffb->vclipzmin); /* Primary Z clip, minimum */ + ctx->vclipzmax = upa_readl(&ffb->vclipzmax); /* Primary Z clip, maximum */ + ctx->dcsf = upa_readl(&ffb->dcsf); /* Depth Cue Scale Front Bound */ + ctx->dcsb = upa_readl(&ffb->dcsb); /* Depth Cue Scale Back Bound */ + ctx->dczf = upa_readl(&ffb->dczf); /* Depth Cue Scale Z Front */ + ctx->dczb = upa_readl(&ffb->dczb); /* Depth Cue Scale Z Back */ + ctx->blendc = upa_readl(&ffb->blendc); /* Alpha Blend Control */ + ctx->blendc1 = upa_readl(&ffb->blendc1); /* Alpha Blend Color 1 */ + ctx->blendc2 = upa_readl(&ffb->blendc2); /* Alpha Blend Color 2 */ + ctx->fbc = upa_readl(&ffb->fbc); /* Frame Buffer Control */ + ctx->rop = upa_readl(&ffb->rop); /* Raster Operation */ + ctx->cmp = upa_readl(&ffb->cmp); /* Compare Controls */ + ctx->matchab = upa_readl(&ffb->matchab); /* Buffer A/B Match Ops */ + ctx->matchc = upa_readl(&ffb->matchc); /* Buffer C Match Ops */ + ctx->magnab = upa_readl(&ffb->magnab); /* Buffer A/B Magnitude Ops */ + ctx->magnc = upa_readl(&ffb->magnc); /* Buffer C Magnitude Ops */ + ctx->pmask = upa_readl(&ffb->pmask); /* RGB Plane Mask */ + ctx->xpmask = upa_readl(&ffb->xpmask); /* X Plane Mask */ + ctx->ypmask = upa_readl(&ffb->ypmask); /* Y Plane Mask */ + ctx->zpmask = upa_readl(&ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min); + ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max); + ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min); + ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max); + ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min); + ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max); + ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min); + ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max); + + ctx->lpat = upa_readl(&ffb->lpat); /* Line Pattern */ + ctx->fontxy = upa_readl(&ffb->fontxy); /* XY Font Coordinate */ + ctx->fontw = upa_readl(&ffb->fontw); /* Font Width */ + ctx->fontinc = upa_readl(&ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + ctx->dcss1 = upa_readl(&ffb->dcss1); /* Depth Cue Scale Slope 1 */ + ctx->dcss2 = upa_readl(&ffb->dcss2); /* Depth Cue Scale Slope 2 */ + ctx->dcss2 = upa_readl(&ffb->dcss3); /* Depth Cue Scale Slope 3 */ + ctx->dcs2 = upa_readl(&ffb->dcs2); /* Depth Cue Scale 2 */ + ctx->dcs3 = upa_readl(&ffb->dcs3); /* Depth Cue Scale 3 */ + ctx->dcs4 = upa_readl(&ffb->dcs4); /* Depth Cue Scale 4 */ + ctx->dcd2 = upa_readl(&ffb->dcd2); /* Depth Cue Depth 2 */ + ctx->dcd3 = upa_readl(&ffb->dcd3); /* Depth Cue Depth 3 */ + ctx->dcd4 = upa_readl(&ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + ctx->stencil = upa_readl(&ffb->stencil); + ctx->stencilctl = upa_readl(&ffb->stencilctl); + } + } + + /* Save the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. */ + ctx->ucsr = upa_readl(&ffb->ucsr); +} + +static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx) +{ + ffb_fbcPtr ffb = fpriv->regs; + struct ffb_hw_context *ctx; + int i; + + ctx = fpriv->hw_state[idx - 1]; + if (idx == 0 || ctx == NULL) + return; + + if (ctx->is_2d_only) { + /* 2D applications only care about certain pieces + * of state. + */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + upa_writel(ctx->ppc, &ffb->ppc); + upa_writel(ctx->wid, &ffb->wid); + upa_writel(ctx->fg, &ffb->fg); + upa_writel(ctx->bg, &ffb->bg); + upa_writel(ctx->xclip, &ffb->xclip); + upa_writel(ctx->fbc, &ffb->fbc); + upa_writel(ctx->rop, &ffb->rop); + upa_writel(ctx->cmp, &ffb->cmp); + upa_writel(ctx->matchab, &ffb->matchab); + upa_writel(ctx->magnab, &ffb->magnab); + upa_writel(ctx->pmask, &ffb->pmask); + upa_writel(ctx->xpmask, &ffb->xpmask); + upa_writel(ctx->lpat, &ffb->lpat); + upa_writel(ctx->fontxy, &ffb->fontxy); + upa_writel(ctx->fontw, &ffb->fontw); + upa_writel(ctx->fontinc, &ffb->fontinc); + + /* stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + upa_writel(ctx->fbc, &ffb->fbc); + } + + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); + return; + } + + /* Restore drawop. */ + upa_writel(ctx->drawop, &ffb->drawop); + + /* If we were restoring the vertex registers, this is where + * we would do it. We would restore 32 32-bit words starting + * at ffb->suvtx. + */ + + /* Restore rendering attributes. */ + + upa_writel(ctx->ppc, &ffb->ppc); /* Pixel Processor Control */ + upa_writel(ctx->wid, &ffb->wid); /* Current WID */ + upa_writel(ctx->fg, &ffb->fg); /* Constant FG color */ + upa_writel(ctx->bg, &ffb->bg); /* Constant BG color */ + upa_writel(ctx->consty, &ffb->consty); /* Constant Y */ + upa_writel(ctx->constz, &ffb->constz); /* Constant Z */ + upa_writel(ctx->xclip, &ffb->xclip); /* X plane clip */ + upa_writel(ctx->dcss, &ffb->dcss); /* Depth Cue Scale Slope */ + upa_writel(ctx->vclipmin, &ffb->vclipmin); /* Primary XY clip, minimum */ + upa_writel(ctx->vclipmax, &ffb->vclipmax); /* Primary XY clip, maximum */ + upa_writel(ctx->vclipzmin, &ffb->vclipzmin); /* Primary Z clip, minimum */ + upa_writel(ctx->vclipzmax, &ffb->vclipzmax); /* Primary Z clip, maximum */ + upa_writel(ctx->dcsf, &ffb->dcsf); /* Depth Cue Scale Front Bound */ + upa_writel(ctx->dcsb, &ffb->dcsb); /* Depth Cue Scale Back Bound */ + upa_writel(ctx->dczf, &ffb->dczf); /* Depth Cue Scale Z Front */ + upa_writel(ctx->dczb, &ffb->dczb); /* Depth Cue Scale Z Back */ + upa_writel(ctx->blendc, &ffb->blendc); /* Alpha Blend Control */ + upa_writel(ctx->blendc1, &ffb->blendc1); /* Alpha Blend Color 1 */ + upa_writel(ctx->blendc2, &ffb->blendc2); /* Alpha Blend Color 2 */ + upa_writel(ctx->fbc, &ffb->fbc); /* Frame Buffer Control */ + upa_writel(ctx->rop, &ffb->rop); /* Raster Operation */ + upa_writel(ctx->cmp, &ffb->cmp); /* Compare Controls */ + upa_writel(ctx->matchab, &ffb->matchab); /* Buffer A/B Match Ops */ + upa_writel(ctx->matchc, &ffb->matchc); /* Buffer C Match Ops */ + upa_writel(ctx->magnab, &ffb->magnab); /* Buffer A/B Magnitude Ops */ + upa_writel(ctx->magnc, &ffb->magnc); /* Buffer C Magnitude Ops */ + upa_writel(ctx->pmask, &ffb->pmask); /* RGB Plane Mask */ + upa_writel(ctx->xpmask, &ffb->xpmask); /* X Plane Mask */ + upa_writel(ctx->ypmask, &ffb->ypmask); /* Y Plane Mask */ + upa_writel(ctx->zpmask, &ffb->zpmask); /* Z Plane Mask */ + + /* Auxiliary Clips. */ + upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min); + upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max); + upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min); + upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max); + upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min); + upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max); + upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min); + upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max); + + upa_writel(ctx->lpat, &ffb->lpat); /* Line Pattern */ + upa_writel(ctx->fontxy, &ffb->fontxy); /* XY Font Coordinate */ + upa_writel(ctx->fontw, &ffb->fontw); /* Font Width */ + upa_writel(ctx->fontinc, &ffb->fontinc); /* Font X/Y Increment */ + + /* These registers/features only exist on FFB2 and later chips. */ + if (fpriv->ffb_type >= ffb2_prototype) { + upa_writel(ctx->dcss1, &ffb->dcss1); /* Depth Cue Scale Slope 1 */ + upa_writel(ctx->dcss2, &ffb->dcss2); /* Depth Cue Scale Slope 2 */ + upa_writel(ctx->dcss3, &ffb->dcss2); /* Depth Cue Scale Slope 3 */ + upa_writel(ctx->dcs2, &ffb->dcs2); /* Depth Cue Scale 2 */ + upa_writel(ctx->dcs3, &ffb->dcs3); /* Depth Cue Scale 3 */ + upa_writel(ctx->dcs4, &ffb->dcs4); /* Depth Cue Scale 4 */ + upa_writel(ctx->dcd2, &ffb->dcd2); /* Depth Cue Depth 2 */ + upa_writel(ctx->dcd3, &ffb->dcd3); /* Depth Cue Depth 3 */ + upa_writel(ctx->dcd4, &ffb->dcd4); /* Depth Cue Depth 4 */ + + /* And stencil/stencilctl only exists on FFB2+ and later + * due to the introduction of 3DRAM-III. + */ + if (fpriv->ffb_type == ffb2_vertical_plus || + fpriv->ffb_type == ffb2_horizontal_plus) { + /* Unfortunately, there is a hardware bug on + * the FFB2+ chips which prevents a normal write + * to the stencil control register from working + * as it should. + * + * The state controlled by the FFB stencilctl register + * really gets transferred to the per-buffer instances + * of the stencilctl register in the 3DRAM chips. + * + * The bug is that FFB does not update buffer C correctly, + * so we have to do it by hand for them. + */ + + /* This will update buffers A and B. */ + upa_writel(ctx->stencil, &ffb->stencil); + upa_writel(ctx->stencilctl, &ffb->stencilctl); + + /* Force FFB to use buffer C 3dram regs. */ + upa_writel(0x80000000, &ffb->fbc); + upa_writel((ctx->stencilctl | 0x80000), + &ffb->rawstencilctl); + + /* Now restore the correct FBC controls. */ + upa_writel(ctx->fbc, &ffb->fbc); + } + } + + /* Restore the 32x32 area pattern. */ + for (i = 0; i < 32; i++) + upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); + + /* Finally, stash away the User Constol/Status Register. + * The only state we really preserve here is the picking + * control. + */ + upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); +} + +#define FFB_UCSR_FB_BUSY 0x01000000 +#define FFB_UCSR_RP_BUSY 0x02000000 +#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) + +static void FFBWait(ffb_fbcPtr ffb) +{ + int limit = 100000; + + do { + u32 regval = upa_readl(&ffb->ucsr); + + if ((regval & FFB_UCSR_ALL_BUSY) == 0) + break; + } while (--limit); +} + +int ffb_context_switch(drm_device_t *dev, int old, int new) +{ + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + + atomic_inc(&dev->total_ctx); + +#if DRM_DMA_HISTOGRAM + dev->ctx_start = get_cycles(); +#endif + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new == dev->last_context || + dev->last_context == 0) { + dev->last_context = new; + return 0; + } + + FFBWait(fpriv->regs); + ffb_save_context(fpriv, old); + ffb_restore_context(fpriv, old, new); + FFBWait(fpriv->regs); + + dev->last_context = new; + + return 0; +} + +int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_res_t res; + drm_ctx_t ctx; + int i; + + DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); + copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT); + if (res.count >= DRM_RESERVED_CONTEXTS) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + copy_to_user_ret(&res.contexts[i], + &i, + sizeof(i), + -EFAULT); + } + } + res.count = DRM_RESERVED_CONTEXTS; + copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT); + return 0; +} + + +int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY)); + if (idx < 0) + return -ENFILE; + + DRM_DEBUG("%d\n", ctx.handle); + ctx.handle = idx; + copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT); + return 0; +} + +int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0) + hwctx->is_2d_only = 0; + else + hwctx->is_2d_only = 1; + + return 0; +} + +int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + struct ffb_hw_context *hwctx; + drm_ctx_t ctx; + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT); + + idx = ctx.handle; + if (idx <= 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + hwctx = fpriv->hw_state[idx - 1]; + if (hwctx == NULL) + return -EINVAL; + + if (hwctx->is_2d_only != 0) + ctx.flags = _DRM_CONTEXT_2DONLY; + else + ctx.flags = 0; + + copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT); + + return 0; +} + +int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + return ffb_context_switch(dev, dev->last_context, ctx.handle); +} + +int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + return 0; +} + +int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_ctx_t ctx; + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int idx; + + copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT); + DRM_DEBUG("%d\n", ctx.handle); + + idx = ctx.handle - 1; + if (idx < 0 || idx >= FFB_MAX_CTXS) + return -EINVAL; + + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + return 0; +} diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c new file mode 100644 index 000000000..a1ab1f279 --- /dev/null +++ b/drivers/char/drm/ffb_drv.c @@ -0,0 +1,842 @@ +/* $Id: ffb_drv.c,v 1.3 2000/06/01 04:24:39 davem Exp $ + * ffb_drv.c: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +#include "drmP.h" + +#include <asm/oplib.h> +#include <asm/upa.h> + +#include "ffb_drv.h" + +#define FFB_NAME "ffb" +#define FFB_DESC "Creator/Creator3D" +#define FFB_DATE "20000517" +#define FFB_MAJOR 0 +#define FFB_MINOR 0 +#define FFB_PATCHLEVEL 1 + +/* Forward declarations. */ +int ffb_init(void); +void ffb_cleanup(void); +static int ffb_version(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_open(struct inode *inode, struct file *filp); +static int ffb_release(struct inode *inode, struct file *filp); +static int ffb_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_lock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_unlock(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma); + +/* From ffb_context.c */ +extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long); +extern int ffb_context_switch(drm_device_t *, int, int); + +static struct file_operations ffb_fops = { + open: ffb_open, + flush: drm_flush, + release: ffb_release, + ioctl: ffb_ioctl, + mmap: ffb_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, +}; + +/* This is just a template, we make a new copy for each FFB + * we discover at init time so that each one gets a unique + * misc device minor number. + */ +static struct miscdevice ffb_misc = { + minor: MISC_DYNAMIC_MINOR, + name: FFB_NAME, + fops: &ffb_fops, +}; + +static drm_ioctl_desc_t ffb_ioctls[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { ffb_version, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, /* XXX */ + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, + + /* The implementation is currently a nop just like on tdfx. + * Later we can do something more clever. -DaveM + */ + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { ffb_addctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { ffb_rmctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { ffb_modctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { ffb_getctx, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { ffb_newctx, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { ffb_resctx, 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { ffb_lock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { ffb_unlock, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 }, +}; +#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls) + +#ifdef MODULE +static char *ffb = NULL; +#endif + +MODULE_AUTHOR("David S. Miller (davem@redhat.com)"); +MODULE_DESCRIPTION("Sun Creator/Creator3D DRI"); + +static int ffb_takedown(drm_device_t *dev) +{ + int i; + drm_magic_entry_t *pt, *next; + drm_map_t *map; + drm_vma_entry_t *vma, *vma_next; + + DRM_DEBUG("\n"); + + down(&dev->struct_sem); + del_timer(&dev->timer); + + if (dev->devname) { + drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); + dev->devname = NULL; + } + + if (dev->unique) { + drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); + dev->unique = NULL; + dev->unique_len = 0; + } + + /* Clear pid list */ + for (i = 0; i < DRM_HASH_SIZE; i++) { + for (pt = dev->magiclist[i].head; pt; pt = next) { + next = pt->next; + drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + } + dev->magiclist[i].head = dev->magiclist[i].tail = NULL; + } + + /* Clear vma list (only built for debugging) */ + if (dev->vmalist) { + for (vma = dev->vmalist; vma; vma = vma_next) { + vma_next = vma->next; + drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + } + dev->vmalist = NULL; + } + + /* Clear map area information */ + if (dev->maplist) { + for (i = 0; i < dev->map_count; i++) { + map = dev->maplist[i]; + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: + drm_ioremapfree(map->handle, map->size); + break; + + case _DRM_SHM: + drm_free_pages((unsigned long)map->handle, + drm_order(map->size) + - PAGE_SHIFT, + DRM_MEM_SAREA); + break; + }; + + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + + drm_free(dev->maplist, + dev->map_count * sizeof(*dev->maplist), + DRM_MEM_MAPS); + dev->maplist = NULL; + dev->map_count = 0; + } + + if (dev->lock.hw_lock) { + dev->lock.hw_lock = NULL; /* SHM removed */ + dev->lock.pid = 0; + wake_up_interruptible(&dev->lock.lock_queue); + } + up(&dev->struct_sem); + + return 0; +} + +drm_device_t **ffb_dev_table; +static int ffb_dev_table_size; + +static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance) +{ + volatile unsigned char *strap_bits; + unsigned char val; + + strap_bits = (volatile unsigned char *) + (ffb_priv->card_phys_base + 0x00200000UL); + + /* Don't ask, you have to read the value twice for whatever + * reason to get correct contents. + */ + val = upa_readb(strap_bits); + val = upa_readb(strap_bits); + switch (val & 0x78) { + case (0x0 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb1_prototype; + printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance); + break; + case (0x0 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb1_standard; + printk("ffb%d: Detected FFB1\n", instance); + break; + case (0x0 << 5) | (0x3 << 3): + ffb_priv->ffb_type = ffb1_speedsort; + printk("ffb%d: Detected FFB1-SpeedSort\n", instance); + break; + case (0x1 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_prototype; + printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance); + break; + case (0x1 << 5) | (0x1 << 3): + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Detected FFB2/vertical\n", instance); + break; + case (0x1 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_vertical_plus; + printk("ffb%d: Detected FFB2+/vertical\n", instance); + break; + case (0x2 << 5) | (0x0 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2/horizontal\n", instance); + break; + case (0x2 << 5) | (0x2 << 3): + ffb_priv->ffb_type = ffb2_horizontal; + printk("ffb%d: Detected FFB2+/horizontal\n", instance); + break; + default: + ffb_priv->ffb_type = ffb2_vertical; + printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val); + break; + }; +} + +static int ffb_init_one(int prom_node, int instance) +{ + struct linux_prom64_registers regs[2*PROMREG_MAX]; + drm_device_t *dev; + ffb_dev_priv_t *ffb_priv; + int ret, i; + + dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + memset(dev, 0, sizeof(*dev)); + spin_lock_init(&dev->count_lock); + sema_init(&dev->struct_sem, 1); + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + ffb_priv->prom_node = prom_node; + if (prom_getproperty(ffb_priv->prom_node, "reg", + (void *)regs, sizeof(regs)) <= 0) { + kfree(dev); + return -EINVAL; + } + ffb_priv->card_phys_base = regs[0].phys_addr; + ffb_priv->regs = (ffb_fbcPtr) + (regs[0].phys_addr + 0x00600000UL); + get_ffb_type(ffb_priv, instance); + for (i = 0; i < FFB_MAX_CTXS; i++) + ffb_priv->hw_state[i] = NULL; + + ffb_dev_table[instance] = dev; + +#ifdef MODULE + drm_parse_options(ffb); +#endif + + memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc)); + ret = misc_register(&ffb_priv->miscdev); + if (ret) { + ffb_dev_table[instance] = NULL; + kfree(dev); + return ret; + } + + dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor); + dev->name = FFB_NAME; + + drm_mem_init(); + drm_proc_init(dev); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n", + FFB_NAME, + FFB_MAJOR, + FFB_MINOR, + FFB_PATCHLEVEL, + FFB_DATE, + ffb_priv->miscdev.minor, + ffb_priv->card_phys_base); + + return 0; +} + +static int ffb_init_dev_table(void) +{ + int root, node; + int total = 0; + + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) + total++; + + ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL); + if (!ffb_dev_table) + return -ENOMEM; + + ffb_dev_table_size = total; + + return 0; +} + +int ffb_init(void) +{ + int root, node, instance, ret; + + ret = ffb_init_dev_table(); + if (ret) + return ret; + + instance = 0; + root = prom_getchild(prom_root_node); + for (node = prom_searchsiblings(root, "SUNW,ffb"); node; + node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { + ret = ffb_init_one(node, instance); + if (ret) + return ret; + instance++; + } + + return 0; +} + +void ffb_cleanup(void) +{ + int instance; + + DRM_DEBUG("\n"); + + drm_proc_cleanup(); + for (instance = 0; instance < ffb_dev_table_size; instance++) { + drm_device_t *dev = ffb_dev_table[instance]; + ffb_dev_priv_t *ffb_priv; + + if (!dev) + continue; + + ffb_priv = (ffb_dev_priv_t *) (dev + 1); + if (misc_deregister(&ffb_priv->miscdev)) { + DRM_ERROR("Cannot unload module\n"); + } else { + DRM_INFO("Module unloaded\n"); + } + ffb_takedown(dev); + kfree(dev); + ffb_dev_table[instance] = NULL; + } + kfree(ffb_dev_table); + ffb_dev_table = NULL; + ffb_dev_table_size = 0; +} + +static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_version_t version; + int len, ret; + + ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version)); + if (ret) + return -EFAULT; + + version.version_major = FFB_MAJOR; + version.version_minor = FFB_MINOR; + version.version_patchlevel = FFB_PATCHLEVEL; + + len = strlen(FFB_NAME); + if (len > version.name_len) + len = version.name_len; + version.name_len = len; + if (len && version.name) { + ret = copy_to_user(version.name, FFB_NAME, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DATE); + if (len > version.date_len) + len = version.date_len; + version.date_len = len; + if (len && version.date) { + ret = copy_to_user(version.date, FFB_DATE, len); + if (ret) + return -EFAULT; + } + + len = strlen(FFB_DESC); + if (len > version.desc_len) + len = version.desc_len; + version.desc_len = len; + if (len && version.desc) { + ret = copy_to_user(version.desc, FFB_DESC, len); + if (ret) + return -EFAULT; + } + + ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version)); + if (ret) + ret = -EFAULT; + + return ret; +} + +static int ffb_setup(drm_device_t *dev) +{ + int i; + + atomic_set(&dev->ioctl_count, 0); + atomic_set(&dev->vma_count, 0); + dev->buf_use = 0; + atomic_set(&dev->buf_alloc, 0); + + atomic_set(&dev->total_open, 0); + atomic_set(&dev->total_close, 0); + atomic_set(&dev->total_ioctl, 0); + atomic_set(&dev->total_irq, 0); + atomic_set(&dev->total_ctx, 0); + atomic_set(&dev->total_locks, 0); + atomic_set(&dev->total_unlocks, 0); + atomic_set(&dev->total_contends, 0); + atomic_set(&dev->total_sleeps, 0); + + for (i = 0; i < DRM_HASH_SIZE; i++) { + dev->magiclist[i].head = NULL; + dev->magiclist[i].tail = NULL; + } + + dev->maplist = NULL; + dev->map_count = 0; + dev->vmalist = NULL; + dev->lock.hw_lock = NULL; + init_waitqueue_head(&dev->lock.lock_queue); + dev->queue_count = 0; + dev->queue_reserved = 0; + dev->queue_slots = 0; + dev->queuelist = NULL; + dev->irq = 0; + dev->context_flag = 0; + dev->interrupt_flag = 0; + dev->dma = 0; + dev->dma_flag = 0; + dev->last_context = 0; + dev->last_switch = 0; + dev->last_checked = 0; + init_timer(&dev->timer); + init_waitqueue_head(&dev->context_wait); + + dev->ctx_start = 0; + dev->lck_start = 0; + + dev->buf_rp = dev->buf; + dev->buf_wp = dev->buf; + dev->buf_end = dev->buf + DRM_BSZ; + dev->buf_async = NULL; + init_waitqueue_head(&dev->buf_readers); + init_waitqueue_head(&dev->buf_writers); + + return 0; +} + +static int ffb_open(struct inode *inode, struct file *filp) +{ + drm_device_t *dev; + int minor, i; + int ret = 0; + + minor = MINOR(inode->i_rdev); + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_dev_priv_t *ffb_priv; + + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + + if (ffb_priv->miscdev.minor == minor) + break; + } + + if (i >= ffb_dev_table_size) + return -EINVAL; + + dev = ffb_dev_table[i]; + if (!dev) + return -EINVAL; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + ret = drm_open_helper(inode, filp, dev); + if (!ret) { + MOD_INC_USE_COUNT; + atomic_inc(&dev->total_open); + spin_lock(&dev->count_lock); + if (!dev->open_count++) { + spin_unlock(&dev->count_lock); + return ffb_setup(dev); + } + spin_unlock(&dev->count_lock); + } + + return ret; +} + +static int ffb_release(struct inode *inode, struct file *filp) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int ret = 0; + + DRM_DEBUG("open_count = %d\n", dev->open_count); + if (dev->lock.hw_lock != NULL + && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + && dev->lock.pid == current->pid) { + ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1); + int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); + int idx; + + /* We have to free up the rogue hw context state + * holding error or else we will leak it. + */ + idx = context - 1; + if (fpriv->hw_state[idx] != NULL) { + kfree(fpriv->hw_state[idx]); + fpriv->hw_state[idx] = NULL; + } + } + + ret = drm_release(inode, filp); + + if (!ret) { + MOD_DEC_USE_COUNT; + atomic_inc(&dev->total_close); + spin_lock(&dev->count_lock); + if (!--dev->open_count) { + if (atomic_read(&dev->ioctl_count) || dev->blocked) { + DRM_ERROR("Device busy: %d %d\n", + atomic_read(&dev->ioctl_count), + dev->blocked); + spin_unlock(&dev->count_lock); + return -EBUSY; + } + spin_unlock(&dev->count_lock); + return ffb_takedown(dev); + } + spin_unlock(&dev->count_lock); + } + + return ret; +} + +static int ffb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int nr = DRM_IOCTL_NR(cmd); + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ioctl_desc_t *ioctl; + drm_ioctl_t *func; + int ret; + + atomic_inc(&dev->ioctl_count); + atomic_inc(&dev->total_ioctl); + ++priv->ioctl_count; + + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, priv->authenticated); + + if (nr >= FFB_IOCTL_COUNT) { + ret = -EINVAL; + } else { + ioctl = &ffb_ioctls[nr]; + func = ioctl->func; + + if (!func) { + DRM_DEBUG("no function\n"); + ret = -EINVAL; + } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) + || (ioctl->auth_needed && !priv->authenticated)) { + ret = -EACCES; + } else { + ret = (func)(inode, filp, cmd, arg); + } + } + + atomic_dec(&dev->ioctl_count); + + return ret; +} + +static int ffb_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_lock_t lock; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -EFAULT; + + if (lock.context == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", + lock.context, current->pid, dev->lock.hw_lock->lock, + lock.flags); + + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + lock.context)) { + dev->lock.pid = current->pid; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->total_locks); + break; /* Got lock */ + } + + /* Contention */ + atomic_inc(&dev->total_sleeps); + current->state = TASK_INTERRUPTIBLE; + current->policy |= SCHED_YIELD; + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev->lock.lock_queue, &entry); + + if (!ret && + (dev->last_context != lock.context)) + ffb_context_switch(dev, dev->last_context, lock.context); + + DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + return ret; +} + +int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_lock_t lock; + unsigned int old, new, prev, ctx; + int ret; + + ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)); + if (ret) + return -EFAULT; + + if ((ctx = lock.context) == DRM_KERNEL_CONTEXT) { + DRM_ERROR("Process %d using kernel context %d\n", + current->pid, lock.context); + return -EINVAL; + } + + DRM_DEBUG("%d frees lock (%d holds)\n", + lock.context, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + atomic_inc(&dev->total_unlocks); + if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) + atomic_inc(&dev->total_contends); + + /* We no longer really hold it, but if we are the next + * agent to request it then we should just be able to + * take it immediately and not eat the ioctl. + */ + dev->lock.pid = 0; + { + __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; + + do { + old = *plock; + new = ctx; + prev = cmpxchg(plock, old, new); + } while (prev != old); + } + + wake_up_interruptible(&dev->lock.lock_queue); + + return 0; +} + +static void align_fb_mapping(struct vm_area_struct *vma) +{ + unsigned long j, alignment; + + j = vma->vm_end - vma->vm_start; + for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3) + if (j >= alignment) + break; + if (alignment > PAGE_SIZE) { + j = alignment; + alignment = j - (vma->vm_start & (j - 1)); + if (alignment != j) { + struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + alignment) { + vma->vm_start += alignment; + vma->vm_end += alignment; + } + } + } +} + +/* The problem here is, due to virtual cache aliasing, + * we must make sure the shared memory area lands in the + * same dcache line for both the kernel and all drm clients. + */ +static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt) +{ + kvirt &= PAGE_SIZE; + if ((vma->vm_start & PAGE_SIZE) != kvirt) { + struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); + + if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) { + vma->vm_start += PAGE_SIZE; + vma->vm_end += PAGE_SIZE; + } + } +} + +extern struct vm_operations_struct drm_vm_ops; +extern struct vm_operations_struct drm_vm_shm_ops; + +static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + ffb_dev_priv_t *ffb_priv; + int i, minor; + + DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", + vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + + minor = MINOR(filp->f_dentry->d_inode->i_rdev); + ffb_priv = NULL; + for (i = 0; i < ffb_dev_table_size; i++) { + ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1); + if (ffb_priv->miscdev.minor == minor) + break; + } + if (i >= ffb_dev_table_size) + return -EINVAL; + + /* We don't support/need dma mappings, so... */ + if (!VM_OFFSET(vma)) + return -EINVAL; + + for (i = 0; i < dev->map_count; i++) { + unsigned long off; + + map = dev->maplist[i]; + + /* Ok, a little hack to make 32-bit apps work. */ + off = (map->offset & 0xffffffff); + if (off == VM_OFFSET(vma)) + break; + } + + if (i >= dev->map_count) + return -EINVAL; + + if (!map || + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) + return -EPERM; + + if (map->size != (vma->vm_end - vma->vm_start)) + return -EINVAL; + + /* Set read-only attribute before mappings are created + * so it works for fb/reg maps too. + */ + if (map->flags & _DRM_READ_ONLY) + vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( + __pte(pgprot_val(vma->vm_page_prot))))); + + switch (map->type) { + case _DRM_FRAME_BUFFER: + align_fb_mapping(vma); + /* FALLTHROUGH */ + + case _DRM_REGISTERS: + /* In order to handle 32-bit drm apps/xserver we + * play a trick. The mappings only really specify + * the 32-bit offset from the cards 64-bit base + * address, and we just add in the base here. + */ + vma->vm_flags |= VM_IO; + if (io_remap_page_range(vma->vm_start, + ffb_priv->card_phys_base + VM_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot, 0)) + return -EAGAIN; + + vma->vm_ops = &drm_vm_ops; + break; + case _DRM_SHM: + align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock); + vma->vm_ops = &drm_vm_shm_ops; + + /* Don't let this area swap. Change when + * DRM_KERNEL advisory is supported. + */ + vma->vm_flags |= VM_LOCKED; + break; + default: + return -EINVAL; /* This should never happen. */ + }; + + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + + vma->vm_file = filp; /* Needed for drm_vm_open() */ + drm_vm_open(vma); + return 0; +} + +module_init(ffb_init); +module_exit(ffb_cleanup); diff --git a/drivers/char/drm/ffb_drv.h b/drivers/char/drm/ffb_drv.h new file mode 100644 index 000000000..094bbce09 --- /dev/null +++ b/drivers/char/drm/ffb_drv.h @@ -0,0 +1,276 @@ +/* $Id: ffb_drv.h,v 1.1 2000/06/01 04:24:39 davem Exp $ + * ffb_drv.h: Creator/Creator3D direct rendering driver. + * + * Copyright (C) 2000 David S. Miller (davem@redhat.com) + */ + +/* Auxilliary clips. */ +typedef struct { + volatile unsigned int min; + volatile unsigned int max; +} ffb_auxclip, *ffb_auxclipPtr; + +/* FFB register set. */ +typedef struct _ffb_fbc { + /* Next vertex registers, on the right we list which drawops + * use said register and the logical name the register has in + * that context. + */ /* DESCRIPTION DRAWOP(NAME) */ +/*0x00*/unsigned int pad1[3]; /* Reserved */ +/*0x0c*/volatile unsigned int alpha; /* ALPHA Transparency */ +/*0x10*/volatile unsigned int red; /* RED */ +/*0x14*/volatile unsigned int green; /* GREEN */ +/*0x18*/volatile unsigned int blue; /* BLUE */ +/*0x1c*/volatile unsigned int z; /* DEPTH */ +/*0x20*/volatile unsigned int y; /* Y triangle(DOYF) */ + /* aadot(DYF) */ + /* ddline(DYF) */ + /* aaline(DYF) */ +/*0x24*/volatile unsigned int x; /* X triangle(DOXF) */ + /* aadot(DXF) */ + /* ddline(DXF) */ + /* aaline(DXF) */ +/*0x28*/unsigned int pad2[2]; /* Reserved */ +/*0x30*/volatile unsigned int ryf; /* Y (alias to DOYF) ddline(RYF) */ + /* aaline(RYF) */ + /* triangle(RYF) */ +/*0x34*/volatile unsigned int rxf; /* X ddline(RXF) */ + /* aaline(RXF) */ + /* triangle(RXF) */ +/*0x38*/unsigned int pad3[2]; /* Reserved */ +/*0x40*/volatile unsigned int dmyf; /* Y (alias to DOYF) triangle(DMYF) */ +/*0x44*/volatile unsigned int dmxf; /* X triangle(DMXF) */ +/*0x48*/unsigned int pad4[2]; /* Reserved */ +/*0x50*/volatile unsigned int ebyi; /* Y (alias to RYI) polygon(EBYI) */ +/*0x54*/volatile unsigned int ebxi; /* X polygon(EBXI) */ +/*0x58*/unsigned int pad5[2]; /* Reserved */ +/*0x60*/volatile unsigned int by; /* Y brline(RYI) */ + /* fastfill(OP) */ + /* polygon(YI) */ + /* rectangle(YI) */ + /* bcopy(SRCY) */ + /* vscroll(SRCY) */ +/*0x64*/volatile unsigned int bx; /* X brline(RXI) */ + /* polygon(XI) */ + /* rectangle(XI) */ + /* bcopy(SRCX) */ + /* vscroll(SRCX) */ + /* fastfill(GO) */ +/*0x68*/volatile unsigned int dy; /* destination Y fastfill(DSTY) */ + /* bcopy(DSRY) */ + /* vscroll(DSRY) */ +/*0x6c*/volatile unsigned int dx; /* destination X fastfill(DSTX) */ + /* bcopy(DSTX) */ + /* vscroll(DSTX) */ +/*0x70*/volatile unsigned int bh; /* Y (alias to RYI) brline(DYI) */ + /* dot(DYI) */ + /* polygon(ETYI) */ + /* Height fastfill(H) */ + /* bcopy(H) */ + /* vscroll(H) */ + /* Y count fastfill(NY) */ +/*0x74*/volatile unsigned int bw; /* X dot(DXI) */ + /* brline(DXI) */ + /* polygon(ETXI) */ + /* fastfill(W) */ + /* bcopy(W) */ + /* vscroll(W) */ + /* fastfill(NX) */ +/*0x78*/unsigned int pad6[2]; /* Reserved */ +/*0x80*/unsigned int pad7[32]; /* Reserved */ + + /* Setup Unit's vertex state register */ +/*100*/ volatile unsigned int suvtx; +/*104*/ unsigned int pad8[63]; /* Reserved */ + + /* Frame Buffer Control Registers */ +/*200*/ volatile unsigned int ppc; /* Pixel Processor Control */ +/*204*/ volatile unsigned int wid; /* Current WID */ +/*208*/ volatile unsigned int fg; /* FG data */ +/*20c*/ volatile unsigned int bg; /* BG data */ +/*210*/ volatile unsigned int consty; /* Constant Y */ +/*214*/ volatile unsigned int constz; /* Constant Z */ +/*218*/ volatile unsigned int xclip; /* X Clip */ +/*21c*/ volatile unsigned int dcss; /* Depth Cue Scale Slope */ +/*220*/ volatile unsigned int vclipmin; /* Viewclip XY Min Bounds */ +/*224*/ volatile unsigned int vclipmax; /* Viewclip XY Max Bounds */ +/*228*/ volatile unsigned int vclipzmin; /* Viewclip Z Min Bounds */ +/*22c*/ volatile unsigned int vclipzmax; /* Viewclip Z Max Bounds */ +/*230*/ volatile unsigned int dcsf; /* Depth Cue Scale Front Bound */ +/*234*/ volatile unsigned int dcsb; /* Depth Cue Scale Back Bound */ +/*238*/ volatile unsigned int dczf; /* Depth Cue Z Front */ +/*23c*/ volatile unsigned int dczb; /* Depth Cue Z Back */ +/*240*/ unsigned int pad9; /* Reserved */ +/*244*/ volatile unsigned int blendc; /* Alpha Blend Control */ +/*248*/ volatile unsigned int blendc1; /* Alpha Blend Color 1 */ +/*24c*/ volatile unsigned int blendc2; /* Alpha Blend Color 2 */ +/*250*/ volatile unsigned int fbramitc; /* FB RAM Interleave Test Control */ +/*254*/ volatile unsigned int fbc; /* Frame Buffer Control */ +/*258*/ volatile unsigned int rop; /* Raster OPeration */ +/*25c*/ volatile unsigned int cmp; /* Frame Buffer Compare */ +/*260*/ volatile unsigned int matchab; /* Buffer AB Match Mask */ +/*264*/ volatile unsigned int matchc; /* Buffer C(YZ) Match Mask */ +/*268*/ volatile unsigned int magnab; /* Buffer AB Magnitude Mask */ +/*26c*/ volatile unsigned int magnc; /* Buffer C(YZ) Magnitude Mask */ +/*270*/ volatile unsigned int fbcfg0; /* Frame Buffer Config 0 */ +/*274*/ volatile unsigned int fbcfg1; /* Frame Buffer Config 1 */ +/*278*/ volatile unsigned int fbcfg2; /* Frame Buffer Config 2 */ +/*27c*/ volatile unsigned int fbcfg3; /* Frame Buffer Config 3 */ +/*280*/ volatile unsigned int ppcfg; /* Pixel Processor Config */ +/*284*/ volatile unsigned int pick; /* Picking Control */ +/*288*/ volatile unsigned int fillmode; /* FillMode */ +/*28c*/ volatile unsigned int fbramwac; /* FB RAM Write Address Control */ +/*290*/ volatile unsigned int pmask; /* RGB PlaneMask */ +/*294*/ volatile unsigned int xpmask; /* X PlaneMask */ +/*298*/ volatile unsigned int ypmask; /* Y PlaneMask */ +/*29c*/ volatile unsigned int zpmask; /* Z PlaneMask */ +/*2a0*/ ffb_auxclip auxclip[4]; /* Auxilliary Viewport Clip */ + + /* New 3dRAM III support regs */ +/*2c0*/ volatile unsigned int rawblend2; +/*2c4*/ volatile unsigned int rawpreblend; +/*2c8*/ volatile unsigned int rawstencil; +/*2cc*/ volatile unsigned int rawstencilctl; +/*2d0*/ volatile unsigned int threedram1; +/*2d4*/ volatile unsigned int threedram2; +/*2d8*/ volatile unsigned int passin; +/*2dc*/ volatile unsigned int rawclrdepth; +/*2e0*/ volatile unsigned int rawpmask; +/*2e4*/ volatile unsigned int rawcsrc; +/*2e8*/ volatile unsigned int rawmatch; +/*2ec*/ volatile unsigned int rawmagn; +/*2f0*/ volatile unsigned int rawropblend; +/*2f4*/ volatile unsigned int rawcmp; +/*2f8*/ volatile unsigned int rawwac; +/*2fc*/ volatile unsigned int fbramid; + +/*300*/ volatile unsigned int drawop; /* Draw OPeration */ +/*304*/ unsigned int pad10[2]; /* Reserved */ +/*30c*/ volatile unsigned int lpat; /* Line Pattern control */ +/*310*/ unsigned int pad11; /* Reserved */ +/*314*/ volatile unsigned int fontxy; /* XY Font coordinate */ +/*318*/ volatile unsigned int fontw; /* Font Width */ +/*31c*/ volatile unsigned int fontinc; /* Font Increment */ +/*320*/ volatile unsigned int font; /* Font bits */ +/*324*/ unsigned int pad12[3]; /* Reserved */ +/*330*/ volatile unsigned int blend2; +/*334*/ volatile unsigned int preblend; +/*338*/ volatile unsigned int stencil; +/*33c*/ volatile unsigned int stencilctl; + +/*340*/ unsigned int pad13[4]; /* Reserved */ +/*350*/ volatile unsigned int dcss1; /* Depth Cue Scale Slope 1 */ +/*354*/ volatile unsigned int dcss2; /* Depth Cue Scale Slope 2 */ +/*358*/ volatile unsigned int dcss3; /* Depth Cue Scale Slope 3 */ +/*35c*/ volatile unsigned int widpmask; +/*360*/ volatile unsigned int dcs2; +/*364*/ volatile unsigned int dcs3; +/*368*/ volatile unsigned int dcs4; +/*36c*/ unsigned int pad14; /* Reserved */ +/*370*/ volatile unsigned int dcd2; +/*374*/ volatile unsigned int dcd3; +/*378*/ volatile unsigned int dcd4; +/*37c*/ unsigned int pad15; /* Reserved */ +/*380*/ volatile unsigned int pattern[32]; /* area Pattern */ +/*400*/ unsigned int pad16[8]; /* Reserved */ +/*420*/ volatile unsigned int reset; /* chip RESET */ +/*424*/ unsigned int pad17[247]; /* Reserved */ +/*800*/ volatile unsigned int devid; /* Device ID */ +/*804*/ unsigned int pad18[63]; /* Reserved */ +/*900*/ volatile unsigned int ucsr; /* User Control & Status Register */ +/*904*/ unsigned int pad19[31]; /* Reserved */ +/*980*/ volatile unsigned int mer; /* Mode Enable Register */ +/*984*/ unsigned int pad20[1439]; /* Reserved */ +} ffb_fbc, *ffb_fbcPtr; + +struct ffb_hw_context { + int is_2d_only; + + unsigned int ppc; + unsigned int wid; + unsigned int fg; + unsigned int bg; + unsigned int consty; + unsigned int constz; + unsigned int xclip; + unsigned int dcss; + unsigned int vclipmin; + unsigned int vclipmax; + unsigned int vclipzmin; + unsigned int vclipzmax; + unsigned int dcsf; + unsigned int dcsb; + unsigned int dczf; + unsigned int dczb; + unsigned int blendc; + unsigned int blendc1; + unsigned int blendc2; + unsigned int fbc; + unsigned int rop; + unsigned int cmp; + unsigned int matchab; + unsigned int matchc; + unsigned int magnab; + unsigned int magnc; + unsigned int pmask; + unsigned int xpmask; + unsigned int ypmask; + unsigned int zpmask; + unsigned int auxclip0min; + unsigned int auxclip0max; + unsigned int auxclip1min; + unsigned int auxclip1max; + unsigned int auxclip2min; + unsigned int auxclip2max; + unsigned int auxclip3min; + unsigned int auxclip3max; + unsigned int drawop; + unsigned int lpat; + unsigned int fontxy; + unsigned int fontw; + unsigned int fontinc; + unsigned int area_pattern[32]; + unsigned int ucsr; + unsigned int stencil; + unsigned int stencilctl; + unsigned int dcss1; + unsigned int dcss2; + unsigned int dcss3; + unsigned int dcs2; + unsigned int dcs3; + unsigned int dcs4; + unsigned int dcd2; + unsigned int dcd3; + unsigned int dcd4; + unsigned int mer; +}; + +#define FFB_MAX_CTXS 32 + +enum ffb_chip_type { + ffb1_prototype = 0, /* Early pre-FCS FFB */ + ffb1_standard, /* First FCS FFB, 100Mhz UPA, 66MHz gclk */ + ffb1_speedsort, /* Second FCS FFB, 100Mhz UPA, 75MHz gclk */ + ffb2_prototype, /* Early pre-FCS vertical FFB2 */ + ffb2_vertical, /* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk, + 75(SingleBuffer)/83(DoubleBuffer) MHz fclk */ + ffb2_vertical_plus, /* Second FCS FFB2/vertical, same timings */ + ffb2_horizontal, /* First FCS FFB2/horizontal, same timings as FFB2/vert */ + ffb2_horizontal_plus, /* Second FCS FFB2/horizontal, same timings */ + afb_m3, /* FCS Elite3D, 3 float chips */ + afb_m6 /* FCS Elite3D, 6 float chips */ +}; + +typedef struct ffb_dev_priv { + /* Misc software state. */ + int prom_node; + enum ffb_chip_type ffb_type; + u64 card_phys_base; + struct miscdevice miscdev; + + /* Controller registers. */ + ffb_fbcPtr regs; + + /* Context table. */ + struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; +} ffb_dev_priv_t; diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c index a823db356..76e0dc2c1 100644 --- a/drivers/char/drm/fops.c +++ b/drivers/char/drm/fops.c @@ -92,7 +92,8 @@ int drm_release(struct inode *inode, struct file *filp) DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", current->pid, dev->device, dev->open_count); - if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) + if (dev->lock.hw_lock != NULL + && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { DRM_ERROR("Process %d dead, freeing lock for context %d\n", current->pid, @@ -216,7 +217,7 @@ int drm_write_string(drm_device_t *dev, const char *s) if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); #else /* Parameter added in 2.3.21 */ - if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN); + kill_fasync(&dev->buf_async, SIGIO, POLL_IN); #endif DRM_DEBUG("waking\n"); wake_up_interruptible(&dev->buf_readers); diff --git a/drivers/char/drm/init.c b/drivers/char/drm/init.c index 7a0115e86..ad887490b 100644 --- a/drivers/char/drm/init.c +++ b/drivers/char/drm/init.c @@ -104,5 +104,9 @@ int drm_cpu_valid(void) #if defined(__i386__) if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */ #endif +#if defined(__sparc__) && !defined(__sparc_v9__) + if (1) + return 0; /* No cmpxchg before v9 sparc. */ +#endif return 1; } diff --git a/drivers/char/drm/proc.c b/drivers/char/drm/proc.c index 4d5d1a964..d44195539 100644 --- a/drivers/char/drm/proc.c +++ b/drivers/char/drm/proc.c @@ -512,9 +512,9 @@ static int _drm_histo_info(char *buf, char **start, off_t offset, int len, } else { DRM_PROC_PRINT("lock none\n"); } - DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag); - DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag); - DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag); + DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag); + DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); + DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag); DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); DRM_PROC_PRINT("last_context %10d\n", dev->last_context); diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 5a89e008a..f0c76181b 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -311,22 +311,6 @@ ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned return 0; } -static int -ds1620_open(struct inode *inode, struct file *file) -{ - MOD_INC_USE_COUNT; - - return 0; -} - -static int -ds1620_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; - - return 0; -} - #ifdef THERM_USE_PROC static int proc_therm_ds1620_read(char *buf, char **start, off_t offset, @@ -352,10 +336,9 @@ static struct proc_dir_entry *proc_therm_ds1620; #endif static struct file_operations ds1620_fops = { + owner: THIS_MODULE, read: ds1620_read, ioctl: ds1620_ioctl, - open: ds1620_open, - release: ds1620_release, }; static struct miscdevice ds1620_miscdev = { diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index ac27c9e0e..dc076dd5a 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -472,10 +472,6 @@ static int dsp56k_open(struct inode *inode, struct file *file) return -ENXIO; } -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif /* MODULE */ - return 0; } @@ -495,13 +491,11 @@ static int dsp56k_release(struct inode *inode, struct file *file) return -ENXIO; } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return 0; } static struct file_operations dsp56k_fops = { + owner: THIS_MODULE, read: dsp56k_read, write: dsp56k_write, ioctl: dsp56k_ioctl, diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 542ad99bf..730b69b17 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -102,6 +102,7 @@ static int dtlk_ioctl(struct inode *inode, struct file *file, static struct file_operations dtlk_fops = { + owner: THIS_MODULE, read: dtlk_read, write: dtlk_write, poll: dtlk_poll, @@ -306,7 +307,6 @@ static int dtlk_ioctl(struct inode *inode, static int dtlk_open(struct inode *inode, struct file *file) { - MOD_INC_USE_COUNT; TRACE_TEXT("(dtlk_open"); switch (MINOR(inode->i_rdev)) { @@ -322,7 +322,6 @@ static int dtlk_open(struct inode *inode, struct file *file) static int dtlk_release(struct inode *inode, struct file *file) { - MOD_DEC_USE_COUNT; TRACE_TEXT("(dtlk_release"); switch (MINOR(inode->i_rdev)) { diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 103e60eef..9ad85c687 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -281,6 +281,7 @@ efi_rtc_close(struct inode *inode, struct file *file) */ static struct file_operations efi_rtc_fops = { + owner: THIS_MODULE, ioctl: efi_rtc_ioctl, open: efi_rtc_open, release: efi_rtc_close, diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 9238ae3eb..13656af4b 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -4007,6 +4007,9 @@ static int __init epca_init_one (struct pci_dev *pdev, int board_idx, info_idx = ent->driver_data; unsigned long addr; + if (pci_enable_device(pdev)) + return -EIO; + board_num++; board_idx = board_num + num_cards; if (board_idx >= MAXBOARDS) diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index dfe89b970..01eb20e92 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -330,7 +330,7 @@ int gs_chars_in_buffer(struct tty_struct *tty) int gs_real_chars_in_buffer(struct tty_struct *tty) { - struct gs_port *port = tty->driver_data; + struct gs_port *port; func_enter (); if (!tty) return 0; diff --git a/drivers/char/hp600_keyb.c b/drivers/char/hp600_keyb.c new file mode 100644 index 000000000..52f66ba5f --- /dev/null +++ b/drivers/char/hp600_keyb.c @@ -0,0 +1,119 @@ +/* + * $Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * HP600 keyboard scan routine and translate table + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include "scan_keyb.h" + +#define PCDR 0xa4000124 +#define PDDR 0xa4000126 +#define PEDR 0xa4000128 +#define PFDR 0xa400012a +#define PGDR 0xa400012c +#define PHDR 0xa400012e + +static const unsigned char hp690_japanese_table[]={ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a, + 0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b, + + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35, + 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, + 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d, + + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27, + 0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f, + + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, + + 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19, + 0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11, + + 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b, + 0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + + +static void hp690_japanese_scan_kbd(unsigned char *s) +{ + ctrl_outb(0xfd, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xdf, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0x7f, PDDR); ctrl_outb(0xff, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xfe, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xfd, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xf7, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0xbf, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + ctrl_outb(0xff, PDDR); ctrl_outb(0x7f, PEDR); + *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR); + *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR); +} + + +void __init hp600_kbd_init_hw(void) +{ + scan_kbd_init(); + register_scan_keyboard(hp690_japanese_scan_kbd, + hp690_japanese_table, 18); + printk(KERN_INFO "HP600 matrix scan keyboard registered\n"); +} + + +/**************************************************************** +HP Jornada 690(Japanese version) keyboard scan matrix + + PTC7 PTC6 PTC5 PTC4 PTC3 PTC2 PTC1 PTC0 +PTD1 REC Escape on/off Han/Zen Hira Eisu +PTD5 REC Z on/off Enter : / +PTD7 REC Right Down +PTE0 REC Windows on/off +PTE1 REC A on/off ] [ ; +PTE3 REC Tab on/off ShirtR \ Up +PTE6 REC Q on/off BS @ P +PTE7 REC 1 on/off ^ - 0 + + + PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0 +PTD1 F5 F4 F6 F7 F8 F3 F2 F1 +PTD5 N B M , . V C X +PTD7 Muhen Alt Left +PTE0 Henkan _ Del Space Ctrl +PTE1 H G J K L F D S +PTE3 ShiftL +PTE6 Y T U I O R E W +PTE7 6 5 7 8 9 4 3 2 + + PTG5 PTG4 PTG3 PTG0 PTH0 +* REC REW FWW Cover on/off + + + 7 6 5 4 3 2 1 0 +C: 0xffff 0xdf IP IP IP IP IP IP IP IP +D: 0x6786 0x59 O I O IP I F O I +E: 0x5045 0x00 O O F F O F O O +F: 0xffff 0xff IP IP IP IP IP IP IP IP +G: 0xaffe 0xfd I I IP IP IP IP IP I +H: 0x70f2 0x49 O IP F F IP IP F I +J: 0x0704 0x22 F F O IP F F O F +K: 0x0100 0x10 F F F O F F F F +L: 0x0c3c 0x26 F F IP F F IP IP F + +****************************************************************/ diff --git a/drivers/char/i2c-old.c b/drivers/char/i2c-old.c index bd9750fc3..b509c9a18 100644 --- a/drivers/char/i2c-old.c +++ b/drivers/char/i2c-old.c @@ -37,8 +37,8 @@ static struct i2c_driver *drivers[I2C_DRIVER_MAX]; static int bus_count = 0, driver_count = 0; #ifdef CONFIG_VIDEO_BT848 -extern int i2c_tuner_init(void); -extern int msp3400c_init(void); +extern int tuner_init_module(void); +extern int msp3400_init_module(void); #endif #ifdef CONFIG_VIDEO_BUZ extern int saa7111_init(void); @@ -55,8 +55,8 @@ int i2c_init(void) scan ? " (i2c bus scan enabled)" : ""); /* anything to do here ? */ #ifdef CONFIG_VIDEO_BT848 - i2c_tuner_init(); - msp3400c_init(); + tuner_init_module(); + msp3400_init_module(); #endif #ifdef CONFIG_VIDEO_BUZ saa7111_init(); diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c new file mode 100644 index 000000000..191ce5001 --- /dev/null +++ b/drivers/char/i810_rng.c @@ -0,0 +1,885 @@ +/* + + Hardware driver for Intel i810 Random Number Generator (RNG) + Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com> + + Driver Web site: http://gtf.org/garzik/drivers/i810_rng/ + + + + Based on: + Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet + May 1999 Order Number: 290658-002 R + + Intel 82802 Firmware Hub: Random Number Generator + Programmer's Reference Manual + December 1999 Order Number: 298029-001 R + + Intel 82802 Firmware HUB Random Number Generator Driver + Copyright (c) 2000 Matt Sottek <msottek@quiknet.com> + + Special thanks to Matt Sottek. I did the "guts", he + did the "brains" and all the testing. (Anybody wanna send + me an i810 or i820?) + + ---------------------------------------------------------- + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + ---------------------------------------------------------- + + From the firmware hub datasheet: + + The Firmware Hub integrates a Random Number Generator (RNG) + using thermal noise generated from inherently random quantum + mechanical properties of silicon. When not generating new random + bits the RNG circuitry will enter a low power state. Intel will + provide a binary software driver to give third party software + access to our RNG for use as a security feature. At this time, + the RNG is only to be used with a system in an OS-present state. + + ---------------------------------------------------------- + + Theory of operation: + + This driver has TWO modes of operation: + + Mode 1 + ------ + Character driver. Using the standard open() + and read() system calls, you can read random data from + the i810 RNG device. This data is NOT CHECKED by any + fitness tests, and could potentially be bogus (if the + hardware is faulty or has been tampered with). + + /dev/intel_rng is char device major 10, minor 183. + + + Mode 2 + ------ + Injection of entropy into the kernel entropy pool via a + timer function. + + A timer is run at RNG_TIMER_LEN intervals, reading 8 bits + of data from the RNG. If the RNG has previously passed a + FIPS test, then the data will be added to the /dev/random + entropy pool. Then, those 8 bits are added to an internal + test data pool. When that pool is full, a FIPS test is + run to verify that the last N bytes read are decently random. + + Thus, the RNG will never be enabled until it passes a + FIPS test. And, data will stop flowing into the system + entropy pool if the data is determined to be non-random. + + Finally, note that the timer defaults to OFF. This ensures + that the system entropy pool will not be polluted with + RNG-originated data unless a conscious decision is made + by the user. + + HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS + BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST. + + ---------------------------------------------------------- + + Driver notes: + + * You may enable and disable the RNG hardware (and this + driver) via sysctl: + + # disable RNG + echo 0 > /proc/sys/dev/i810_hw_enabled + + # enable RNG + echo 1 > /proc/sys/dev/i810_hw_enabled + + * The default number of entropy bits added by default is + the full 8 bits. If you wish to reduce this value for + paranoia's sake, you can do so via sysctl as well: + + # Add only 4 bits of entropy to /dev/random + echo 4 > /proc/sys/dev/i810_rng_entropy + + * The default number of entropy bits can also be set via + a module parameter "rng_entropy" at module load time. + + * In order to unload the i810_rng module, you must first + disable the hardware via sysctl i810_hw_enabled, as shown above, + and make sure all users of the character device + + */ + + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/random.h> +#include <linux/sysctl.h> +#include <linux/miscdevice.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + + +/* + * core module and version information + */ +#define RNG_VERSION "0.6.1" +#define RNG_MODULE_NAME "i810_rng" +#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION +#define PFX RNG_MODULE_NAME ": " + + +/* + * debugging macros + */ +#undef RNG_DEBUG /* define to 1 to enable copious debugging info */ + +#ifdef RNG_DEBUG +/* note: prints function name for you */ +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */ +#if RNG_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(!(expr)) { \ + printk( "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + + +/* + * misc helper macros + */ +#define arraysize(x) (sizeof(x)/sizeof(*(x))) + +/* + * prototypes + */ +static void rng_fips_test_store (int rng_data); +static void rng_run_fips_test (void); + + +/* + * RNG registers (offsets from rng_mem) + */ +#define RNG_HW_STATUS 0 +#define RNG_PRESENT 0x40 +#define RNG_ENABLED 0x01 +#define RNG_STATUS 1 +#define RNG_DATA_PRESENT 0x01 +#define RNG_DATA 2 + +#define RNG_ADDR 0xFFBC015F +#define RNG_ADDR_LEN 3 + +#define RNG_MAX_ENTROPY 8 /* max entropy h/w is capable of */ + +#define RNG_MISCDEV_MINOR 183 /* official */ + + +/* + * Frequency that data is added to kernel entropy pool + * HZ>>1 == every half-second + */ +#define RNG_TIMER_LEN (HZ >> 1) + + +/* + * number of bytes required for a FIPS test. + * do not alter unless you really, I mean + * REALLY know what you are doing. + */ +#define RNG_FIPS_TEST_THRESHOLD 2500 + + +/* + * various RNG status variables. they are globals + * as we only support a single RNG device + */ +static int rng_allocated = 0; /* is someone using the RNG region? */ +static int rng_hw_enabled = 0; /* is the RNG h/w, and timer, enabled? */ +static int rng_trusted = 0; /* does FIPS trust out data? */ +static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ +static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ +static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ +static int rng_have_mem_region = 0; /* did we grab RNG region via request_mem_region? */ +static int rng_fips_counter = 0; /* size of internal FIPS test data pool */ +static void *rng_mem = NULL; /* token to our ioremap'd RNG register area */ +static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ +static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */ +static atomic_t rng_open; + +/* + * inlined helper functions for accessing RNG registers + */ +static inline u8 rng_hwstatus (void) +{ + assert (rng_mem != NULL); + return readb (rng_mem + RNG_HW_STATUS); +} + + +static inline void rng_hwstatus_set (u8 hw_status) +{ + assert (rng_mem != NULL); + writeb (hw_status, rng_mem + RNG_HW_STATUS); +} + + +static inline int rng_data_present (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0; +} + + +static inline int rng_data_read (void) +{ + assert (rng_mem != NULL); + assert (rng_hw_enabled == 1); + + return readb (rng_mem + RNG_DATA); +} + + +/* + * rng_timer_ticker - executes every RNG_TIMER_LEN jiffies, + * adds a single byte to system entropy + * and internal FIPS test pools + */ +static void rng_timer_tick (unsigned long data) +{ + unsigned long flags; + int rng_data; + + spin_lock_irqsave (&rng_lock, flags); + + if (rng_data_present ()) { + /* gimme some thermal noise, baby */ + rng_data = rng_data_read (); + + /* + * if RNG has been verified in the past, add + * data just read to the /dev/random pool, + * with the entropy specified by the user + * via sysctl (defaults to 8 bits) + */ + if (rng_trusted) + batch_entropy_store (rng_data, jiffies, rng_entropy); + + /* fitness testing via FIPS, if we have enough data */ + rng_fips_test_store (rng_data); + if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) + rng_run_fips_test (); + } + + spin_unlock_irqrestore (&rng_lock, flags); + + /* run the timer again */ + rng_timer.expires = jiffies + RNG_TIMER_LEN; + add_timer (&rng_timer); +} + + +/* + * rng_enable - enable or disable the RNG and internal timer + */ +static int rng_enable (int enable) +{ + unsigned long flags; + int rc = 0; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + + hw_status = rng_hwstatus (); + + if (enable && !rng_hw_enabled) { + rng_hwstatus_set (hw_status | RNG_ENABLED); + + printk (KERN_INFO PFX "RNG h/w enabled\n"); + rng_hw_enabled = 1; + MOD_INC_USE_COUNT; + } + + else if (!enable && rng_hw_enabled) { + del_timer (&rng_timer); + + rng_hwstatus_set (hw_status & ~RNG_ENABLED); + + printk (KERN_INFO PFX "RNG h/w disabled\n"); + rng_hw_enabled = 0; + MOD_DEC_USE_COUNT; + } + + if (enable != (rng_hwstatus () & RNG_ENABLED) ) { + del_timer (&rng_timer); + printk (KERN_ERR PFX "Unable to %sable the RNG\n", + enable ? "en" : "dis"); + rc = -EIO; + } + + spin_unlock_irqrestore (&rng_lock, flags); + + DPRINTK ("EXIT, returning %d\n", rc); + return rc; +} + + +/* + * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl + */ + +static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + unsigned long flags; + int enabled_save, rc; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + rng_enabled_sysctl = enabled_save = rng_hw_enabled; + spin_unlock_irqrestore (&rng_lock, flags); + + rc = proc_dointvec (table, write, filp, buffer, lenp); + if (rc) + return rc; + + if (enabled_save != rng_enabled_sysctl) + rng_enable (rng_enabled_sysctl); + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl + */ + +static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp, + void *buffer, size_t * lenp) +{ + unsigned long flags; + int entropy_bits_save, rc; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + rng_entropy_sysctl = entropy_bits_save = rng_entropy; + spin_unlock_irqrestore (&rng_lock, flags); + + rc = proc_dointvec (table, write, filp, buffer, lenp); + if (rc) + return rc; + + if (entropy_bits_save == rng_entropy_sysctl) + goto out; + + if ((rng_entropy_sysctl >= 0) && + (rng_entropy_sysctl <= 8)) { + spin_lock_irqsave (&rng_lock, flags); + rng_entropy = rng_entropy_sysctl; + spin_unlock_irqrestore (&rng_lock, flags); + + printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl); + } else { + printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n", + rng_entropy_sysctl); + } + +out: + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_sysctl - add or remove the rng sysctl + */ +static void rng_sysctl (int add) +{ +#define DEV_I810_RNG 1 +#define DEV_I810_RNG_ENTROPY 2 + /* Definition of the sysctl */ + static ctl_table rng_sysctls[] = { + {DEV_I810_RNG, /* ID */ + RNG_MODULE_NAME "_enabled", /* name in /proc */ + &rng_enabled_sysctl, + sizeof (rng_enabled_sysctl), /* data ptr, data size */ + 0644, /* mode */ + 0, /* child */ + rng_handle_sysctl_enable, /* proc handler */ + 0, /* strategy */ + 0, /* proc control block */ + 0, 0} + , + {DEV_I810_RNG_ENTROPY, /* ID */ + RNG_MODULE_NAME "_entropy", /* name in /proc */ + &rng_entropy_sysctl, + sizeof (rng_entropy_sysctl), /* data ptr, data size */ + 0644, /* mode */ + 0, /* child */ + rng_handle_sysctl_entropy, /* proc handler */ + 0, /* strategy */ + 0, /* proc control block */ + 0, 0} + , + {0} + }; + + /* Define the parent file : /proc/sys/dev */ + static ctl_table sysctls_root[] = { + {CTL_DEV, + "dev", + NULL, 0, + 0555, + rng_sysctls}, + {0} + }; + static struct ctl_table_header *sysctls_root_header = NULL; + + if (add) { + if (!sysctls_root_header) + sysctls_root_header = register_sysctl_table (sysctls_root, 0); + } else if (sysctls_root_header) { + unregister_sysctl_table (sysctls_root_header); + sysctls_root_header = NULL; + } +} + + +static int rng_dev_open (struct inode *inode, struct file *filp) +{ + int rc = -EINVAL; + unsigned long flags; + + if ((filp->f_mode & FMODE_READ) == 0) + goto err_out; + if (filp->f_mode & FMODE_WRITE) + goto err_out; + + spin_lock_irqsave (&rng_lock, flags); + + if (atomic_read(&rng_open)) { + spin_unlock_irqrestore (&rng_lock, flags); + rc = -EBUSY; + goto err_out; + } + + atomic_set (&rng_open, 1); + + spin_unlock_irqrestore (&rng_lock, flags); + + if (rng_enable(1) != 0) { + spin_lock_irqsave (&rng_lock, flags); + atomic_set (&rng_open, 0); + spin_unlock_irqrestore (&rng_lock, flags); + rc = -EIO; + goto err_out; + } + + return 0; + +err_out: + return rc; +} + + +static int rng_dev_release (struct inode *inode, struct file *filp) +{ + unsigned long flags; + + if (rng_enable(0) != 0) + return -EIO; + + spin_lock_irqsave (&rng_lock, flags); + atomic_set (&rng_open, 0); + spin_unlock_irqrestore (&rng_lock, flags); + + return 0; +} + + +static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size, + loff_t *offp) +{ + int have_data, copied = 0; + unsigned long flags; + u8 data=0; + u8 *page; + + if (size < 1) + return 0; + + page = (unsigned char *) get_zeroed_page (GFP_KERNEL); + if (!page) + return -ENOMEM; + +read_loop: + /* using the fact that read() can return >0 but + * less than the requested amount, we simply + * read up to PAGE_SIZE or buffer size, whichever + * is smaller, and return that data. + */ + if ((copied == size) || (copied == PAGE_SIZE)) { + size_t tmpsize = (copied == size) ? size : PAGE_SIZE; + int rc = copy_to_user (buf, page, tmpsize); + free_page ((long)page); + if (rc) return rc; + return tmpsize; + } + + spin_lock_irqsave (&rng_lock, flags); + + have_data = 0; + if (rng_data_present ()) { + data = rng_data_read (); + have_data = 1; + } + + spin_unlock_irqrestore (&rng_lock, flags); + + if (have_data) { + page[copied] = data; + copied++; + } else { + if (filp->f_flags & O_NONBLOCK) { + free_page ((long)page); + return -EAGAIN; + } + } + + if (current->need_resched) + schedule (); + + if (signal_pending (current)) { + free_page ((long)page); + return -ERESTARTSYS; + } + + goto read_loop; +} + + +/* + * rng_init_one - look for and attempt to init a single RNG + */ +static int __init rng_init_one (struct pci_dev *dev, + const struct pci_device_id *id) +{ + int rc; + u8 hw_status; + + DPRINTK ("ENTER\n"); + + if (rng_allocated) { + printk (KERN_ERR PFX "this driver only supports one RNG\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + return -EBUSY; + } + + /* XXX currently fails, investigate who has our mem region */ + if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) + rng_have_mem_region = 1; + + rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN); + if (rng_mem == NULL) { + printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); + DPRINTK ("EXIT, returning -EBUSY\n"); + rc = -EBUSY; + goto err_out; + } + + /* Check for Intel 82802 */ + hw_status = rng_hwstatus (); + if ((hw_status & RNG_PRESENT) == 0) { + printk (KERN_ERR PFX "RNG not detected\n"); + DPRINTK ("EXIT, returning -ENODEV\n"); + rc = -ENODEV; + goto err_out; + } + + rng_allocated = 1; + + if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) + rng_entropy = RNG_MAX_ENTROPY; + + /* init core RNG timer, but do not add it */ + init_timer (&rng_timer); + rng_timer.function = rng_timer_tick; + + rc = rng_enable (0); + if (rc) { + printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); + goto err_out; + } + + /* add sysctls */ + rng_sysctl (1); + + DPRINTK ("EXIT, returning 0\n"); + return 0; + +err_out: + if (rng_mem) + iounmap (rng_mem); + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); + return rc; +} + + +/* + * Data for PCI driver interface + */ +const static struct pci_device_id rng_pci_tbl[] __initdata = { + { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, + { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; +MODULE_DEVICE_TABLE (pci, rng_pci_tbl); + +static struct pci_driver rng_driver = { + name: RNG_MODULE_NAME, + id_table: rng_pci_tbl, + probe: rng_init_one, +}; + +MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); +MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); +MODULE_PARM(rng_entropy, "1i"); +MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)"); + + +static struct file_operations rng_chrdev_ops = { + owner: THIS_MODULE, + open: rng_dev_open, + release: rng_dev_release, + read: rng_dev_read, +}; + + +static struct miscdevice rng_miscdev = { + RNG_MISCDEV_MINOR, + RNG_MODULE_NAME, + &rng_chrdev_ops, +}; + + +/* + * rng_init - initialize RNG module + */ +static int __init rng_init (void) +{ + int rc; + + DPRINTK ("ENTER\n"); + + MOD_INC_USE_COUNT; + + if (pci_register_driver (&rng_driver) < 1) { + DPRINTK ("EXIT, returning -ENODEV\n"); + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + rc = misc_register (&rng_miscdev); + if (rc) { + pci_unregister_driver (&rng_driver); + DPRINTK ("EXIT, returning %d\n", rc); + MOD_DEC_USE_COUNT; + return rc; + } + + printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + + /* FIXME: verify module unload logic, then remove + * this additional MOD_INC_USE_COUNT */ + MOD_INC_USE_COUNT; + + MOD_DEC_USE_COUNT; /* init complete, unload allowed now */ + + DPRINTK ("EXIT, returning 0\n"); + return 0; +} + + +/* + * rng_init - shutdown RNG module + */ +static void __exit rng_cleanup (void) +{ + unsigned long flags; + + DPRINTK ("ENTER\n"); + + spin_lock_irqsave (&rng_lock, flags); + del_timer (&rng_timer); + spin_unlock_irqrestore (&rng_lock, flags); + + rng_sysctl (0); + pci_unregister_driver (&rng_driver); + + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); + + rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED); + + misc_deregister (&rng_miscdev); + + DPRINTK ("EXIT\n"); +} + + +module_init (rng_init); +module_exit (rng_cleanup); + + + + +/* These are the startup tests suggested by the FIPS 140-1 spec section +* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm) +* The Monobit, Poker, Runs, and Long Runs tests are implemented below. +* This test is run at periodic intervals to verify +* data is sufficently random. If the tests are failed the RNG module +* will no longer submit data to the entropy pool, but the tests will +* continue to run at the given interval. If at a later time the RNG +* passes all tests it will be re-enabled for the next period. +* The reason for this is that it is not unlikely that at some time +* during normal operation one of the tests will fail. This does not +* necessarily mean the RNG is not operating properly, it is just a +* statistically rare event. In that case we don't want to forever +* disable the RNG, we will just leave it disabled for the period of +* time until the tests are rerun and passed. +* +* For argument sake I tested /proc/urandom with these tests and it +* took 142,095 tries before I got a failure, and urandom isn't as +* random as random :) +*/ + +static int poker[16] = { 0, }, runs[12] = { 0, }; +static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0; + + +/* + * rng_fips_test_store - store 8 bits of entropy in FIPS + * internal test data pool + */ +static void rng_fips_test_store (int rng_data) +{ + int j; + static int last_bit = 0; + + DPRINTK ("ENTER, rng_data = %d\n", rng_data & 0xFF); + + poker[rng_data >> 4]++; + poker[rng_data & 15]++; + + /* Note in the loop below rlength is always one less than the actual + run length. This makes things easier. */ + last_bit = (rng_data & 128) >> 7; + for (j = 7; j >= 0; j--) { + ones += current_bit = (rng_data & 1 << j) >> j; + if (current_bit != last_bit) { + /* If runlength is 1-6 count it in correct bucket. 0's go in + runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */ + if (rlength < 5) { + runs[rlength + + (6 * current_bit)]++; + } else { + runs[5 + (6 * current_bit)]++; + } + + /* Check if we just failed longrun test */ + if (rlength >= 33) + rng_test &= 8; + rlength = 0; + /* flip the current run type */ + last_bit = current_bit; + } else { + rlength++; + } + } + + DPRINTK ("EXIT\n"); +} + + +/* + * now that we have some data, run a FIPS test + */ +static void rng_run_fips_test (void) +{ + int j, i; + + DPRINTK ("ENTER\n"); + + /* add in the last (possibly incomplete) run */ + if (rlength < 5) + runs[rlength + (6 * current_bit)]++; + else { + runs[5 + (6 * current_bit)]++; + if (rlength >= 33) + rng_test &= 8; + } + /* Ones test */ + if ((ones >= 10346) || (ones <= 9654)) + rng_test &= 1; + /* Poker calcs */ + for (i = 0, j = 0; i < 16; i++) + j += poker[i] * poker[i]; + if ((j >= 1580457) || (j <= 1562821)) + rng_test &= 2; + if ((runs[0] < 2267) || (runs[0] > 2733) || + (runs[1] < 1079) || (runs[1] > 1421) || + (runs[2] < 502) || (runs[2] > 748) || + (runs[3] < 223) || (runs[3] > 402) || + (runs[4] < 90) || (runs[4] > 223) || + (runs[5] < 90) || (runs[5] > 223) || + (runs[6] < 2267) || (runs[6] > 2733) || + (runs[7] < 1079) || (runs[7] > 1421) || + (runs[8] < 502) || (runs[8] > 748) || + (runs[9] < 223) || (runs[9] > 402) || + (runs[10] < 90) || (runs[10] > 223) || + (runs[11] < 90) || (runs[11] > 223)) { + rng_test &= 4; + } + + rng_test = !rng_test; + DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail"); + + /* enable/disable RNG with results of the tests */ + if (rng_test && !rng_trusted) + printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n"); + else if (!rng_test && rng_trusted) + printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n"); + + rng_trusted = rng_test; + + /* finally, clear out FIPS variables for start of next run */ + memset (&poker, 0, sizeof (poker)); + memset (&runs, 0, sizeof (runs)); + ones = 0; + rlength = -1; + current_bit = 0; + rng_test = 0; + + DPRINTK ("EXIT\n"); +} + diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 6b42c7f63..033eb9aaf 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -311,6 +311,7 @@ static struct termios * TermiosLocked[IP2_MAX_PORTS]; * download the loadware to the boards. */ static struct file_operations ip2_ipl = { + owner: THIS_MODULE, read: ip2_ipl_read, write: ip2_ipl_write, ioctl: ip2_ipl_ioctl, @@ -3202,8 +3203,6 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile ) printk (KERN_DEBUG "IP2IPL: open\n" ); #endif - //MOD_INC_USE_COUNT; // Needs close entry with decrement. - switch(iplminor) { // These are the IPL devices case 0: diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 958fbf776..52c6b5f19 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -86,8 +86,6 @@ static char re_schedule = 1; static unsigned long tx_count = 0; #endif -static int ISILoad_open(struct inode *inode, struct file *filp); -static int ISILoad_release(struct inode *inode, struct file *filp); static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); static void isicom_tx(unsigned long _data); @@ -109,9 +107,8 @@ static signed char linuxb_to_isib[] = { */ static struct file_operations ISILoad_fops = { + owner: THIS_MODULE, ioctl: ISILoad_ioctl, - open: ISILoad_open, - release: ISILoad_release, }; struct miscdevice isiloader_device = { @@ -129,24 +126,6 @@ extern inline int WaitTillCardIsFree(unsigned short base) return 1; } -static int ISILoad_open(struct inode *inode, struct file *filp) -{ -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n"); -#endif - MOD_INC_USE_COUNT; - return 0; -} - -static int ISILoad_release(struct inode *inode, struct file *filp) -{ -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",); -#endif - MOD_DEC_USE_COUNT; - return 0; -} - static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 5733fac43..8d16c9daf 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -687,8 +687,6 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p static int stli_brdinit(stlibrd_t *brdp); static int stli_startbrd(stlibrd_t *brdp); -static int stli_memopen(struct inode *ip, struct file *fp); -static int stli_memclose(struct inode *ip, struct file *fp); static ssize_t stli_memread(struct file *fp, char *buf, size_t count, loff_t *offp); static ssize_t stli_memwrite(struct file *fp, const char *buf, size_t count, loff_t *offp); static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); @@ -780,11 +778,10 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp); * board. This is also a very useful debugging tool. */ static struct file_operations stli_fsiomem = { + owner: THIS_MODULE, read: stli_memread, write: stli_memwrite, ioctl: stli_memioctl, - open: stli_memopen, - release: stli_memclose, }; /*****************************************************************************/ @@ -5183,27 +5180,6 @@ static int stli_getbrdstruct(unsigned long arg) /*****************************************************************************/ /* - * Memory device open code. Need to keep track of opens and close - * for module handling. - */ - -static int stli_memopen(struct inode *ip, struct file *fp) -{ - MOD_INC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -static int stli_memclose(struct inode *ip, struct file *fp) -{ - MOD_DEC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -/* * The "staliomem" device is also required to do some special operations on * the board. We need to be able to send an interrupt to the board, * reset it, and start/stop it. diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c index 5e3198f70..8c0ba6923 100644 --- a/drivers/char/joystick/joy-amiga.c +++ b/drivers/char/joystick/joy-amiga.c @@ -78,26 +78,6 @@ static int js_am_read(void *info, int **axes, int **buttons) } /* - * js_am_open() is a callback from the file open routine. - */ - -static int js_am_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_am_close() is a callback from the file release routine. - */ - -static int js_am_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_am_init_corr() initializes correction values of * Amiga joysticks. */ @@ -139,7 +119,7 @@ int __init js_am_init(void) if (js_am[i]) { js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read); printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n", - js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", js_am_open, js_am_close), i); + js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", THIS_MODULE, NULL, NULL), i); js_am_init_corr(js_am_port->corr); } if (js_am_port) return 0; diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c index a4a7b9849..f73ee8ded 100644 --- a/drivers/char/joystick/joy-analog.c +++ b/drivers/char/joystick/joy-analog.c @@ -153,26 +153,6 @@ static int js_an_read(void *xinfo, int **axes, int **buttons) } /* - * js_an_open() is a callback from the file open routine. - */ - -static int js_an_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_an_close() is a callback from the file release routine. - */ - -static int js_an_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_an_calibrate_timer() calibrates the timer and computes loop * and timeout values for a joystick port. */ @@ -248,7 +228,7 @@ static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct j for (i = 0; i < numdev; i++) printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n", js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an), - js_an_name(i, &ax->an), js_an_open, js_an_close), + js_an_name(i, &ax->an), THIS_MODULE, NULL, NULL), js_an_name(i, &ax->an), ax->io, ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed, diff --git a/drivers/char/joystick/joy-assassin.c b/drivers/char/joystick/joy-assassin.c index b76ba8e36..469c6c8ce 100644 --- a/drivers/char/joystick/joy-assassin.c +++ b/drivers/char/joystick/joy-assassin.c @@ -177,26 +177,6 @@ static int js_as_read(void *xinfo, int **axes, int **buttons) } /* - * js_as_open() is a callback from the file open routine. - */ - -static int js_as_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_as_close() is a callback from the file release routine. - */ - -static int js_as_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_as_pxl_init_corr() initializes the correction values for * the Panther XL. */ @@ -317,13 +297,13 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j if (info->mode == JS_AS_MODE_PXL) { printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n", - js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close), + js_register_device(port, 0, 9, 9, "MadCatz Panther XL", THIS_MODULE, NULL, NULL), info->io); js_as_read(port->info, port->axes, port->buttons); js_as_pxl_init_corr(port->corr, port->axes); if (info->an.axes[0] < 254) { printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n", - js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close)); + js_register_device(port, 1, 1, 0, "Analog rudder", THIS_MODULE, NULL, NULL)); info->rudder = 1; port->axes[1][0] = info->an.axes[0]; js_as_rudder_init_corr(port->corr, port->axes); @@ -339,7 +319,7 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j } printk(KERN_INFO "js%d: %s at %#x\n", - js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close), + js_register_device(port, 0, 2, 3, name, THIS_MODULE, NULL, NULL), name, info->io); js_as_as_init_corr(port->corr); @@ -354,7 +334,7 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j for (i = 0; i < numdev; i++) printk(KERN_INFO "js%d: %s on %s\n", js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_as_open, js_as_close), + js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), name); js_an_decode(&info->an, port->axes + 1, port->buttons + 1); diff --git a/drivers/char/joystick/joy-console.c b/drivers/char/joystick/joy-console.c index 58392f839..e56da540a 100644 --- a/drivers/char/joystick/joy-console.c +++ b/drivers/char/joystick/joy-console.c @@ -501,6 +501,7 @@ static int js_console_read(void *xinfo, int **axes, int **buttons) /* * open callback: claim parport. + * FIXME: if parport_claim() will sleep we can get into mess. */ int js_console_open(struct js_dev *dev) @@ -754,7 +755,7 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port for (i = 0; i < info.pads; i++) { printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close), + js_register_device(port, i, axes[i], buttons[i], name[i], NULL, js_console_open, js_console_close), name[i], info.port->port->name); js_console_init_corr(axes[i], type[i], port->corr[i]); diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c index 8faec5f82..b5ae4c019 100644 --- a/drivers/char/joystick/joy-creative.c +++ b/drivers/char/joystick/joy-creative.c @@ -151,26 +151,6 @@ static int js_cr_read(void *xinfo, int **axes, int **buttons) } /* - * js_cr_open() is a callback from the file open routine. - */ - -static int js_cr_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_cr_close() is a callback from the file release routine. - */ - -static int js_cr_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_cr_init_corr() initializes correction values of * Blaster gamepads. */ @@ -243,7 +223,7 @@ static struct js_port __init *js_cr_probe(int io, struct js_port *port) if (info.mode[i]) { printk(KERN_INFO "js%d: %s at %#x\n", js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]], - names[info.mode[i]], js_cr_open, js_cr_close), + names[info.mode[i]], THIS_MODULE, NULL, NULL), names[info.mode[i]], io); js_cr_init_corr(info.mode[i], port->corr[i]); } diff --git a/drivers/char/joystick/joy-db9.c b/drivers/char/joystick/joy-db9.c index d5b6565ee..41169b12c 100644 --- a/drivers/char/joystick/joy-db9.c +++ b/drivers/char/joystick/joy-db9.c @@ -244,6 +244,7 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons) /* * open callback: claim parport. + * FIXME: race possible. */ int js_db9_open(struct js_dev *dev) @@ -364,7 +365,7 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port) for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) { printk(KERN_INFO "js%d: %s on %s\n", - js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close), + js_register_device(port, i, 2, buttons[info.mode], name[info.mode], NULL, js_db9_open, js_db9_close), name[info.mode], info.port->port->name); js_db9_init_corr(port->corr[i]); diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c index 3863d161f..84a6def16 100644 --- a/drivers/char/joystick/joy-gravis.c +++ b/drivers/char/joystick/joy-gravis.c @@ -231,26 +231,6 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons) } /* - * js_gr_open() is a callback from the file open routine. - */ - -static int js_gr_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_gr_close() is a callback from the file release routine. - */ - -static int js_gr_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_gr_init_corr() initializes correction values of * GrIP joysticks. */ @@ -359,7 +339,7 @@ static struct js_port __init *js_gr_probe(int io, struct js_port *port) if (info.mode[i]) { printk(KERN_INFO "js%d: %s at %#x\n", js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]], - names[info.mode[i]], js_gr_open, js_gr_close), + names[info.mode[i]], THIS_MODULE, NULL, NULL), names[info.mode[i]], io); js_gr_init_corr(info.mode[i], port->corr[i]); } diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c index 038d33a3c..26c18856a 100644 --- a/drivers/char/joystick/joy-lightning.c +++ b/drivers/char/joystick/joy-lightning.c @@ -208,26 +208,6 @@ static void js_l4_calibrate(struct js_l4_info *info) js_l4_setcal(info->port, cal); } - -/* - * js_l4_open() is a callback from the file open routine. - */ - -static int js_l4_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_l4_close() is a callback from the file release routine. - */ - -static int js_l4_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} /* * js_l4_probe() probes for joysticks on the L4 cards. @@ -262,7 +242,7 @@ static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int for (i = 0; i < numdev; i++) printk(KERN_INFO "js%d: %s on L4 port %d\n", js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_l4_open, js_l4_close), + js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), info->port); js_l4_calibrate(info); diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c index daea89c8b..6044cbfb0 100644 --- a/drivers/char/joystick/joy-logitech.c +++ b/drivers/char/joystick/joy-logitech.c @@ -276,26 +276,6 @@ static int js_lt_read(void *xinfo, int **axes, int **buttons) } /* - * js_lt_open() is a callback from the file open routine. - */ - -static int js_lt_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_lt_close() is a callback from the file release routine. - */ - -static int js_lt_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_lt_init_digital() sends a trigger & delay sequence * to reset and initialize a Logitech joystick into digital mode. */ @@ -482,7 +462,7 @@ static struct js_port __init *js_lt_probe(int io, struct js_port *port) printk(KERN_INFO "js%d: %s [%s] at %#x\n", js_register_device(port, i, info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1), - info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io); + info->buttons[i], name, THIS_MODULE, NULL, NULL), name, info->name[i], io); } mdelay(JS_LT_INIT_DELAY); diff --git a/drivers/char/joystick/joy-magellan.c b/drivers/char/joystick/joy-magellan.c index 3a54d157e..cb14646e8 100644 --- a/drivers/char/joystick/joy-magellan.c +++ b/drivers/char/joystick/joy-magellan.c @@ -232,7 +232,6 @@ static int js_mag_open(struct js_dev *jd) { struct js_mag_info *info = jd->port->info; info->used++; - MOD_INC_USE_COUNT; return 0; } @@ -247,7 +246,6 @@ static int js_mag_close(struct js_dev *jd) js_unregister_device(jd->port->devs[0]); js_mag_port = js_unregister_port(jd->port); } - MOD_DEC_USE_COUNT; return 0; } @@ -298,7 +296,7 @@ static int js_mag_ldisc_open(struct tty_struct *tty) } printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n", - js_register_device(js_mag_port, 0, 6, 9, "Magellan", js_mag_open, js_mag_close), + js_register_device(js_mag_port, 0, 6, 9, "Magellan", THIS_MODULE, js_mag_open, js_mag_close), info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); diff --git a/drivers/char/joystick/joy-pci.c b/drivers/char/joystick/joy-pci.c index ae49fd8e1..fbf9125e5 100644 --- a/drivers/char/joystick/joy-pci.c +++ b/drivers/char/joystick/joy-pci.c @@ -150,26 +150,6 @@ static int js_pci_read(void *xinfo, int **axes, int **buttons) return 0; } - -/* - * js_pci_open() is a callback from the file open routine. - */ - -static int js_pci_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_pci_close() is a callback from the file release routine. - */ - -static int js_pci_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number, struct pci_dev *pci_p, struct js_pci_data *data) @@ -212,7 +192,7 @@ static struct js_port * __init js_pci_probe(struct js_port *port, int type, int for (i = 0; i < numdev; i++) printk(KERN_WARNING "js%d: %s on %s #%d\n", js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an), - js_an_name(i, &info->an), js_pci_open, js_pci_close), js_an_name(i, &info->an), data->name, number); + js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), data->name, number); js_pci_read(info, port->axes, port->buttons); js_an_init_corr(&info->an, port->axes, port->corr, 32); @@ -243,7 +223,8 @@ int __init js_pci_init(void) for (i = 0; js_pci_data[i].vendor; i++) for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++) - js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i); + if (pci_enable_device(pci_p) == 0) + js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i); if (!js_pci_port) { #ifdef MODULE diff --git a/drivers/char/joystick/joy-sidewinder.c b/drivers/char/joystick/joy-sidewinder.c index 37d276ba1..da11598f4 100644 --- a/drivers/char/joystick/joy-sidewinder.c +++ b/drivers/char/joystick/joy-sidewinder.c @@ -476,26 +476,6 @@ static int js_sw_read(void *xinfo, int **axes, int **buttons) } /* - * js_sw_open() is a callback from the file open routine. - */ - -static int js_sw_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_sw_close() is a callback from the file release routine. - */ - -static int js_sw_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_sw_init_corr() initializes the correction values for * SideWinders. */ @@ -810,7 +790,7 @@ static struct js_port __init *js_sw_probe(int io, struct js_port *port) for (i = 0; i < info.number; i++) printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n", js_register_device(port, i, axes[info.type], buttons[info.type], - names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io, + names[info.type], THIS_MODULE, NULL, NULL), names[info.type], comment, io, 1000000 / speed, m, j, k); js_sw_init_corr(axes[info.type], info.type, info.number, port->corr); diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c index 874eb5268..3ace13642 100644 --- a/drivers/char/joystick/joy-spaceball.c +++ b/drivers/char/joystick/joy-spaceball.c @@ -152,7 +152,6 @@ static int js_sball_open(struct js_dev *jd) { struct js_sball_info *info = jd->port->info; info->used++; - MOD_INC_USE_COUNT; return 0; } @@ -167,7 +166,6 @@ static int js_sball_close(struct js_dev *jd) js_unregister_device(jd->port->devs[0]); js_sball_port = js_unregister_port(jd->port); } - MOD_DEC_USE_COUNT; return 0; } @@ -219,7 +217,7 @@ static int js_sball_ldisc_open(struct tty_struct *tty) info->port = js_sball_port; tty->disc_data = info; - info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", js_sball_open, js_sball_close); + info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", THIS_MODULE, js_sball_open, js_sball_close); js_sball_init_corr(js_sball_port->corr); diff --git a/drivers/char/joystick/joy-spaceorb.c b/drivers/char/joystick/joy-spaceorb.c index a154bcdd5..0fb4f4c71 100644 --- a/drivers/char/joystick/joy-spaceorb.c +++ b/drivers/char/joystick/joy-spaceorb.c @@ -152,7 +152,6 @@ static int js_orb_open(struct js_dev *jd) { struct js_orb_info *info = jd->port->info; info->used++; - MOD_INC_USE_COUNT; return 0; } @@ -167,7 +166,6 @@ static int js_orb_close(struct js_dev *jd) js_unregister_device(jd->port->devs[0]); js_orb_port = js_unregister_port(jd->port); } - MOD_DEC_USE_COUNT; return 0; } @@ -211,7 +209,7 @@ static int js_orb_ldisc_open(struct tty_struct *tty) info->port = js_orb_port; tty->disc_data = info; - info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", js_orb_open, js_orb_close); + info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", THIS_MODULE, js_orb_open, js_orb_close); js_orb_init_corr(js_orb_port->corr); diff --git a/drivers/char/joystick/joy-thrustmaster.c b/drivers/char/joystick/joy-thrustmaster.c index 4cd3de23f..56e043a59 100644 --- a/drivers/char/joystick/joy-thrustmaster.c +++ b/drivers/char/joystick/joy-thrustmaster.c @@ -163,26 +163,6 @@ static int js_tm_read(void *xinfo, int **axes, int **buttons) } /* - * js_tm_open() is a callback from the file open routine. - */ - -static int js_tm_open(struct js_dev *jd) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * js_tm_close() is a callback from the file release routine. - */ - -static int js_tm_close(struct js_dev *jd) -{ - MOD_DEC_USE_COUNT; - return 0; -} - -/* * js_tm_init_corr() initializes the correction values for * ThrustMaster joysticks. */ @@ -261,7 +241,7 @@ static struct js_port __init *js_tm_probe(int io, struct js_port *port) request_region(io, 1, "joystick (thrustmaster)"); port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read); printk(KERN_INFO "js%d: %s revision %d at %#x\n", - js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io); + js_register_device(port, 0, a, b, name, THIS_MODULE, NULL, NULL), name, data[JS_TM_BYTE_REV], io); js_tm_init_corr(a, info.mode, port->axes, port->corr); return port; diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c index 0211ea6f9..c138a99d0 100644 --- a/drivers/char/joystick/joy-turbografx.c +++ b/drivers/char/joystick/joy-turbografx.c @@ -101,6 +101,7 @@ static int js_tg_read(void *xinfo, int **axes, int **buttons) /* * open callback: claim parport. + * FIXME: race possible here. */ int js_tg_open(struct js_dev *dev) @@ -205,7 +206,7 @@ static struct js_port __init *js_tg_probe(int *config, struct js_port *port) for (i = 0; i < 7; i++) if (config[i+1] > 0 && config[i+1] < 6) { printk(KERN_INFO "js%d: Multisystem joystick on %s\n", - js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close), + js_register_device(port, i, 2, config[i+1], "Multisystem joystick", NULL, js_tg_open, js_tg_close), info->port->port->name); info->sticks |= (1 << i); } diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c index 8737d1cc9..232699859 100644 --- a/drivers/char/joystick/joy-warrior.c +++ b/drivers/char/joystick/joy-warrior.c @@ -123,7 +123,6 @@ static int js_war_open(struct js_dev *jd) { struct js_war_info *info = jd->port->info; info->used++; - MOD_INC_USE_COUNT; return 0; } @@ -138,7 +137,6 @@ static int js_war_close(struct js_dev *jd) js_unregister_device(jd->port->devs[0]); js_war_port = js_unregister_port(jd->port); } - MOD_DEC_USE_COUNT; return 0; } @@ -200,7 +198,7 @@ static int js_war_ldisc_open(struct tty_struct *tty) tty->disc_data = info; printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n", - js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", js_war_open, js_war_close), + js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", THIS_MODULE, js_war_open, js_war_close), tty->driver.name, MINOR(tty->device) - tty->driver.minor_start); js_war_init_corr(js_war_port->corr); diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c index 1b156538e..c9bd56ce3 100644 --- a/drivers/char/joystick/joystick.c +++ b/drivers/char/joystick/joystick.c @@ -511,15 +511,21 @@ static int js_open(struct inode *inode, struct file *file) if (!jd) return -ENODEV; - if ((result = jd->open(jd))) + if (jd->owner) + __MOD_INC_USE_COUNT(jd->owner); + if (jd->open && (result = jd->open(jd))) { + if (jd->owner) + __MOD_DEC_USE_COUNT(jd->owner); return result; - - MOD_INC_USE_COUNT; + } new = kmalloc(sizeof(struct js_list), GFP_KERNEL); if (!new) { - jd->close(jd); - MOD_DEC_USE_COUNT; + if (jd->close) + jd->close(jd); + if (jd->owner) + __MOD_DEC_USE_COUNT(jd->owner); + return -ENOMEM; } @@ -577,9 +583,10 @@ static int js_release(struct inode *inode, struct file *file) if (!--js_use_count) del_timer(&js_timer); - jd->close(jd); - - MOD_DEC_USE_COUNT; + if (jd->close) + jd->close(jd); + if (jd->owner) + __MOD_DEC_USE_COUNT(jd->owner); return 0; } @@ -659,8 +666,9 @@ extern struct file_operations js_fops; static devfs_handle_t devfs_handle = NULL; -int js_register_device(struct js_port *port, int number, int axes, int buttons, char *name, - js_ops_func open, js_ops_func close) +int js_register_device(struct js_port *port, int number, int axes, + int buttons, char *name, struct module *owner, + js_ops_func open, js_ops_func close) { struct js_dev **ptrd = &js_dev; struct js_dev *curd; @@ -681,6 +689,7 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons, curd->port = port; curd->open = open; curd->close = close; + curd->owner = owner; init_waitqueue_head(&curd->wait); @@ -743,6 +752,7 @@ void js_unregister_device(struct js_dev *dev) static struct file_operations js_fops = { + owner: THIS_MODULE, read: js_read, poll: js_poll, ioctl: js_ioctl, diff --git a/drivers/char/logibusmouse.c b/drivers/char/logibusmouse.c index f9eae25eb..5e9ef9360 100644 --- a/drivers/char/logibusmouse.c +++ b/drivers/char/logibusmouse.c @@ -107,7 +107,6 @@ static int close_mouse(struct inode * inode, struct file * file) { MSE_INT_OFF(); free_irq(mouse_irq, NULL); - MOD_DEC_USE_COUNT; return 0; } @@ -119,13 +118,12 @@ static int open_mouse(struct inode * inode, struct file * file) { if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL)) return -EBUSY; - MOD_INC_USE_COUNT; MSE_INT_ON(); return 0; } static struct busmouse busmouse = { - LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7 + LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7 }; static int __init logi_busmouse_init(void) diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 90f034396..c2df7ea18 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -371,8 +371,6 @@ static int lp_open(struct inode * inode, struct file * file) if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor))) return -EBUSY; - MOD_INC_USE_COUNT; - /* If ABORTOPEN is set and the printer is offline or out of paper, we may still want to open it to perform ioctl()s. Therefore we have commandeered O_NONBLOCK, even though it is being used in @@ -385,24 +383,20 @@ static int lp_open(struct inode * inode, struct file * file) parport_release (lp_table[minor].dev); if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lp%d off-line\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -EIO; } } lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } @@ -415,7 +409,6 @@ static int lp_release(struct inode * inode, struct file * file) kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; - MOD_DEC_USE_COUNT; LP_F(minor) &= ~LP_BUSY; return 0; } @@ -526,6 +519,7 @@ static int lp_ioctl(struct inode *inode, struct file *file, } static struct file_operations lp_fops = { + owner: THIS_MODULE, write: lp_write, ioctl: lp_ioctl, open: lp_open, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 86ee11a5e..df1e97494 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -112,8 +112,7 @@ static int misc_open(struct inode * inode, struct file * file) int minor = MINOR(inode->i_rdev); struct miscdevice *c; int err = -ENODEV; - - file->f_op = NULL; + struct file_operations *old_fops; down(&misc_sem); @@ -134,14 +133,22 @@ static int misc_open(struct inode * inode, struct file * file) goto fail; } - if ((file->f_op = c->fops) && file->f_op->open) + old_fops = file->f_op; + file->f_op = fops_get(c->fops); + if (file->f_op && file->f_op->open) err=file->f_op->open(inode,file); + if (err) { + fops_put(file->f_op); + file->f_op = fops_get(old_fops); + } + fops_put(old_fops); fail: up(&misc_sem); return err; } static struct file_operations misc_fops = { + owner: THIS_MODULE, open: misc_open, }; diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c index 5894353e3..6352d6f73 100644 --- a/drivers/char/mixcomwd.c +++ b/drivers/char/mixcomwd.c @@ -94,8 +94,6 @@ static int mixcomwd_open(struct inode *inode, struct file *file) mixcomwd_timer_alive=0; } #endif - MOD_INC_USE_COUNT; - return 0; } @@ -114,7 +112,6 @@ static int mixcomwd_release(struct inode *inode, struct file *file) mixcomwd_timer_alive=1; add_timer(&mixcomwd_timer); #endif - MOD_DEC_USE_COUNT; clear_bit(0,&mixcomwd_opened); return 0; @@ -171,6 +168,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, static struct file_operations mixcomwd_fops= { + owner: THIS_MODULE, write: mixcomwd_write, ioctl: mixcomwd_ioctl, open: mixcomwd_open, diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c index c3148a9cc..e47817fae 100644 --- a/drivers/char/msbusmouse.c +++ b/drivers/char/msbusmouse.c @@ -108,7 +108,6 @@ static int release_mouse(struct inode * inode, struct file * file) { MS_MSE_INT_OFF(); free_irq(mouse_irq, NULL); - MOD_DEC_USE_COUNT; return 0; } @@ -118,13 +117,12 @@ static int open_mouse(struct inode * inode, struct file * file) return -EBUSY; outb(MS_MSE_START, MS_MSE_CONTROL_PORT); - MOD_INC_USE_COUNT; MS_MSE_INT_ON(); return 0; } static struct busmouse msbusmouse = { - MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0 + MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0 }; static int __init ms_bus_mouse_init(void) diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index f4252a071..d6fa8314b 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -1,7 +1,7 @@ /* * programming the msp34* sound processor family * - * (c) 1997,1998 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * (c) 1997-2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> * * what works and what doesn't: * @@ -46,6 +46,7 @@ #include <linux/i2c.h> #include <linux/videodev.h> #include <asm/semaphore.h> +#include <linux/init.h> #ifdef CONFIG_SMP #include <asm/pgtable.h> @@ -57,16 +58,14 @@ #include "audiochip.h" -#define WAIT_QUEUE wait_queue_head_t - /* sound mixer stuff */ -#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) +#if 0 /* defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) */ # define REGISTER_MIXER 1 #endif /* Addresses to scan */ static unsigned short normal_i2c[] = {I2C_CLIENT_END}; -static unsigned short normal_i2c_range[] = {0x40,0x44,I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END}; static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; @@ -102,7 +101,7 @@ struct msp3400c { /* thread */ struct task_struct *thread; - WAIT_QUEUE wq; + wait_queue_head_t wq; struct semaphore *notify; int active,restart,rmmod; @@ -680,10 +679,10 @@ static int msp3400c_thread(void *data) #endif exit_mm(current); + exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); - current->fs->umask = 0; strcpy(current->comm,"msp3400"); msp->thread = current; @@ -932,10 +931,10 @@ static int msp3410d_thread(void *data) #endif exit_mm(current); + exit_fs(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); - current->fs->umask = 0; strcpy(current->comm,"msp3410 [auto]"); msp->thread = current; @@ -1256,7 +1255,6 @@ msp3400c_mixer_open(struct inode *inode, struct file *file) if (client->adapter->inc_use) client->adapter->inc_use(client->adapter); - MOD_INC_USE_COUNT; return 0; } @@ -1267,7 +1265,6 @@ msp3400c_mixer_release(struct inode *inode, struct file *file) if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); - MOD_DEC_USE_COUNT; return 0; } @@ -1278,6 +1275,7 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin) } static struct file_operations msp3400c_mixer_fops = { + owner: THIS_MODULE, llseek: msp3400c_mixer_llseek, ioctl: msp3400c_mixer_ioctl, open: msp3400c_mixer_open, @@ -1370,7 +1368,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr, if (simple == -1) { /* default mode */ - msp->simple = 0; + msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; } else { /* use insmod option */ msp->simple = simple; @@ -1632,22 +1630,19 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) /* ----------------------------------------------------------------------- */ -#ifdef MODULE -int init_module(void) -#else -int msp3400c_init(void) -#endif +int msp3400_init_module(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +void msp3400_cleanup_module(void) { i2c_del_driver(&driver); } -#endif + +module_init(msp3400_init_module); +module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 8de8336d1..fbbec0fb1 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -618,6 +618,8 @@ int mxser_init(void) mxser_pcibrds[b].device_id, pdev); if (!pdev) break; + if (pci_enable_device(pdev)) + continue; b++; hwconf.pdev = pdev; printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n", diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 1d27b680d..7a0df755e 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -663,7 +663,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, #if LINUX_VERSION_CODE < VERSION(2,3,0) kill_fasync (n_hdlc->tty->fasync, SIGIO); #else - kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); + kill_fasync(&n_hdlc->tty->fasync, SIGIO, POLL_IN); #endif } /* end of n_hdlc_tty_receive() */ diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 81d562747..f488d9124 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -630,8 +630,7 @@ send_signal: put_tty_queue(c, tty); tty->canon_head = tty->read_head; tty->canon_data++; - if (tty->fasync) - kill_fasync(tty->fasync, SIGIO, POLL_IN); + kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); return; @@ -735,8 +734,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, } if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { - if (tty->fasync) - kill_fasync(tty->fasync, SIGIO, POLL_IN); + kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); } diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index c5be675c7..42063cefa 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -332,7 +332,6 @@ static int nvram_open( struct inode *inode, struct file *file ) if (file->f_mode & 2) nvram_open_mode |= NVRAM_WRITE; nvram_open_cnt++; - MOD_INC_USE_COUNT; return( 0 ); } @@ -344,7 +343,6 @@ static int nvram_release( struct inode *inode, struct file *file ) if (file->f_mode & 2) nvram_open_mode &= ~NVRAM_WRITE; - MOD_DEC_USE_COUNT; return( 0 ); } @@ -393,6 +391,7 @@ static int nvram_read_proc( char *buffer, char **start, off_t offset, #endif /* CONFIG_PROC_FS */ static struct file_operations nvram_fops = { + owner: THIS_MODULE, llseek: nvram_llseek, read: nvram_read, write: nvram_write, diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 34d996582..8cf8a15a7 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -172,34 +172,6 @@ static int button_read (struct file *filp, char *buffer, ? -EFAULT : bcount; } -/* - * This function is called when a user space process attempts to open the - * device. If the driver is compiled into the kernel it does nothing but - * succeed, but if it is compiled in as a module it also increments the - * module usage count to prevent the module from being removed whilst a - * process has the device open. - */ - -static int button_open (struct inode *inode, struct file *filp) -{ - MOD_INC_USE_COUNT; - return 0; -} - -/* - * This function is called when a user space process attempts to close the - * device. If the driver is compiled into the kernel it does nothing at all, - * but if it is compiled in as a module it also decrements the module usage - * count so that it will be possible to unload the module again once all the - * user processes have closed the device. - */ - -static int button_release (struct inode *inode, struct file *filp) -{ - MOD_DEC_USE_COUNT; - return 0; -} - /* * This structure is the file operations structure, which specifies what * callbacks functions the kernel should call when a user mode process @@ -207,9 +179,8 @@ static int button_release (struct inode *inode, struct file *filp) */ static struct file_operations button_fops = { + owner: THIS_MODULE, read: button_read, - open: button_open, - release: button_release, }; /* diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index 579e970d4..5be07b769 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -39,7 +39,6 @@ MSTATIC int get_flash_id(void); MSTATIC int erase_block(int nBlock); MSTATIC int write_block(unsigned long p, const char *buf, int count); static int open_flash(struct inode *inodep, struct file *filep); -static int release_flash(struct inode *inodep, struct file *filep); static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg); static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos); static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos); @@ -60,12 +59,12 @@ extern spinlock_t gpio_lock; static struct file_operations flash_fops = { + owner: THIS_MODULE, llseek: flash_llseek, read: flash_read, write: flash_write, ioctl: flash_ioctl, open: open_flash, - release: release_flash, }; static struct miscdevice flash_miscdev = @@ -128,19 +127,10 @@ static int open_flash(struct inode *inodep, struct file *filep) printk("Flash: incorrect ID 0x%04X.\n", id); return -ENXIO; } - MOD_INC_USE_COUNT; return 0; } - -static int release_flash(struct inode *inodep, struct file *filep) -{ - MOD_DEC_USE_COUNT; - return 0; -} - - static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg) { // printk("Flash_ioctl: cmd = 0x%X.\n",cmd); diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c index e0b620596..dfef66e39 100644 --- a/drivers/char/pc110pad.c +++ b/drivers/char/pc110pad.c @@ -83,8 +83,7 @@ static struct semaphore reader_lock; static void wake_readers(void) { wake_up_interruptible(&queue); - if(asyncptr) - kill_fasync(asyncptr, SIGIO, POLL_IN); + kill_fasync(&asyncptr, SIGIO, POLL_IN); } @@ -588,7 +587,6 @@ static int close_pad(struct inode * inode, struct file * file) if (--active) return 0; outb(0x30, current_params.io+2); /* switch off digitiser */ - MOD_DEC_USE_COUNT; return 0; } @@ -610,7 +608,6 @@ static int open_pad(struct inode * inode, struct file * file) if (active++) return 0; - MOD_INC_USE_COUNT; save_flags(flags); cli(); @@ -772,6 +769,7 @@ static int pad_ioctl(struct inode *inode, struct file * file, static struct file_operations pad_fops = { + owner: THIS_MODULE, read: read_pad, write: write_pad, poll: pad_poll, diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index c8a1da0d3..86d012bed 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -415,8 +415,7 @@ static inline void handle_mouse_event(unsigned char scancode) head = (head + 1) & (AUX_BUF_SIZE-1); if (head != queue->tail) { queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO, POLL_IN); + kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } } @@ -452,7 +451,9 @@ static unsigned char handle_kbd_event(void) scancode = kbd_read_input(); -#if 0 + /* Error bytes must be ignored to make the + Synaptics touchpads compaq use work */ +#if 1 /* Ignore error bytes */ if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) #endif diff --git a/drivers/char/pcmcia/serial_cb.c b/drivers/char/pcmcia/serial_cb.c index 457b2f647..86bb70f57 100644 --- a/drivers/char/pcmcia/serial_cb.c +++ b/drivers/char/pcmcia/serial_cb.c @@ -92,6 +92,7 @@ static dev_node_t *serial_attach(dev_locator_t *loc) if (loc->bus != LOC_PCI) goto err_out; pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn); if (!pdev) goto err_out; + if (pci_enable_device(pdev)) goto err_out; printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn); io = pci_resource_start (pdev, 0); diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c index 2e2d391fa..b85a168de 100644 --- a/drivers/char/pcwd.c +++ b/drivers/char/pcwd.c @@ -414,7 +414,6 @@ static int pcwd_open(struct inode *ino, struct file *filep) is_open = 1; return(0); case TEMP_MINOR: - MOD_INC_USE_COUNT; return(0); default: return (-ENODEV); @@ -450,7 +449,6 @@ static ssize_t pcwd_read(struct file *file, char *buf, size_t count, static int pcwd_close(struct inode *ino, struct file *filep) { - MOD_DEC_USE_COUNT; if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) { is_open = 0; @@ -543,6 +541,7 @@ static void debug_off(void) } static struct file_operations pcwd_fops = { + owner: THIS_MODULE, read: pcwd_read, write: pcwd_write, ioctl: pcwd_ioctl, diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index f4c84ac95..819ed0b1a 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -83,6 +83,63 @@ struct pp_struct { /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) +struct pp_port_list_struct { + struct parport *port; + struct pp_port_list_struct *next; +}; +static struct pp_port_list_struct *pp_port_list; +static DECLARE_MUTEX(pp_port_list_lock); + +/* pp_attach and pp_detach are for keeping a list of currently + * available ports, held under a mutex. We do this rather than + * using parport_enumerate because it stops a load of races. + */ + +static void pp_attach (struct parport *port) +{ + struct pp_port_list_struct *add; + + add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL); + if (!add) { + printk (KERN_WARNING CHRDEV ": memory squeeze\n"); + return; + } + + add->next = pp_port_list; + down (&pp_port_list_lock); + pp_port_list = add; + up (&pp_port_list_lock); +} + +static void pp_detach (struct parport *port) +{ + struct pp_port_list_struct *del; + + down (&pp_port_list_lock); + del = pp_port_list; + if (del->port == port) + pp_port_list = del->next; + else { + struct pp_port_list_struct *prev; + do { + prev = del; + del = del->next; + } while (del && del->port != port); + if (del) + prev->next = del->next; + } + up (&pp_port_list_lock); + + if (del) + kfree (del); +} + +static struct parport_driver ppdev_driver = { + name: CHRDEV, + attach: pp_attach, + detach: pp_detach +}; + static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; @@ -216,7 +273,7 @@ static void pp_irq (int irq, void * private, struct pt_regs * unused) static int register_device (int minor, struct pp_struct *pp) { - struct parport * port; + struct pp_port_list_struct *ports; struct pardevice * pdev = NULL; char *name; int fl; @@ -226,20 +283,24 @@ static int register_device (int minor, struct pp_struct *pp) return -ENOMEM; sprintf (name, CHRDEV "%x", minor); - port = parport_enumerate (); /* FIXME: use attach/detach */ - while (port && port->number != minor) - port = port->next; + down (&pp_port_list_lock); + ports = pp_port_list; + while (ports && ports->port->number != minor) + ports = ports->next; + if (ports->port) { + fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + pdev = parport_register_device (ports->port, name, NULL, + NULL, pp_irq, fl, pp); + } + up (&pp_port_list_lock); - if (!port) { + if (!ports->port) { printk (KERN_WARNING "%s: no associated port!\n", name); kfree (name); return -ENXIO; } - fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; - pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl, - pp); if (!pdev) { printk (KERN_WARNING "%s: failed to register device!\n", name); @@ -507,13 +568,9 @@ static int pp_open (struct inode * inode, struct file * file) if (minor >= PARPORT_MAX) return -ENXIO; - MOD_INC_USE_COUNT; - pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL); - if (!pp) { - MOD_DEC_USE_COUNT; + if (!pp) return -ENOMEM; - } pp->state.mode = IEEE1284_MODE_COMPAT; pp->state.phase = init_phase (pp->state.mode); @@ -565,7 +622,6 @@ static int pp_release (struct inode * inode, struct file * file) kfree (pp); - MOD_DEC_USE_COUNT; return 0; } @@ -583,6 +639,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait) } static struct file_operations pp_fops = { + owner: THIS_MODULE, llseek: pp_lseek, read: pp_read, write: pp_write, @@ -596,6 +653,10 @@ static devfs_handle_t devfs_handle = NULL; static int __init ppdev_init (void) { + if (parport_register_driver (&ppdev_driver)) { + printk (KERN_WARNING CHRDEV ": unable to register driver\n"); + return -EIO; + } if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", PP_MAJOR); @@ -616,6 +677,7 @@ static void __exit ppdev_cleanup (void) /* Clean up all parport stuff */ devfs_unregister (devfs_handle); devfs_unregister_chrdev (PP_MAJOR, CHRDEV); + parport_unregister_driver (&ppdev_driver); } module_init(ppdev_init); diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c index 096cf6afb..6fd5a3d65 100644 --- a/drivers/char/qpmouse.c +++ b/drivers/char/qpmouse.c @@ -133,8 +133,7 @@ static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs) head &= QP_BUF_SIZE-1; } queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO, POLL_IN); + kill_fasync(&queue->fasync, SIGIO, POLL_IN); wake_up_interruptible(&queue->proc_list); } @@ -151,7 +150,6 @@ static int release_qp(struct inode * inode, struct file * file) if (!poll_qp_status()) printk("Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ, NULL); - MOD_DEC_USE_COUNT; } return 0; } @@ -196,7 +194,6 @@ static int open_qp(struct inode * inode, struct file * file) } outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ - MOD_INC_USE_COUNT; return 0; } @@ -290,6 +287,7 @@ repeat: } struct file_operations qp_fops = { + owner: THIS_MODULE, read: read_qp, write: write_qp, poll: poll_qp, diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c index ee986b335..d716c54bd 100644 --- a/drivers/char/radio-aimslab.c +++ b/drivers/char/radio-aimslab.c @@ -355,7 +355,7 @@ static int __init rtrack_init(void) return -EINVAL; request_region(io, 2, "rtrack"); - printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n"); + printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n"); /* Set up the I/O locking */ diff --git a/drivers/char/random.c b/drivers/char/random.c index b983ae825..9f0e1374c 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -139,7 +139,7 @@ * add_interrupt_randomness() uses the inter-interrupt timing as random * inputs to the entropy pool. Note that not all interrupts are good * sources of randomness! For example, the timer interrupts is not a - * good choice, because the periodicity of the interrupts is to + * good choice, because the periodicity of the interrupts is too * regular, and hence predictable to an attacker. Disk interrupts are * a better measure, since the timing of the disk interrupts are more * unpredictable. diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 625f7022b..01865a09d 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -201,8 +201,6 @@ static void rio_close (void *ptr); static int rio_chars_in_buffer (void * ptr); static int rio_fw_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -static int rio_fw_open(struct inode *inode, struct file *filp); -static INT rio_fw_release(struct inode *inode, struct file *filp); static int rio_init_drivers(void); @@ -277,9 +275,8 @@ static struct real_driver rio_real_driver = { */ static struct file_operations rio_fw_fops = { + owner: THIS_MODULE, ioctl: rio_fw_ioctl, - open: rio_fw_open, - release: rio_fw_release, }; struct miscdevice rio_fw_device = { @@ -634,32 +631,6 @@ static void rio_shutdown_port (void * ptr) func_exit(); } - - -/* ********************************************************************** * - * Here are the routines that actually * - * interface with the rest of the system * - * ********************************************************************** */ - - -static int rio_fw_open(struct inode *inode, struct file *filp) -{ - func_enter (); - rio_inc_mod_count (); - func_exit (); - return 0; -} - - -static INT rio_fw_release(struct inode *inode, struct file *filp) -{ - func_enter (); - rio_dec_mod_count (); - func_exit (); - return NO_ERROR; -} - - /* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug @@ -1149,6 +1120,7 @@ int rio_init(void) while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, @@ -1234,6 +1206,7 @@ int rio_init(void) while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { + if (pci_enable_device(pdev)) continue; #else for (i=0;i< RIO_NBOARDS;i++) { if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX, diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 29d4227ff..943ea6a61 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1957,7 +1957,10 @@ int __init register_PCI(int i, unsigned int bus, unsigned int device_fn) if (!dev) return 0; - rcktpt_io_addr[i] = dev->resource[0].start; + if (pci_enable_device(dev)) + return 0; + + rcktpt_io_addr[i] = pci_resource_start (dev, 0); switch(dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index bfe700219..9809952ea 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -179,8 +179,7 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* Now do the rest of the actions */ wake_up_interruptible(&rtc_wait); - if (rtc_async_queue) - kill_fasync (rtc_async_queue, SIGIO, POLL_IN); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); } #endif @@ -513,8 +512,6 @@ static int rtc_open(struct inode *inode, struct file *file) if(rtc_status & RTC_IS_OPEN) return -EBUSY; - MOD_INC_USE_COUNT; - rtc_status |= RTC_IS_OPEN; spin_lock_irq (&rtc_lock); @@ -558,7 +555,6 @@ static int rtc_release(struct inode *inode, struct file *file) } #endif - MOD_DEC_USE_COUNT; spin_lock_irq (&rtc_lock); rtc_irq_data = 0; @@ -590,6 +586,7 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) */ static struct file_operations rtc_fops = { + owner: THIS_MODULE, llseek: rtc_llseek, read: rtc_read, #if !defined(__alpha__) && !defined(CONFIG_DECSTATION) @@ -783,8 +780,7 @@ static void rtc_dropped_irq(unsigned long data) /* Now we have new data */ wake_up_interruptible(&rtc_wait); - if (rtc_async_queue) - kill_fasync (rtc_async_queue, SIGIO, POLL_IN); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); } #endif diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c new file mode 100644 index 000000000..a0bea62c0 --- /dev/null +++ b/drivers/char/sbc60xxwdt.c @@ -0,0 +1,338 @@ +/* + * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x + * + * Based on acquirewdt.c by Alan Cox. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for + * any of this software. This material is provided "AS-IS" in + * the hope that it may be useful for others. + * + * (c) Copyright 2000 Jakob Oestergaard <jakob@ostenfeld.dk> + * + * 12/4 - 2000 [Initial revision] + * 25/4 - 2000 Added /dev/watchdog support + * + * + * Theory of operation: + * A Watchdog Timer (WDT) is a hardware circuit that can + * reset the computer system in case of a software fault. + * You probably knew that already. + * + * Usually a userspace daemon will notify the kernel WDT driver + * via the /proc/watchdog special device file that userspace is + * still alive, at regular intervals. When such a notification + * occurs, the driver will usually tell the hardware watchdog + * that everything is in order, and that the watchdog should wait + * for yet another little while to reset the system. + * If userspace fails (RAM error, kernel bug, whatever), the + * notifications cease to occur, and the hardware watchdog will + * reset the system (causing a reboot) after the timeout occurs. + * + * This WDT driver is different from the other Linux WDT + * drivers in several ways: + * *) The driver will ping the watchdog by itself, because this + * particular WDT has a very short timeout (one second) and it + * would be insane to count on any userspace daemon always + * getting scheduled within that time frame. + * *) This driver expects the userspace daemon to send a specific + * character code ('V') to /dev/watchdog before closing the + * /dev/watchdog file. If the userspace daemon closes the file + * without sending this special character, the driver will assume + * that the daemon (and userspace in general) died, and will + * stop pinging the WDT without disabling it first. This will + * cause a reboot. + * + * Why `V' ? Well, `V' is the character in ASCII for the value 86, + * and we all know that 86 is _the_ most random number in the universe. + * Therefore it is the letter that has the slightest chance of occuring + * by chance, when the system becomes corrupted. + * + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/timer.h> +#include <linux/sched.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/malloc.h> +#include <linux/ioport.h> +#include <linux/fcntl.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> + +#define OUR_NAME "sbc60xxwdt" + +/* + * You must set these - The driver cannot probe for the settings + */ + +#define WDT_STOP 0x45 +#define WDT_START 0x443 + +/* + * The 60xx board can use watchdog timeout values from one second + * to several minutes. The default is one second, so if we reset + * the watchdog every ~250ms we should be safe. + */ + +#define WDT_INTERVAL (HZ/4+1) + +/* + * We must not require too good response from the userspace daemon. + * Here we require the userspace daemon to send us a heartbeat + * char to /dev/watchdog every 10 seconds. + * If the daemon pulses us every 5 seconds, we can still afford + * a 5 second scheduling delay on the (high priority) daemon. That + * should be sufficient for a box under any load. + */ + +#define WDT_HEARTBEAT (HZ * 10) + +static void wdt_timer_ping(unsigned long); +static struct timer_list timer; +static unsigned long next_heartbeat = 0; +static int wdt_is_open = 0; +static int wdt_expect_close = 0; + +/* + * Whack the dog + */ + +static void wdt_timer_ping(unsigned long data) +{ + /* If we got a heartbeat pulse within the WDT_US_INTERVAL + * we agree to ping the WDT + */ + if(time_before(jiffies, next_heartbeat)) + { + /* Ping the WDT by reading from WDT_START */ + inb_p(WDT_START); + /* Re-set the timer interval */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + } else { + printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n"); + } +} + +/* + * Utility routines + */ + +static void wdt_startup(void) +{ + next_heartbeat = jiffies + WDT_HEARTBEAT; + + /* Start the timer */ + timer.expires = jiffies + WDT_INTERVAL; + add_timer(&timer); + printk(OUR_NAME ": Watchdog timer is now enabled.\n"); +} + +static void wdt_turnoff(void) +{ + /* Stop the timer */ + del_timer(&timer); + inb_p(WDT_STOP); + printk(OUR_NAME ": Watchdog timer is now disabled...\n"); +} + + +/* + * /dev/watchdog handling + */ + +static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos) +{ + /* We can't seek */ + if(ppos != &file->f_pos) + return -ESPIPE; + + /* See if we got the magic character */ + if(count) + { + size_t ofs; + + /* note: just in case someone wrote the magic character + * five months ago... */ + wdt_expect_close = 0; + + /* now scan */ + for(ofs = 0; ofs != count; ofs++) + if(buf[ofs] == 'V') + wdt_expect_close = 1; + + /* Well, anyhow someone wrote to us, we should return that favour */ + next_heartbeat = jiffies + WDT_HEARTBEAT; + } + return 0; +} + +static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos) +{ + /* No can do */ + return -EINVAL; +} + +static int fop_open(struct inode * inode, struct file * file) +{ + switch(MINOR(inode->i_rdev)) + { + case WATCHDOG_MINOR: + /* Just in case we're already talking to someone... */ + if(wdt_is_open) + return -EBUSY; + /* Good, fire up the show */ + wdt_is_open = 1; + wdt_startup(); + return 0; + + default: + return -ENODEV; + } +} + +static int fop_close(struct inode * inode, struct file * file) +{ + if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) + { + if(wdt_expect_close) + wdt_turnoff(); + else { + del_timer(&timer); + printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n"); + } + } + wdt_is_open = 0; + return 0; +} + +static long long fop_llseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + static struct watchdog_info ident= + { + 0, + 1, + "SB60xx" + }; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0; + case WDIOC_KEEPALIVE: + next_heartbeat = jiffies + WDT_HEARTBEAT; + return 0; + } +} + +static struct file_operations wdt_fops = { + owner: THIS_MODULE, + llseek: fop_llseek, + read: fop_read, + write: fop_write, + open: fop_open, + release: fop_close, + ioctl: fop_ioctl +}; + +static struct miscdevice wdt_miscdev = { + WATCHDOG_MINOR, + "watchdog", + &wdt_fops +}; + +/* + * Notifier for system down + */ + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt_turnoff(); + return NOTIFY_DONE; +} + +/* + * The WDT needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block wdt_notifier= +{ + wdt_notify_sys, + 0, + 0 +}; + +static void __exit sbc60xxwdt_unload(void) +{ + wdt_turnoff(); + + /* Deregister */ + misc_deregister(&wdt_miscdev); + + unregister_reboot_notifier(&wdt_notifier); + release_region(WDT_START,1); + release_region(WDT_STOP,1); +} + +static int __init sbc60xxwdt_init(void) +{ + int rc = -EBUSY; + + if (!request_region(WDT_STOP, 1, "SBC 60XX WDT")) + goto err_out; + if (!request_region(WDT_START, 1, "SBC 60XX WDT")) + goto err_out_region1; + + init_timer(&timer); + timer.function = wdt_timer_ping; + timer.data = 0; + + rc = misc_register(&wdt_miscdev); + if (rc) + goto err_out_region2; + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + goto err_out_miscdev; + + printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n"); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region2: + release_region(WDT_START,1); +err_out_region1: + release_region(WDT_STOP,1); +err_out: + return rc; +} + +module_init(sbc60xxwdt_init); +module_exit(sbc60xxwdt_unload) diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c new file mode 100644 index 000000000..7536c0769 --- /dev/null +++ b/drivers/char/scan_keyb.c @@ -0,0 +1,129 @@ +/* + * $Id: scan_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Generic scan keyboard driver + */ + +#include <linux/config.h> + +#include <linux/spinlock.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/mm.h> +#include <linux/signal.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/delay.h> +#include <linux/random.h> +#include <linux/poll.h> +#include <linux/miscdevice.h> +#include <linux/malloc.h> +#include <linux/kbd_kern.h> + +struct scan_keyboard { + struct scan_keyboard *next; + void (*scan)(unsigned char *buffer); + const unsigned char *table; + unsigned char *s0, *s1; + int length; +}; + +static struct scan_keyboard *keyboards=NULL; +static struct tq_struct task_scan_kbd; + +static void check_kbd(const unsigned char *table, + unsigned char *new, unsigned char *old, int length) +{ + int need_tasklet_schedule=0; + unsigned char xor, bit; + + while(length-->0) { + if((xor=*new^*old)==0) { + table+=8; + } + else { + for(bit=0x80; bit!=0; bit>>=1) { + if(xor&bit) { + handle_scancode(*table, !(*new&bit)); + need_tasklet_schedule=1; + } + table++; + } + } + new++; old++; + } + + if(need_tasklet_schedule) + tasklet_schedule(&keyboard_tasklet); +} + + +static void scan_kbd(void *dummy) +{ + struct scan_keyboard *kbd; + + for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) { + if(jiffies&1) { + kbd->scan(kbd->s0); + check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length); + } + else { + kbd->scan(kbd->s1); + check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length); + } + + } + queue_task(&task_scan_kbd, &tq_timer); +} + + +int register_scan_keyboard(void (*scan)(unsigned char *buffer), + const unsigned char *table, + int length) +{ + struct scan_keyboard *kbd; + + if((kbd=kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL))==NULL) + goto error_out; + + kbd->scan=scan; + kbd->table=table; + kbd->length=length; + + kbd->s0=kbd->s1=NULL; + if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL) + goto error_out; + if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL) + goto error_out; + + kbd->scan(kbd->s0); + kbd->scan(kbd->s1); + + kbd->next=keyboards; + keyboards=kbd; + + return 0; + + error_mem_free: + if(kbd->s0) + kfree(kbd->s0); + if(kbd->s1) + kfree(kbd->s1); + kfree(kbd); + + error_out: + return -ENOMEM; +} + + +void __init scan_kbd_init(void) +{ + + task_scan_kbd.next=NULL; + task_scan_kbd.sync=0; + task_scan_kbd.routine=scan_kbd; + task_scan_kbd.data=NULL; + queue_task(&task_scan_kbd, &tq_timer); + printk(KERN_INFO "Generic scan keyboard driver initialized\n"); +} diff --git a/drivers/char/scan_keyb.h b/drivers/char/scan_keyb.h new file mode 100644 index 000000000..849b50870 --- /dev/null +++ b/drivers/char/scan_keyb.h @@ -0,0 +1,15 @@ +#ifndef __DRIVER_CHAR_SCAN_KEYB_H +#define __DRIVER_CHAR_SCAN_KEYB_H +/* + * $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $ + * Copyright (C) 2000 YAEGASHI Takeshi + * Generic scan keyboard driver + */ + +int register_scan_keyboard(void (*scan)(unsigned char *buffer), + const unsigned char *table, + int length); + +void __init scan_kbd_init(void); + +#endif diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 458cbad6e..82d1bf131 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -43,13 +43,16 @@ * few races on freeing buffers too. * Alan Modra <alan@linuxcare.com> * + * 5/00: Support for the RSA-DV II/S card added. + * Kiyokazu SUTO <suto@ks-and-ks.ne.jp> + * * This module exports the following rs232 io functions: * * int rs_init(void); */ -static char *serial_version = "4.93"; -static char *serial_revdate = "2000-03-20"; +static char *serial_version = "5.01"; +static char *serial_revdate = "2000-05-29"; /* * Serial driver configuration section. Here are the various options: @@ -134,6 +137,8 @@ static char *serial_revdate = "2000-03-20"; #endif #endif +#define CONFIG_SERIAL_RSA + #define RS_STROBE_TIME (10*HZ) #define RS_ISR_PASS_LIMIT 256 @@ -277,9 +282,20 @@ static struct serial_uart_config uart_config[] = { UART_STARTECH }, { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, { 0, 0} }; +#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) + +#define PORT_RSA_MAX 4 +static int probe_rsa[PORT_RSA_MAX]; +static int force_rsa[PORT_RSA_MAX]; + +MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +#endif /* CONFIG_SERIAL_RSA */ + static struct serial_state rs_table[RS_TABLE_SIZE] = { SERIAL_PORT_DFNS /* Defined in serial.h */ }; @@ -293,11 +309,8 @@ static struct serial_state rs_table[RS_TABLE_SIZE] = { static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; static int serial_pci_board_idx = 0; #endif -#ifndef PCI_BASE_ADDRESS -#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) -#define PCI_BASE_REGION_SIZE(dev, r) ((dev)->resource[r].end - \ - (dev)->resource[r].start) -#define IS_PCI_REGION_IOPORT(dev, r) ((dev)->resource[r].flags & \ +#ifndef IS_PCI_REGION_IOPORT +#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ IORESOURCE_IO) #endif #ifndef PCI_IRQ_RESOURCE @@ -314,7 +327,8 @@ static int serial_pci_board_idx = 0; #define ACTIVATE_FUNC(dev) (dev->activate) #define DEACTIVATE_FUNC(dev) (dev->deactivate) #endif - + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) static struct tty_struct *serial_table[NR_PORTS]; static struct termios *serial_termios[NR_PORTS]; @@ -996,6 +1010,9 @@ static void do_softint(void *private_) tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } } @@ -1090,6 +1107,50 @@ static void figure_IRQ_timeout(int irq) IRQ_timeout[irq] = timeout ? timeout : 1; } +#ifdef CONFIG_SERIAL_RSA +/* Attempts to turn on the RSA FIFO. Returns zero on failure */ +static int enable_rsa(struct async_struct *info) +{ + unsigned char mode; + int result; + unsigned long flags; + + save_flags(flags); cli(); + mode = serial_inp(info, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_inp(info, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + restore_flags(flags); + return result; +} + +/* Attempts to turn off the RSA FIFO. Returns zero on failure */ +static int disable_rsa(struct async_struct *info) +{ + unsigned char mode; + int result; + unsigned long flags; + + save_flags(flags); cli(); + mode = serial_inp(info, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_inp(info, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + restore_flags(flags); + return result; +} +#endif /* CONFIG_SERIAL_RSA */ + static int startup(struct async_struct * info) { unsigned long flags; @@ -1127,7 +1188,7 @@ static int startup(struct async_struct * info) printk("starting up ttys%d (irq %d)...", info->line, state->irq); #endif - if (uart_config[info->state->type].flags & UART_STARTECH) { + if (uart_config[state->type].flags & UART_STARTECH) { /* Wake up UART */ serial_outp(info, UART_LCR, 0xBF); serial_outp(info, UART_EFR, UART_EFR_ECB); @@ -1145,7 +1206,7 @@ static int startup(struct async_struct * info) /* * For a XR16C850, we need to set the trigger levels */ - if (info->state->type == PORT_16850) { + if (state->type == PORT_16850) { serial_outp(info, UART_FCTR, UART_FCTR_TRGD | UART_FCTR_RX); serial_outp(info, UART_TRG, UART_TRG_96); @@ -1156,12 +1217,12 @@ static int startup(struct async_struct * info) serial_outp(info, UART_LCR, 0); } - if (info->state->type == PORT_16750) { + if (state->type == PORT_16750) { /* Wake up UART */ serial_outp(info, UART_IER, 0); } - if (info->state->type == PORT_16C950) { + if (state->type == PORT_16C950) { /* Wake up and initialize UART */ info->ACR = 0; serial_outp(info, UART_LCR, 0xBF); @@ -1174,6 +1235,20 @@ static int startup(struct async_struct * info) serial_outp(info, UART_LCR, 0); } +#ifdef CONFIG_SERIAL_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + if (state->type == PORT_RSA) { + if (state->baud_base != SERIAL_RSA_BAUD_BASE && + enable_rsa(info)) + state->baud_base = SERIAL_RSA_BAUD_BASE; + if (state->baud_base == SERIAL_RSA_BAUD_BASE) + serial_outp(info, UART_RSA_FRR, 0); + } +#endif + /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) @@ -1199,7 +1274,8 @@ static int startup(struct async_struct * info) * if it is, then bail out, because there's likely no UART * here. */ - if (serial_inp(info, UART_LSR) == 0xff) { + if (!(info->flags & ASYNC_BUGGY_UART) && + (serial_inp(info, UART_LSR) == 0xff)) { printk("LSR safety check engaged!\n"); if (capable(CAP_SYS_ADMIN)) { if (info->tty) @@ -1425,6 +1501,17 @@ static void shutdown(struct async_struct * info) UART_FCR_CLEAR_XMIT)); serial_outp(info, UART_FCR, 0); +#ifdef CONFIG_SERIAL_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + if ((state->type == PORT_RSA) && + (state->baud_base == SERIAL_RSA_BAUD_BASE && + disable_rsa(info))) + state->baud_base = SERIAL_RSA_BAUD_BASE_LO; +#endif + + (void)serial_in(info, UART_RX); /* read data port to reset things */ if (info->tty) @@ -1522,6 +1609,12 @@ static void change_speed(struct async_struct *info, baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; /* B0 transition handled in rs_set_termios */ +#ifdef CONFIG_SERIAL_RSA + if ((info->state->type == PORT_RSA) && + (info->state->baud_base != SERIAL_RSA_BAUD_BASE) && + enable_rsa(info)) + info->state->baud_base = SERIAL_RSA_BAUD_BASE; +#endif baud_base = info->state->baud_base; if (info->state->type == PORT_16C950) { if (baud <= baud_base) @@ -1583,6 +1676,10 @@ static void change_speed(struct async_struct *info, if (uart_config[info->state->type].flags & UART_USE_FIFO) { if ((info->state->baud_base / quot) < 2400) fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; +#ifdef CONFIG_SERIAL_RSA + else if (info->state->type == PORT_RSA) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; +#endif else fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; } @@ -1810,6 +1907,9 @@ static void rs_flush_buffer(struct tty_struct *tty) info->xmit.head = info->xmit.tail = 0; restore_flags(flags); wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); @@ -1912,6 +2012,10 @@ static int get_serial_info(struct async_struct * info, tmp.type = state->type; tmp.line = state->line; tmp.port = state->port; + if (HIGH_BITS_OFFSET) + tmp.port_high = state->port >> HIGH_BITS_OFFSET; + else + tmp.port_high = 0; tmp.irq = state->irq; tmp.flags = state->flags; tmp.xmit_fifo_size = state->xmit_fifo_size; @@ -1933,14 +2037,19 @@ static int set_serial_info(struct async_struct * info, struct serial_state old_state, *state; unsigned int i,change_irq,change_port; int retval = 0; + unsigned long new_port; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; state = info->state; old_state = *state; - + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += new_serial.port_high << HIGH_BITS_OFFSET; + change_irq = new_serial.irq != state->irq; - change_port = (new_serial.port != state->port) || + change_port = (new_port != ((int) state->port)) || (new_serial.hub6 != state->hub6); if (!capable(CAP_SYS_ADMIN)) { @@ -1978,7 +2087,7 @@ static int set_serial_info(struct async_struct * info, if (new_serial.type) { for (i = 0 ; i < NR_PORTS; i++) if ((state != &rs_table[i]) && - (rs_table[i].port == new_serial.port) && + (rs_table[i].port == new_port) && rs_table[i].type) return -EADDRINUSE; } @@ -2005,8 +2114,14 @@ static int set_serial_info(struct async_struct * info, info->xmit_fifo_size = state->xmit_fifo_size = new_serial.xmit_fifo_size; - if ((state->type != PORT_UNKNOWN) && state->port) + if ((state->type != PORT_UNKNOWN) && state->port) { +#ifdef CONFIG_SERIAL_RSA + if (old_state.type == PORT_RSA) + release_region(state->port + UART_RSA_BASE, 16); + else +#endif release_region(state->port,8); + } state->type = new_serial.type; if (change_port || change_irq) { /* @@ -2015,15 +2130,22 @@ static int set_serial_info(struct async_struct * info, */ shutdown(info); state->irq = new_serial.irq; - info->port = state->port = new_serial.port; + info->port = state->port = new_port; info->hub6 = state->hub6 = new_serial.hub6; if (info->hub6) info->io_type = state->io_type = SERIAL_IO_HUB6; else if (info->io_type == SERIAL_IO_HUB6) info->io_type = state->io_type = SERIAL_IO_PORT; } - if ((state->type != PORT_UNKNOWN) && state->port) - request_region(state->port,8,"serial(set)"); + if ((state->type != PORT_UNKNOWN) && state->port) { +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + request_region(state->port + UART_RSA_BASE, + 16, "serial_rsa(set)"); + else +#endif + request_region(state->port,8,"serial(set)"); + } check_and_exit: @@ -2462,6 +2584,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, /* note the counters on entry */ cprev = info->state->icount; restore_flags(flags); + /* Force modem status interrupts on */ + info->IER |= UART_IER_MSI; + serial_out(info, UART_IER, info->IER); while (1) { interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ @@ -3348,6 +3473,16 @@ static void autoconfig_startech_uarts(struct async_struct *info, * LSR register (which serial_icr_read does) */ if (state->type == PORT_16550A) { + /* + * EFR [4] must be set else this test fails + * + * This shouldn't be necessary, but Mike Hudson + * (Exoray@isys.ca) claims that it's needed for 952 + * dual UART's (which are not recommended for new designs). + */ + serial_out(info, UART_LCR, 0xBF); + serial_out(info, UART_EFR, 0x10); + serial_out(info, UART_LCR, 0x00); /* Check for Oxford Semiconductor 16C950 */ scratch = serial_icr_read(info, UART_ID1); scratch2 = serial_icr_read(info, UART_ID2); @@ -3434,7 +3569,8 @@ static void autoconfig(struct serial_state * state) save_flags(flags); cli(); - if (!state->iomem_base) { + if (!(state->flags & ASYNC_BUGGY_UART) && + !state->iomem_base) { /* * Do a simple existence test first; if we fail this, * there's no point trying anything else. @@ -3459,8 +3595,9 @@ static void autoconfig(struct serial_state * state) serial_outp(info, UART_IER, scratch); if (scratch2 || scratch3 != 0x0F) { #ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: simple autoconfig failed\n", - state->line); + printk("serial: ttyS%d: simple autoconfig failed " + "(%02x, %02x)\n", state->line, + scratch2, scratch3); #endif restore_flags(flags); return; /* We failed; there's nothing here */ @@ -3545,6 +3682,25 @@ static void autoconfig(struct serial_state * state) } serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } +#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) + if (state->type == PORT_16550A) { + int i; + + for (i = 0 ; i < PORT_RSA_MAX ; ++i) { + if (!probe_rsa[i] && !force_rsa[i]) + break; + if (((probe_rsa[i] != state->port) || + check_region(state->port + UART_RSA_BASE, 16)) && + (force_rsa[i] != state->port)) + continue; + if (!enable_rsa(info)) + continue; + state->type = PORT_RSA; + state->baud_base = SERIAL_RSA_BAUD_BASE; + break; + } + } +#endif serial_outp(info, UART_LCR, save_lcr); if (state->type == PORT_16450) { scratch = serial_in(info, UART_SCR); @@ -3564,12 +3720,23 @@ static void autoconfig(struct serial_state * state) return; } - if (info->port) - request_region(info->port,8,"serial(auto)"); + if (info->port) { +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + request_region(info->port + UART_RSA_BASE, 16, + "serial_rsa(auto)"); + else +#endif + request_region(info->port,8,"serial(auto)"); + } /* * Reset the UART. */ +#ifdef CONFIG_SERIAL_RSA + if (state->type == PORT_RSA) + serial_outp(info, UART_RSA_FRR, 0); +#endif serial_outp(info, UART_MCR, save_mcr); serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | @@ -3614,7 +3781,7 @@ static void __init printk_pnp_dev_id(unsigned short vendor, static _INLINE_ int get_pci_port(struct pci_dev *dev, struct pci_board *board, - struct serial_struct *state, + struct serial_struct *req, int idx) { unsigned long port; @@ -3626,24 +3793,28 @@ static _INLINE_ int get_pci_port(struct pci_dev *dev, base_idx += idx; if (board->flags & SPCI_FL_REGION_SZ_CAP) { - max_port = PCI_BASE_REGION_SIZE(dev, base_idx) / 8; + max_port = pci_resource_len(dev, base_idx) / 8; if (idx >= max_port) return 1; } - port = PCI_BASE_ADDRESS(dev, base_idx) + board->first_uart_offset; + port = pci_resource_start(dev, base_idx) + board->first_uart_offset; if ((board->flags & SPCI_FL_BASE_TABLE) == 0) port += idx * (board->uart_offset ? board->uart_offset : 8); if (IS_PCI_REGION_IOPORT(dev, base_idx)) { - state->port = port; + req->port = port; + if (HIGH_BITS_OFFSET) + req->port_high = port >> HIGH_BITS_OFFSET; + else + req->port_high = 0; return 0; } - state->io_type = SERIAL_IO_MEM; - state->iomem_base = ioremap(port, board->uart_offset); - state->iomem_reg_shift = board->reg_shift; - state->port = 0; + req->io_type = SERIAL_IO_MEM; + req->iomem_base = ioremap(port, board->uart_offset); + req->iomem_reg_shift = board->reg_shift; + req->port = 0; return 0; } @@ -3670,23 +3841,28 @@ static void __init start_pci_pnp_board(struct pci_dev *dev, struct pci_board *board) { int k, line; - struct serial_struct fake_state; + struct serial_struct serial_req; int base_baud; if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { - printk("SERIAL: PNP device '"); + printk("serial: PNP device '"); printk_pnp_dev_id(board->vendor, board->device); printk("' prepare failed\n"); return; } if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { - printk("SERIAL: PNP device '"); + printk("serial: PNP device '"); printk_pnp_dev_id(board->vendor, board->device); printk("' activate failed\n"); return; } + if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) { + printk("serial: PCI device enable failed\n"); + return; + } + /* * Run the initialization function, if any */ @@ -3710,18 +3886,18 @@ static void __init start_pci_pnp_board(struct pci_dev *dev, base_baud = board->base_baud; if (!base_baud) base_baud = BASE_BAUD; - memset(&fake_state, 0, sizeof(fake_state)); + memset(&serial_req, 0, sizeof(serial_req)); for (k=0; k < board->num_ports; k++) { - fake_state.irq = get_pci_irq(dev, board, k); - if (get_pci_port(dev, board, &fake_state, k)) + serial_req.irq = get_pci_irq(dev, board, k); + if (get_pci_port(dev, board, &serial_req, k)) break; - fake_state.flags = ASYNC_SKIP_TEST; + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; #ifdef SERIAL_DEBUG_PCI printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", - fake_state.port, fake_state.irq, fake_state.io_type); + serial_req.port, serial_req.irq, serial_req.io_type); #endif - line = register_serial(&fake_state); + line = register_serial(&serial_req); if (line < 0) break; rs_table[line].baud_base = base_baud; @@ -3742,28 +3918,45 @@ __init #endif pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) { - u8 data, *p, scratch; + u8 data, *p, irq_config; + int pci_config; + irq_config = 0x41; + pci_config = PCI_COMMAND_MEMORY; + if (dev->vendor == PCI_VENDOR_ID_PANACOM) + irq_config = 0x43; + if ((dev->vendor == PCI_VENDOR_ID_PLX) && + (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) { + /* + * As the megawolf cards have the int pins active + * high, and have 2 UART chips, both ints must be + * enabled on the 9050. Also, the UARTS are set in + * 16450 mode by default, so we have to enable the + * 16C950 'enhanced' mode so that we can use the deep + * FIFOs + */ + irq_config = 0x5b; + pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + } + pci_read_config_byte(dev, PCI_COMMAND, &data); if (enable) pci_write_config_byte(dev, PCI_COMMAND, - data | PCI_COMMAND_MEMORY); + data | pci_config); /* enable/disable interrupts */ - p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); - scratch = 0x41; - if (dev->vendor == PCI_VENDOR_ID_PANACOM) - scratch = 0x43; - writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c); + p = ioremap(pci_resource_start(dev, 0), 0x80); + writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c); iounmap(p); if (!enable) pci_write_config_byte(dev, PCI_COMMAND, - data & ~PCI_COMMAND_MEMORY); + data & ~pci_config); return 0; } + /* * SIIG serial cards have an PCI interface chip which also controls * the UART clocking frequency. Each UART can be clocked independently @@ -3796,7 +3989,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) if (!enable) return 0; - p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80); + p = ioremap(pci_resource_start(dev, 0), 0x80); switch (dev->device & 0xfff8) { case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ @@ -3841,6 +4034,36 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) return 0; } +/* Added for EKF Intel i960 serial boards */ +static int +#ifndef MODULE +__init +#endif +pci_inteli960ni_fn(struct pci_dev *dev, + struct pci_board *board, + int enable) +{ + unsigned long oldval; + + if (!(board->subdevice & 0x1000)) + return(-1); + + if (!enable) /* is there something to deinit? */ + return(0); + +#ifdef SERIAL_DEBUG_PCI + printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n", + (unsigned long) board->subdevice); +#endif + /* is firmware started? */ + pci_read_config_dword(dev, 0x44, (void*) &oldval); + if (oldval == 0x00001000L) { /* RESET value */ + printk(KERN_DEBUG "Local i960 firmware missing"); + return(-1); + } + return(0); +} + /* * This is the configuration table for all of the PCI serial boards @@ -3851,8 +4074,9 @@ static struct pci_board pci_boards[] __initdata = { * Vendor ID, Device ID, * Subvendor ID, Subdevice ID, * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, - * Offset to get to next UART's registers - * Register shift to use for memory-mapped I/O + * Offset to get to next UART's registers, + * Register shift to use for memory-mapped I/O, + * Initialization function, first UART offset */ { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, PCI_SUBVENDOR_ID_CONNECT_TECH, @@ -3942,6 +4166,10 @@ static struct pci_board pci_boards[] __initdata = { { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, + /* VScom SPCOM800, from sl@s.pl */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2, 8, 921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, PCI_SUBDEVICE_ID_KEYSPAN_SX2, @@ -3979,6 +4207,12 @@ static struct pci_board pci_boards[] __initdata = { PCI_SUBVENDOR_ID_CHASE_PCIRAS, PCI_SUBDEVICE_ID_CHASE_PCIRAS8, SPCI_FL_BASE2, 8, 460800 }, + /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ + /* (Exoray@isys.ca) */ + { PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS, + 0x10b5, 0x106a, + SPCI_FL_BASE2, 4, 921600, + 0x20, 2, pci_plx9050_fn, 0x03 }, { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE1, 4, 115200 }, @@ -4164,7 +4398,7 @@ static struct pci_board pci_boards[] __initdata = { PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, 0, 0, pci_siig20x_fn }, - /* Computone devices submitted by Doug McNash dougm@computone.com */ + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, SPCI_FL_BASE0, 4, 921600, /* IOMEM */ @@ -4198,6 +4432,15 @@ static struct pci_board pci_boards[] __initdata = { { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, PCI_ANY_ID, PCI_ANY_ID, SPCI_FL_BASE0, 4, 921600 }, + /* EKF addition for i960 Boards form EKF with serial port */ + { PCI_VENDOR_ID_INTEL, 0x1960, + 0xE4BF, PCI_ANY_ID, + SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ + 8<<2, 2, pci_inteli960ni_fn, 0x10000}, + /* RAStel 2 port modem, gerg@moreton.com.au */ + { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* * Untested PCI modems, sent in from various folks... */ @@ -4222,12 +4465,12 @@ static struct pci_board pci_boards[] __initdata = { }; /* - * Given a complete unknown PCI device, try to use some hueristics to + * Given a complete unknown PCI device, try to use some heuristics to * guess what the configuration might be, based on the pitiful PCI * serial specs. Returns 0 on success, 1 on failure. */ -static int _INLINE_ serial_guess_board(struct pci_dev *dev, - struct pci_board *board) +static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev, + struct pci_board *board) { int num_iomem = 0, num_port = 0, first_port = -1; int i; @@ -4282,13 +4525,6 @@ static void __init probe_serial_pci(void) printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - if (!pcibios_present()) { -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); -#endif - return; - } - pci_for_each_dev(dev) { for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && @@ -4306,7 +4542,7 @@ static void __init probe_serial_pci(void) break; } - if (board->vendor == 0 && serial_guess_board(dev, board)) + if (board->vendor == 0 && serial_pci_guess_board(dev, board)) continue; start_pci_pnp_board(dev, board); @@ -4322,58 +4558,280 @@ static void __init probe_serial_pci(void) #ifdef ENABLE_SERIAL_PNP -static struct pci_board pnp_devices[] __initdata = { - /* Motorola VoiceSURFR 56K Modem */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, +struct pnp_board { + unsigned short vendor; + unsigned short device; +}; + +static struct pnp_board pnp_devices[] __initdata = { + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, + /* Anchor Datacomm BV */ + /* SXPro 144 External Data Fax Modem Plug & Play */ + { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) }, + /* SXPro 288 External Data Fax Modem Plug & Play */ + { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) }, /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT, - 1, 115200 }, + { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) }, /* AZT3005 PnP SOUND DEVICE */ - { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) }, /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, + /* Boca Research */ + /* Boca Complete Ofc Communicator 14.4 Data-FAX */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, /* Boca Research 33,600 ACF Modem */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, + /* Computer Peripherals Inc */ + /* EuroViVa CommCenter-33.6 SP PnP */ + { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) }, + /* Creative Labs */ + /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ + { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) }, + /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ + { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) }, + /* Creative */ /* Creative Modem Blaster Flash56 DI5601-1 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) }, /* Creative Modem Blaster V.90 DI5660 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) }, + /* FUJITSU */ + /* Fujitsu 33600 PnP-I2 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) }, + /* Fujitsu FMV-FX431 Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) }, + /* Fujitsu 33600 PnP-I4 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) }, + /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ + { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) }, + /* Hayes */ + /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) }, + /* Hayes Optima 336 V.34 + FAX + Voice PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) }, + /* Hayes Optima 336B V.34 + FAX + Voice PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) }, + /* Hayes Accura 56K Fax Modem PnP */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) }, + /* Hayes 288, V.34 + FAX */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) }, + /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ + { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) }, + /* IBM */ + /* IBM Thinkpad 701 Internal Modem Voice */ + { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) }, + /* Intertex */ + /* Intertex 28k8 33k6 Voice EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) }, + /* Intertex 33k6 56k Voice EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) }, + /* Intertex 28k8 33k6 Voice SP INT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) }, + /* Kortex International */ + /* KORTEX 28800 Externe PnP */ + { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) }, + /* KXPro 33.6 Vocal ASVD PnP */ + { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) }, + /* Lasat */ + /* LASAT Internet 33600 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) }, + /* Lasat Safire 560 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) }, + /* Lasat Safire 336 PnP */ + { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) }, + /* Microcom, Inc. */ + /* Microcom TravelPorte FAST V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) }, + /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) }, + /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) }, + /* Microcom DeskPorte 28.8P Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, + /* Microcom DeskPorte 28.8S Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) }, + /* Motorola */ + /* Motorola BitSURFR Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) }, + /* Motorola TA210 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) }, + /* Motorola HMTA 200 (ISDN) Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) }, + /* Motorola BitSURFR Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) }, + /* Motorola Lifestyle 28.8 Internal */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) }, + /* Motorola V.3400 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) }, + /* Motorola Lifestyle 28.8 V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) }, + /* Motorola Power 28.8 V.34 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) }, + /* Motorola ModemSURFR External 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) }, + /* Motorola Premier 33.6 Desktop Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) }, + /* Motorola VoiceSURFR 56K External PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) }, + /* Motorola ModemSURFR 56K External PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) }, + /* Motorola ModemSURFR 56K Internal PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) }, + /* Motorola ModemSURFR Internal 28.8 Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) }, + /* Motorola Premier 33.6 Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) }, + /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) }, + /* Motorola VoiceSURFR 56K Internal PnP */ + { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) }, + /* Com 1 */ + /* Deskline K56 Phone System PnP */ + { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) }, + /* PC Rider K56 Phone System PnP */ + { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) }, /* Pace 56 Voice Internal Plug & Play Modem */ - { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* SupraExpress 28.8 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* US Robotics Sporster 33600 Modem */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* U.S. Robotics 56K FAX INT */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* Viking 56K FAX INT */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - - /* These ID's are taken from M$ documentation */ - /* Compaq 14400 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, - /* Compaq 2400/9600 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) }, + /* Generic */ /* Generic standard PC COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, /* Generic 16550A-compatible COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0, - SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 }, + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, + /* Compaq 14400 Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) }, + /* Compaq 2400/9600 Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) }, + /* Dial-Up Networking Serial Cable between 2 PCs */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) }, + /* Dial-Up Networking Parallel Cable between 2 PCs */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) }, + /* Standard 28800 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) }, + /* Standard Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) }, + /* Standard 9600 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) }, + /* Standard 14400 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) }, + /* Standard 28800 bps Modem*/ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) }, + /* Standard 28800 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) }, + /* Standard 9600 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) }, + /* Standard 14400 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) }, + /* Standard 28800 bps Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) }, + /* Standard Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) }, + /* Standard PCMCIA Card Modem */ + { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) }, + /* Rockwell */ + /* Modular Technology */ + /* Rockwell 33.6 DPF Internal PnP */ + /* Modular Technology 33.6 Internal PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) }, + /* Kortex International */ + /* KORTEX 14400 Externe PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) }, + /* Viking Components, Inc */ + /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ + { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) }, + /* Rockwell */ + /* British Telecom */ + /* Modular Technology */ + /* Rockwell 33.6 DPF External PnP */ + /* BT Prologue 33.6 External PnP */ + /* Modular Technology 33.6 External PnP */ + { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) }, + /* Viking 56K FAX INT */ + { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) }, + /* SupraExpress 28.8 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) }, + /* Phoebe Micro */ + /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ + { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, + /* 3Com Corp. */ + /* Gateway Telepath IIvi 33.6 */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) }, + /* Sportster Vi 14.4 PnP FAX Voicemail */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) }, + /* U.S. Robotics 33.6K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) }, + /* U.S. Robotics 56K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) }, + /* U.S. Robotics 56K FAX INT */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) }, + /* U.S. Robotics 56K Voice EXT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) }, + /* U.S. Robotics 56K Voice INT PnP */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) }, + /* U.S. Robotics 56K Message */ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) }, + /* U.S. Robotics 56K FAX EXT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) }, + /* U.S. Robotics 56K FAX INT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) }, + /* U.S. Robotics 56K Voice EXT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) }, + /* U.S. Robotics 56K Voice INT PnP*/ + { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) }, { 0, } }; @@ -4395,10 +4853,80 @@ static void inline avoid_irq_share(struct pci_dev *dev) irq->map = map; } +static char *modem_names[] __initdata = { + "MODEM", "Modem", "modem", "FAX", "Fax", "fax", + "56K", "56k", "K56", "33.6", "28.8", "14.4", + "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", + "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 +}; + +static int __init check_name(char *name) +{ + char **tmp = modem_names; + + while (*tmp) { + if (strstr(name, *tmp)) + return 1; + tmp++; + } + return 0; +} + +static int inline check_compatible_id(struct pci_dev *dev) +{ + int i; + for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++) + if ((dev->vendor_compatible[i] == + ISAPNP_VENDOR('P', 'N', 'P')) && + (swab16(dev->device_compatible[i]) >= 0xc000) && + (swab16(dev->device_compatible[i]) <= 0xdfff)) + return 0; + return 1; +} + +/* + * Given a complete unknown ISA PnP device, try to use some heuristics to + * detect modems. Currently use such heuristic set: + * - dev->name or dev->bus->name must contain "modem" substring; + * - device must have only one IO region (8 byte long) with base adress + * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. + * + * Such detection looks very ugly, but can detect at least some of numerous + * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[] + * table. + */ +static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev, + struct pci_board *board) +{ + struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata; + struct isapnp_resources *resa; + + if (!(check_name(dev->name) || check_name(dev->bus->name)) && + !(check_compatible_id(dev))) + return 1; + + if (!res || res->next) + return 1; + + for (resa = res->alt; resa; resa = resa->alt) { + struct isapnp_port *port; + for (port = res->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || + (port->min == 0x3e8))) + return 0; + } + + return 1; +} + static void __init probe_serial_pnp(void) { struct pci_dev *dev = NULL; - struct pci_board *board; + struct pnp_board *pnp_board; + struct pci_board board; #ifdef SERIAL_DEBUG_PNP printk("Entered probe_serial_pnp()\n"); @@ -4410,13 +4938,35 @@ static void __init probe_serial_pnp(void) return; } - for (board = pnp_devices; board->vendor; board++) { - while ((dev = isapnp_find_dev(NULL, board->vendor, - board->device, dev))) { - if (board->flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); - start_pci_pnp_board(dev, board); - } + isapnp_for_each_dev(dev) { + if (dev->active) + continue; + + memset(&board, 0, sizeof(board)); + board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT; + board.num_ports = 1; + board.base_baud = 115200; + + for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++) + if ((dev->vendor == pnp_board->vendor) && + (dev->device == pnp_board->device)) + break; + + if (pnp_board->vendor) { + board.vendor = pnp_board->vendor; + board.device = pnp_board->device; + /* Special case that's more efficient to hardcode */ + if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') && + board.device == ISAPNP_DEVICE(0x1021))) + board.flags |= SPCI_FL_NO_SHIRQ; + } else { + if (serial_pnp_guess_board(dev, &board)) + continue; + } + + if (board.flags & SPCI_FL_NO_SHIRQ) + avoid_irq_share(dev); + start_pci_pnp_board(dev, &board); } #ifdef SERIAL_DEBUG_PNP @@ -4478,7 +5028,7 @@ int __init rs_init(void) #if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "serial"; #endif -#ifdef CONFIG_DEVFS_FS +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d"; #else serial_driver.name = "ttyS"; @@ -4526,7 +5076,7 @@ int __init rs_init(void) * major number and the subtype code. */ callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS +#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d"; #else callout_driver.name = "cua"; @@ -4616,14 +5166,25 @@ int register_serial(struct serial_struct *req) unsigned long flags; struct serial_state *state; struct async_struct *info; + unsigned long port; + + port = req->port; + if (HIGH_BITS_OFFSET) + port += req->port_high << HIGH_BITS_OFFSET; save_flags(flags); cli(); for (i = 0; i < NR_PORTS; i++) { - if ((rs_table[i].port == req->port) && + if ((rs_table[i].port == port) && (rs_table[i].iomem_base == req->iomem_base)) break; } if (i == NR_PORTS) { + for (i = 4; i < NR_PORTS; i++) + if ((rs_table[i].type == PORT_UNKNOWN) && + (rs_table[i].count == 0)) + break; + } + if (i == NR_PORTS) { for (i = 0; i < NR_PORTS; i++) if ((rs_table[i].type == PORT_UNKNOWN) && (rs_table[i].count == 0)) @@ -4637,11 +5198,11 @@ int register_serial(struct serial_struct *req) if (rs_table[i].count) { restore_flags(flags); printk("Couldn't configure serial #%d (port=%ld,irq=%d): " - "device already open\n", i, req->port, req->irq); + "device already open\n", i, port, req->irq); return -1; } state->irq = req->irq; - state->port = req->port; + state->port = port; state->flags = req->flags; state->io_type = req->io_type; state->iomem_base = req->iomem_base; @@ -4649,7 +5210,7 @@ int register_serial(struct serial_struct *req) if (req->baud_base) state->baud_base = req->baud_base; if ((info = state->info) != NULL) { - info->port = req->port; + info->port = port; info->flags = req->flags; info->io_type = req->io_type; info->iomem_base = req->iomem_base; @@ -4722,10 +5283,10 @@ void rs_fini(void) timer_table[RS_TIMER].expires = 0; remove_bh(SERIAL_BH); if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", + printk("serial: failed to unregister serial driver (%d)\n", e1); if ((e2 = tty_unregister_driver(&callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", + printk("serial: failed to unregister callout driver (%d)\n", e2); restore_flags(flags); @@ -4734,8 +5295,15 @@ void rs_fini(void) rs_table[i].info = NULL; kfree_s(info, sizeof(struct async_struct)); } - if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) - release_region(rs_table[i].port, 8); + if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) { +#ifdef CONFIG_SERIAL_RSA + if (rs_table[i].type == PORT_RSA) + release_region(rs_table[i].port + + UART_RSA_BASE, 16); + else +#endif + release_region(rs_table[i].port, 8); + } #if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) if (rs_table[i].iomem_base) iounmap(rs_table[i].iomem_base); @@ -4882,9 +5450,6 @@ static int __init serial_console_setup(struct console *co, char *options) int cflag = CREAD | HUPCL | CLOCAL; int quot = 0; char *s; -#if defined(CONFIG_KDB) - extern int kdb_port; -#endif if (options) { baud = simple_strtoul(options, NULL, 10); @@ -4988,14 +5553,6 @@ static int __init serial_console_setup(struct console *co, char *options) if (serial_in(info, UART_LSR) == 0xff) return -1; -#if defined(CONFIG_KDB) - /* - * Remember I/O port for kdb - */ - if (kdb_port == 0 ) - kdb_port = ser->port; -#endif /* CONFIG_KDB */ - return 0; } @@ -5024,6 +5581,6 @@ void __init serial_console_init(void) /* Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" + compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" End: */ diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c index 05bfcb607..b51e91557 100644 --- a/drivers/char/sh-sci.c +++ b/drivers/char/sh-sci.c @@ -5,6 +5,7 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Sugioka Toshinobu + * Modified to support multiple serial ports. Stuart Menefy (May 2000). * * TTY code is based on sx.c (Specialix SX driver) by: * @@ -31,7 +32,9 @@ #include <linux/malloc.h> #include <linux/init.h> #include <linux/delay.h> +#ifdef CONFIG_SERIAL_CONSOLE #include <linux/console.h> +#endif #include <asm/system.h> #include <asm/io.h> @@ -40,15 +43,23 @@ #include <asm/bitops.h> #include <linux/generic_serial.h> -#include "sh-sci.h" #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB static void gdb_detach(void); +static int in_gdb = 1; +#define IN_GDB in_gdb #endif +#include "sh-sci.h" -struct sci_port sci_ports[1]; +#ifdef CONFIG_SERIAL_CONSOLE +static struct console sercons; +static struct sci_port* sercons_port; +static int sercons_baud; +#endif /* Function prototypes */ +static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag); +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag); static void sci_disable_tx_interrupts(void *ptr); static void sci_enable_tx_interrupts(void *ptr); static void sci_disable_rx_interrupts(void *ptr); @@ -63,9 +74,10 @@ static int sci_init_drivers(void); static struct tty_driver sci_driver, sci_callout_driver; -#define SCI_NPORTS 1 +static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT; static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, }; -static struct termios *sci_termios[2]; /* nomal, locked */ +static struct termios *sci_termios[SCI_NPORTS]; +static struct termios *sci_termios_locked[SCI_NPORTS]; int sci_refcount; int sci_debug = 0; @@ -88,6 +100,63 @@ static struct real_driver sci_real_driver = { NULL }; +#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) +static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag) +{ +} +#endif + +#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF) +#if defined(__sh3__) +/* For SH7709, SH7709A, SH7729 */ +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ + ctrl_outw(data&0x0fcf, SCPCR); + } + if (cflag & CRTSCTS) + fcr_val |= SCFCR_MCE; + else { + unsigned short data; + + /* We need to set SCPCR to enable RTS/CTS */ + data = ctrl_inw(SCPCR); + /* Clear out SCP7MD1,0, SCP4MD1,0, + Set SCP6MD1,0 = {01} (output) */ + ctrl_outw((data&0x0fcf)|0x1000, SCPCR); + + data = ctrl_inb(SCPDR); + /* Set /RTS2 (bit6) = 0 */ + ctrl_outb(data&0xbf, SCPDR); + } + sci_out(port, SCFCR, fcr_val); +} + +#else + +/* For SH7750 */ +static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag) +{ + unsigned int fcr_val = 0; + + if (cflag & CRTSCTS) { + fcr_val |= SCFCR_MCE; + } else { + ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ + } + sci_out(port, SCFCR, fcr_val); +} + +#endif +#endif /* SCIF_ONLY || SCI_AND_SCIF */ + static void sci_setsignals(struct sci_port *port, int dtr, int rts) { /* This routine is used for seting signals of: DTR, DCD, CTS/RTS */ @@ -112,11 +181,11 @@ static int sci_getsignals(struct sci_port *port) */ } -static void sci_set_baud(struct sci_port *port) +static void sci_set_baud(struct sci_port *port, int baud) { int t; - switch (port->gs.baud) { + switch (baud) { case 0: t = -1; break; @@ -136,7 +205,7 @@ static void sci_set_baud(struct sci_port *port) t = BPS_38400; break; default: - printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud); + printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", baud); case 115200: t = BPS_115200; break; @@ -145,93 +214,57 @@ static void sci_set_baud(struct sci_port *port) if (t > 0) { sci_setsignals (port, 1, -1); if(t >= 256) { - ctrl_out((ctrl_in(SCSMR) & ~3) | 1, SCSMR); + sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; } - ctrl_outb(t, SCBRR); - ctrl_outw(0xa400, RFCR); /* Refresh counter clear */ - while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER) - ; + sci_out(port, SCBRR, t); + udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ } else { sci_setsignals (port, 0, -1); } } -static void sci_set_termios_cflag(struct sci_port *port) +static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud) { - unsigned short status; - unsigned short smr_val; -#if defined(CONFIG_SH_SCIF_SERIAL) - unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */ -#endif + unsigned int status; + unsigned int smr_val; do - status = ctrl_in(SC_SR); - while (!(status & SCI_TEND)); + status = sci_in(port, SCxSR); + while (!(status & SCxSR_TEND(port))); - port->old_cflag = port->gs.tty->termios->c_cflag; + sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */ - ctrl_out(0x00, SCSCR); /* TE=0, RE=0, CKE1=0 */ -#if defined(CONFIG_SH_SCIF_SERIAL) - ctrl_out(fcr_val, SCFCR); - fcr_val = 0; -#endif + if (port->type == PORT_SCIF) { + sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST); + } - smr_val = ctrl_in(SCSMR) & 3; - if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7) + smr_val = sci_in(port, SCSMR) & 3; + if ((cflag & CSIZE) == CS7) smr_val |= 0x40; - if (C_PARENB(port->gs.tty)) + if (cflag & PARENB) smr_val |= 0x20; - if (C_PARODD(port->gs.tty)) + if (cflag & PARODD) smr_val |= 0x10; - if (C_CSTOPB(port->gs.tty)) + if (cflag & CSTOPB) smr_val |= 0x08; - ctrl_out(smr_val, SCSMR); - -#if defined(CONFIG_SH_SCIF_SERIAL) -#if defined(__sh3__) - { /* For SH7709, SH7709A, SH7729 */ - unsigned short data; - - /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); - /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/ - ctrl_outw(data&0x0fcf, SCPCR); - } -#endif - if (C_CRTSCTS(port->gs.tty)) - fcr_val |= 0x08; - else { -#if defined(__sh3__) - unsigned short data; - - /* We need to set SCPCR to enable RTS/CTS */ - data = ctrl_inw(SCPCR); - /* Clear out SCP7MD1,0, SCP4MD1,0, - Set SCP6MD1,0 = {01} (output) */ - ctrl_outw((data&0x0fcf)|0x1000, SCPCR); + sci_out(port, SCSMR, smr_val); - data = ctrl_inb(SCPDR); - /* Set /RTS2 (bit6) = 0 */ - ctrl_outb(data&0xbf, SCPDR); -#elif defined(__SH4__) - ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */ -#endif - } - ctrl_out(fcr_val, SCFCR); -#endif + port->init_pins(port, cflag); - sci_set_baud(port); - ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */ - sci_enable_rx_interrupts(port); + sci_set_baud(port, baud); + sci_out(port, SCSCR, SCSCR_INIT(port)); } static int sci_set_real_termios(void *ptr) { struct sci_port *port = ptr; - if (port->old_cflag != port->gs.tty->termios->c_cflag) - sci_set_termios_cflag(port); + if (port->old_cflag != port->gs.tty->termios->c_cflag) { + port->old_cflag = port->gs.tty->termios->c_cflag; + sci_set_termios_cflag(port, port->old_cflag, port->gs.baud); + sci_enable_rx_interrupts(port); + } /* Tell line discipline whether we will do input cooking */ if (I_OTHER(port->gs.tty)) @@ -265,27 +298,27 @@ static void sci_transmit_chars(struct sci_port *port) unsigned short ctrl; unsigned char c; - status = ctrl_in(SC_SR); - if (!(status & SCI_TD_E)) { + status = sci_in(port, SCxSR); + if (!(status & SCxSR_TDxE(port))) { save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else ctrl |= SCI_CTRL_FLAGS_TIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); return; } while (1) { count = port->gs.xmit_cnt; -#if defined(CONFIG_SH_SCIF_SERIAL) - txroom = 16 - (ctrl_inw(SCFDR)>>8); -#else - txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0; -#endif + if (port->type == PORT_SCIF) { + txroom = 16 - (sci_in(port, SCFDR)>>8); + } else { + txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0; + } if (count > txroom) count = txroom; @@ -299,9 +332,9 @@ static void sci_transmit_chars(struct sci_port *port) for (i=0; i<count; i++) { c = port->gs.xmit_buf[port->gs.xmit_tail + i]; - ctrl_outb(c, SC_TDR); + sci_out(port, SCxTDR, c); } - ctrl_out(SCI_TD_E_CLEAR, SC_SR); + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); /* Update the kernel buffer end */ port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1); @@ -319,18 +352,18 @@ static void sci_transmit_chars(struct sci_port *port) } save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); if (port->gs.xmit_cnt == 0) { ctrl &= ~SCI_CTRL_FLAGS_TIE; port->gs.flags &= ~GS_TX_INTEN; } else { -#if defined(CONFIG_SH_SCIF_SERIAL) - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_TD_E_CLEAR, SC_SR); -#endif + if (port->type == PORT_SCIF) { + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCIF_TDFE); + } ctrl |= SCI_CTRL_FLAGS_TIE; } - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -341,17 +374,17 @@ static inline void sci_receive_chars(struct sci_port *port) int copied=0; unsigned short status; - status = ctrl_in(SC_SR); - if (!(status & SCI_RD_F)) + status = sci_in(port, SCxSR); + if (!(status & SCxSR_RDxF(port))) return; tty = port->gs.tty; while (1) { -#if defined(CONFIG_SH_SCIF_SERIAL) - count = ctrl_inw(SCFDR)&0x001f; -#else - count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0; -#endif + if (port->type == PORT_SCIF) { + count = sci_in(port, SCFDR)&0x001f; + } else { + count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0; + } /* Don't copy more bytes than there is room for in the buffer */ if (tty->flip.count + count > TTY_FLIPBUF_SIZE) @@ -362,9 +395,9 @@ static inline void sci_receive_chars(struct sci_port *port) break; for (i=0; i<count; i++) - tty->flip.char_buf_ptr[i] = ctrl_inb(SC_RDR); - ctrl_in(SC_SR); /* dummy read */ - ctrl_out(SCI_RDRF_CLEAR, SC_SR); + tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR); + sci_in(port, SCxSR); /* dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); @@ -384,16 +417,13 @@ static inline void sci_receive_chars(struct sci_port *port) static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct sci_port *port = ptr; - unsigned long flags; if (port->gs.flags & GS_ACTIVE) if (!(port->gs.flags & SCI_RX_THROTTLE)) { sci_receive_chars(port); return; } - save_and_cli(flags); - ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_RIE, SCSCR); - restore_flags(flags); + sci_disable_rx_interrupts(port); } static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) @@ -403,19 +433,17 @@ static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs) if (port->gs.flags & GS_ACTIVE) sci_transmit_chars(port); else { - unsigned long flags; - - save_and_cli(flags); - ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_TIE, SCSCR); - restore_flags(flags); + sci_disable_tx_interrupts(port); } } static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) { + struct sci_port *port = ptr; + /* Handle errors */ - if (ctrl_in(SC_SR) & SCI_ERRORS) - ctrl_out(SCI_ERROR_CLEAR, SC_SR); + if (sci_in(port, SCxSR) & SCxSR_ERRORS(port)) + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr, regs); @@ -428,14 +456,15 @@ static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs) static void sci_disable_tx_interrupts(void *ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_TIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -443,34 +472,36 @@ static void sci_enable_tx_interrupts(void *ptr) { struct sci_port *port = ptr; - disable_irq(SCI_TXI_IRQ); + disable_irq(port->irqs[SCIx_TXI_IRQ]); sci_transmit_chars(port); - enable_irq(SCI_TXI_IRQ); + enable_irq(port->irqs[SCIx_TXI_IRQ]); } static void sci_disable_rx_interrupts(void * ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl &= ~SCI_CTRL_FLAGS_RIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } static void sci_enable_rx_interrupts(void * ptr) { + struct sci_port *port = ptr; unsigned long flags; unsigned short ctrl; /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ save_and_cli(flags); - ctrl = ctrl_in(SCSCR); + ctrl = sci_in(port, SCSCR); ctrl |= SCI_CTRL_FLAGS_RIE; - ctrl_out(ctrl, SCSCR); + sci_out(port, SCSCR, ctrl); restore_flags(flags); } @@ -482,11 +513,13 @@ static int sci_get_CD(void * ptr) static int sci_chars_in_buffer(void * ptr) { -#if defined(CONFIG_SH_SCIF_SERIAL) - return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1); -#else - return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1; -#endif + struct sci_port *port = ptr; + + if (port->type == PORT_SCIF) { + return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1); + } else { + return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1; + } } static void sci_shutdown_port(void * ptr) @@ -551,6 +584,15 @@ static int sci_open(struct tty_struct * tty, struct file * filp) sci_set_real_termios(port); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + port->gs.baud = sercons_baud; + sercons.cflag = 0; + sci_set_real_termios(port); + } +#endif + sci_enable_rx_interrupts(port); port->gs.session = current->session; @@ -665,6 +707,25 @@ static void sci_unthrottle(struct tty_struct * tty) return; } +#ifdef CONFIG_PROC_FS +static int sci_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i; + struct sci_port *port; + int len = 0; + + len += sprintf(page, "serinfo:1.0\n"); + for (i = 0; i < SCI_NPORTS && len < 4000; i++) { + port = &sci_ports[i]; + len += sprintf(page+len, "%d: uart:%s address: %08x\n", i, + (port->type == PORT_SCI) ? "SCI" : "SCIF", + port->base); + } + return len; +} +#endif + /* ********************************************************************** * * Here are the initialization routines. * * ********************************************************************** */ @@ -678,20 +739,19 @@ static int sci_init_drivers(void) sci_driver.magic = TTY_DRIVER_MAGIC; sci_driver.driver_name = "serial"; sci_driver.name = "ttyS"; - sci_driver.major = TTY_MAJOR; + sci_driver.major = SCI_MAJOR; sci_driver.minor_start = SCI_MINOR_START; - sci_driver.num = 1; + sci_driver.num = SCI_NPORTS; sci_driver.type = TTY_DRIVER_TYPE_SERIAL; sci_driver.subtype = SERIAL_TYPE_NORMAL; sci_driver.init_termios = tty_std_termios; sci_driver.init_termios.c_cflag = - B115200 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; + B9600 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS; sci_driver.flags = TTY_DRIVER_REAL_RAW; sci_driver.refcount = &sci_refcount; sci_driver.table = sci_table; - sci_driver.termios = &sci_termios[0]; - sci_driver.termios_locked = &sci_termios[1]; - sci_termios[0] = sci_termios[1] = NULL; + sci_driver.termios = sci_termios; + sci_driver.termios_locked = sci_termios_locked; sci_driver.open = sci_open; sci_driver.close = gs_close; @@ -708,11 +768,15 @@ static int sci_init_drivers(void) sci_driver.stop = gs_stop; sci_driver.start = gs_start; sci_driver.hangup = gs_hangup; +#ifdef CONFIG_PROC_FS + sci_driver.read_proc = sci_read_proc; +#endif sci_callout_driver = sci_driver; - sci_callout_driver.name = "cua"; - sci_callout_driver.major = TTYAUX_MAJOR; + sci_callout_driver.name = "cusc"; + sci_callout_driver.major = SCI_MAJOR + 1; sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + sci_callout_driver.read_proc = NULL; if ((error = tty_register_driver(&sci_driver))) { printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n", @@ -726,16 +790,17 @@ static int sci_init_drivers(void) return 1; } - port = &sci_ports[0]; - port->gs.callout_termios = tty_std_termios; - port->gs.normal_termios = tty_std_termios; - port->gs.magic = SCI_MAGIC; - port->gs.close_delay = HZ/2; - port->gs.closing_wait = 30 * HZ; - port->gs.rd = &sci_real_driver; - init_waitqueue_head(&port->gs.open_wait); - init_waitqueue_head(&port->gs.close_wait); - port->old_cflag = 0; + for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) { + port->gs.callout_termios = sci_callout_driver.init_termios; + port->gs.normal_termios = sci_driver.init_termios; + port->gs.magic = SCI_MAGIC; + port->gs.close_delay = HZ/2; + port->gs.closing_wait = 30 * HZ; + port->gs.rd = &sci_real_driver; + init_waitqueue_head(&port->gs.open_wait); + init_waitqueue_head(&port->gs.close_wait); + port->old_cflag = 0; + } return 0; } @@ -744,26 +809,20 @@ int __init sci_init(void) { struct sci_port *port; int i; - - for (i=SCI_ERI_IRQ; i<SCI_IRQ_END; i++) - set_ipr_data(i, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); - - port = &sci_ports[0]; - - if (request_irq(SCI_ERI_IRQ, sci_er_interrupt, SA_INTERRUPT, - "serial", port)) { - printk(KERN_ERR "sci: Cannot allocate error irq.\n"); - return -ENODEV; - } - if (request_irq(SCI_RXI_IRQ, sci_rx_interrupt, SA_INTERRUPT, - "serial", port)) { - printk(KERN_ERR "sci: Cannot allocate rx irq.\n"); - return -ENODEV; - } - if (request_irq(SCI_TXI_IRQ, sci_tx_interrupt, SA_INTERRUPT, - "serial", port)) { - printk(KERN_ERR "sci: Cannot allocate tx irq.\n"); - return -ENODEV; + void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt + }; + + for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) { + for (i=0; i<3; i++) { + set_ipr_data(port->irqs[i], port->intc_addr, port->intc_pos, SCI_PRIORITY); + + if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, + "serial", port)) { + printk(KERN_ERR "sci: Cannot allocate irq.\n"); + return -ENODEV; + } + } } /* XXX: How about BRI interrupt?? */ @@ -802,121 +861,21 @@ void cleanup_module(void) * ------------------------------------------------------------ */ -static inline void put_char(char c) -{ - unsigned long flags; - unsigned short status; - - save_and_cli(flags); - - do - status = ctrl_in(SC_SR); - while (!(status & SCI_TD_E)); - - ctrl_outb(c, SC_TDR); - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_TD_E_CLEAR, SC_SR); - - restore_flags(flags); -} - #ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB -static int in_gdb = 1; -static inline void handle_error(void) -{ /* Clear error flags */ - ctrl_out(SCI_ERROR_CLEAR, SC_SR); -} - -static inline int get_char(void) -{ - unsigned long flags; - unsigned short status; - int c; - - save_and_cli(flags); - do { - status = ctrl_in(SC_SR); - if (status & SCI_ERRORS) { - handle_error(); - continue; - } - } while (!(status & SCI_RD_F)); - c = ctrl_inb(SC_RDR); - ctrl_in(SC_SR); /* Dummy read */ - ctrl_out(SCI_RDRF_CLEAR, SC_SR); - restore_flags(flags); - - return c; -} - -/* Taken from sh-stub.c of GDB 4.18 */ -static const char hexchars[] = "0123456789abcdef"; -static char highhex(int x) -{ - return hexchars[(x >> 4) & 0xf]; -} - -static char lowhex(int x) -{ - return hexchars[x & 0xf]; -} - -static void gdb_detach(void) +static void __init gdb_detach(void) { asm volatile("trapa #0xff"); if (in_gdb == 1) { in_gdb = 0; - get_char(); - put_char('\r'); - put_char('\n'); + get_char(sercons_port); + put_char(sercons_port, '\r'); + put_char(sercons_port, '\n'); } } #endif -/* send the packet in buffer. The host get's one chance to read it. - This routine does not wait for a positive acknowledge. */ - -static void -put_string(const char *buffer, int count) -{ - int i; - const unsigned char *p = buffer; -#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB - int checksum; - -if (in_gdb) { - /* $<packet info>#<checksum>. */ - do { - unsigned char c; - put_char('$'); - put_char('O'); /* 'O'utput to console */ - checksum = 'O'; - - for (i=0; i<count; i++) { /* Don't use run length encoding */ - int h, l; - - c = *p++; - h = highhex(c); - l = lowhex(c); - put_char(h); - put_char(l); - checksum += h + l; - } - put_char('#'); - put_char(highhex(checksum)); - put_char(lowhex(checksum)); - } while (get_char() != '+'); -} else -#endif - for (i=0; i<count; i++) { - if (*p == 10) - put_char('\r'); - put_char(*p++); - } -} - /* * Print a string to the serial port trying not to disturb * any possible real use of the port... @@ -924,7 +883,7 @@ if (in_gdb) { static void serial_console_write(struct console *co, const char *s, unsigned count) { - put_string(s, count); + put_string(sercons_port, s, count); } /* @@ -938,7 +897,7 @@ static int serial_console_wait_key(struct console *co) static kdev_t serial_console_device(struct console *c) { - return MKDEV(TTY_MAJOR, SCI_MINOR_START + c->index); + return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index); } /* @@ -949,12 +908,14 @@ static kdev_t serial_console_device(struct console *c) */ static int __init serial_console_setup(struct console *co, char *options) { - int baud = 115200; + int baud = 9600; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; + sercons_port = &sci_ports[co->index]; + if (options) { baud = simple_strtoul(options, NULL, 10); s = options; @@ -983,6 +944,7 @@ static int __init serial_console_setup(struct console *co, char *options) case 9600: default: cflag |= B9600; + baud = 9600; break; } switch (bits) { @@ -1002,14 +964,18 @@ static int __init serial_console_setup(struct console *co, char *options) cflag |= PARENB; break; } + co->cflag = cflag; + sercons_baud = baud; + + sci_set_termios_cflag(sercons_port, cflag, baud); + sercons_port->old_cflag = cflag; - /* XXX: set baud, char, and parity here. */ return 0; } static struct console sercons = { - "ttyS", + "ttySC", serial_console_write, NULL, serial_console_device, diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h index f501951ec..ddf5712a5 100644 --- a/drivers/char/sh-sci.h +++ b/drivers/char/sh-sci.h @@ -5,148 +5,135 @@ * SuperH on-chip serial module support. (SCI with no FIFO / with FIFO) * Copyright (C) 1999, 2000 Niibe Yutaka * Copyright (C) 2000 Greg Banks + * Modified to support multiple serial ports. Stuart Menefy (May 2000). * */ #include <linux/config.h> -#if defined(CONFIG_SH_SCI_SERIAL) -#if defined(__sh3__) -#define SCSMR (volatile unsigned char *)0xfffffe80 -#define SCBRR 0xfffffe82 -#define SCSCR (volatile unsigned char *)0xfffffe84 -#define SC_TDR 0xfffffe86 -#define SC_SR (volatile unsigned char *)0xfffffe88 -#define SC_RDR 0xfffffe8a -#define SCSPTR 0xffffff7c -#elif defined(__SH4__) -#define SCSMR (volatile unsigned char *)0xffe00000 -#define SCBRR 0xffe00004 -#define SCSCR (volatile unsigned char *)0xffe00008 -#define SC_TDR 0xffe0000c -#define SC_SR (volatile unsigned char *)0xffe00010 -#define SC_RDR 0xffe00014 -#define SCSPTR 0xffe0001c +/* Values for sci_port->type */ +#define PORT_SCI 0 +#define PORT_SCIF 1 + +/* Offsets into the sci_port->irqs array */ +#define SCIx_ERI_IRQ 0 +#define SCIx_RXI_IRQ 1 +#define SCIx_TXI_IRQ 2 + +/* ERI, RXI, TXI, INTC reg, INTC pos */ +#define SCI_IRQS { 23, 24, 25 }, INTC_IPRB, 1 +#define SH3_SCIF_IRQS { 56, 57, 59 }, INTC_IPRE, 1 +#define SH4_SCIF_IRQS { 40, 41, 43 }, INTC_IPRC, 1 + +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +# define SCI_NPORTS 1 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci } \ +} +# define SCSPTR 0xffffff7c /* 8 bit */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SH7709) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \ + { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */ +# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */ +# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +# define SCI_AND_SCIF +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +# define SCI_NPORTS 2 +# define SCI_INIT { \ + { {}, PORT_SCI, 0xffe00000, SCI_IRQS, sci_init_pins_sci }, \ + { {}, PORT_SCIF, 0xFFE80000, SH4_SCIF_IRQS, sci_init_pins_scif } \ +} +# define SCSPTR1 0xffe0001c /* 8 bit SCI */ +# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ +# define SCLSR2 0xFFE80024 /* 16 bit SCIF */ +# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ + 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ + 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) +# define SCI_AND_SCIF +#else +# error CPU subtype not defined #endif -#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ +/* SCSCR */ +#define SCI_CTRL_FLAGS_TIE 0x80 /* all */ +#define SCI_CTRL_FLAGS_RIE 0x40 /* all */ +#define SCI_CTRL_FLAGS_TE 0x20 /* all */ +#define SCI_CTRL_FLAGS_RE 0x10 /* all */ +/* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */ +/* SCI_CTRL_FLAGS_MPIE 0x08 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_TEIE 0x04 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_CTRL_FLAGS_CKE1 0x02 * all */ +/* SCI_CTRL_FLAGS_CKE0 0x01 * 7708 SCI, 7709 SCI/SCIF, 7750 SCI */ -#define SCI_TD_E 0x80 -#define SCI_RD_F 0x40 -#define SCI_ORER 0x20 -#define SCI_FER 0x10 -#define SCI_PER 0x08 -#define SCI_TEND 0x04 +/* SCxSR SCI */ +#define SCI_TDRE 0x80 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_RDRF 0x40 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_ORER 0x20 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_FER 0x10 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_PER 0x08 /* 7708 SCI, 7709 SCI, 7750 SCI */ +#define SCI_TEND 0x04 /* 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPB 0x02 * 7708 SCI, 7709 SCI, 7750 SCI */ +/* SCI_MPBT 0x01 * 7708 SCI, 7709 SCI, 7750 SCI */ #define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER) -#define SCI_TD_E_CLEAR 0x78 -#define SCI_RDRF_CLEAR 0xbc -#define SCI_ERROR_CLEAR 0xc4 - -#define SCI_CTRL_FLAGS_TIE 0x80 -#define SCI_CTRL_FLAGS_RIE 0x40 -#define SCI_CTRL_FLAGS_TE 0x20 -#define SCI_CTRL_FLAGS_RE 0x10 -/* TEIE=0x04 */ -#define SCI_CTRL_FLAGS_CKE1 0x02 -#define SCI_CTRL_FLAGS_CKE0 0x01 - -#define SCI_ERI_IRQ 23 -#define SCI_RXI_IRQ 24 -#define SCI_TXI_IRQ 25 -#define SCI_TEI_IRQ 26 -#define SCI_IRQ_END 27 - -#define SCI_IPR_ADDR INTC_IPRB -#define SCI_IPR_POS 1 -#endif - -#if defined(CONFIG_SH_SCIF_SERIAL) -#if defined(__sh3__) -#define SCSMR (volatile unsigned char *)0xA4000150 -#define SCBRR 0xA4000152 -#define SCSCR (volatile unsigned char *)0xA4000154 -#define SC_TDR 0xA4000156 -#define SC_SR (volatile unsigned short *)0xA4000158 -#define SC_RDR 0xA400015A -#define SCFCR (volatile unsigned char *)0xA400015C -#define SCFDR 0xA400015E - -#undef SCSPTR /* SH7709 doesn't have SCSPTR */ -#define SCPCR 0xA4000116 /* Instead, it has SCPCR and SCPDR */ -#define SCPDR 0xA4000136 -#undef SCLSR - -#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ - /* 0x33 when external clock is used */ -#define SCI_IPR_ADDR INTC_IPRE -#define SCI_IPR_POS 1 - -#elif defined(__SH4__) -#define SCSMR (volatile unsigned short *)0xFFE80000 -#define SCBRR 0xFFE80004 -#define SCSCR (volatile unsigned short *)0xFFE80008 -#define SC_TDR 0xFFE8000C -#define SC_SR (volatile unsigned short *)0xFFE80010 -#define SC_RDR 0xFFE80014 -#define SCFCR (volatile unsigned short *)0xFFE80018 -#define SCFDR 0xFFE8001C -#define SCSPTR 0xFFE80020 -#define SCLSR 0xFFE80024 - -#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ -#define SCI_IPR_ADDR INTC_IPRC -#define SCI_IPR_POS 1 -#endif +/* SCxSR SCIF */ +#define SCIF_ER 0x0080 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_TEND 0x0040 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_TDFE 0x0020 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_BRK 0x0010 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_FER 0x0008 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_PER 0x0004 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_RDF 0x0002 /* 7709 SCIF, 7750 SCIF */ +#define SCIF_DR 0x0001 /* 7709 SCIF, 7750 SCIF */ -#define SCI_ER 0x0080 -#define SCI_TEND 0x0040 -#define SCI_TD_E 0x0020 -#define SCI_BRK 0x0010 -#define SCI_FER 0x0008 -#define SCI_PER 0x0004 -#define SCI_RD_F 0x0002 -#define SCI_DR 0x0001 - -#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK) -#define SCI_TD_E_CLEAR 0x00df -#define SCI_TEND_CLEAR 0x00bf -#define SCI_RDRF_CLEAR 0x00fc -#define SCI_ERROR_CLEAR 0x0063 - -#define SCI_CTRL_FLAGS_TIE 0x80 -#define SCI_CTRL_FLAGS_RIE 0x40 -#define SCI_CTRL_FLAGS_TE 0x20 -#define SCI_CTRL_FLAGS_RE 0x10 -#define SCI_CTRL_FLAGS_REIE 0x08 -#define SCI_CTRL_FLAGS_CKE1 0x02 - -#if defined(__sh3__) -#define SCI_ERI_IRQ 56 -#define SCI_RXI_IRQ 57 -#define SCI_BRI_IRQ 58 -#define SCI_TXI_IRQ 59 -#define SCI_IRQ_END 60 -#elif defined(__SH4__) -#define SCI_ERI_IRQ 40 -#define SCI_RXI_IRQ 41 -#define SCI_BRI_IRQ 42 -#define SCI_TXI_IRQ 43 -#define SCI_IRQ_END 44 -#endif -#endif - -#if defined(__sh3__) -#define RFCR 0xffffff74 -#elif defined(__SH4__) -#define RFCR 0xFF800028 +#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) + +#if defined(SCI_ONLY) +# define SCxSR_TEND(port) SCI_TEND +# define SCxSR_ERRORS(port) SCI_ERRORS +# define SCxSR_RDxF(port) SCI_RDRF +# define SCxSR_TDxE(port) SCI_TDRE +# define SCxSR_RDxF_CLEAR(port) 0xbc +# define SCxSR_ERROR_CLEAR(port) 0xc4 +# define SCxSR_TDxE_CLEAR(port) 0x78 +#elif defined(SCIF_ONLY) +# define SCxSR_TEND(port) SCIF_TEND +# define SCxSR_ERRORS(port) SCIF_ERRORS +# define SCxSR_RDxF(port) SCIF_RDF +# define SCxSR_TDxE(port) SCIF_TDFE +# define SCxSR_RDxF_CLEAR(port) 0x00fc +# define SCxSR_ERROR_CLEAR(port) 0x0063 +# define SCxSR_TDxE_CLEAR(port) 0x00df +#else +# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) +# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) +# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) +# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063) +# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) #endif +/* SCFCR */ +#define SCFCR_RFRST 0x0002 +#define SCFCR_TFRST 0x0004 +#define SCFCR_MCE 0x0008 + #define SCI_PRIORITY 3 -#define SCI_MINOR_START 64 +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + +/* Generic serial flags */ #define SCI_RX_THROTTLE 0x0000001 +/* generic serial tty */ #define O_OTHER(tty) \ ((O_OLCUC(tty)) ||\ (O_ONLCR(tty)) ||\ @@ -173,10 +160,85 @@ struct sci_port { struct gs_port gs; + int type; + unsigned int base; + unsigned char irqs[3]; /* ERI, RXI, TXI */ + unsigned int intc_addr, intc_pos; + void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; }; -#define WAIT_RFCR_COUNTER 200 +#define SCI_IN(size, offset) \ + unsigned int addr = port->base + (offset); \ + if ((size) == 8) { \ + return ctrl_inb(addr); \ + } else { \ + return ctrl_inw(addr); \ + } +#define SCI_OUT(size, offset, value) \ + unsigned int addr = port->base + (offset); \ + if ((size) == 8) { \ + ctrl_outb(value, addr); \ + } else { \ + ctrl_outw(value, addr); \ + } + +#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ + static inline unsigned int sci_##name##_in(struct sci_port* port) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_IN(sci_size, sci_offset) \ + } else { \ + SCI_IN(scif_size, scif_offset); \ + } \ + } \ + static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ + { \ + if (port->type == PORT_SCI) { \ + SCI_OUT(sci_size, sci_offset, value) \ + } else { \ + SCI_OUT(scif_size, scif_offset, value); \ + } \ + } + +#define CPU_SCIF_FNS(name, scif_offset, scif_size) \ + static inline unsigned int sci_##name##_in(struct sci_port* port) \ + { \ + SCI_IN(scif_size, scif_offset); \ + } \ + static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \ + { \ + SCI_OUT(scif_size, scif_offset, value); \ + } + +#ifdef __sh3__ +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size) +#else +#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \ + sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size) +#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ + CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) +#endif + +/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 */ +/* name off sz off sz off sz off sz */ +SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16) +SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8) +SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16) +SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8) +SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16) +SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8) +SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) +SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) + +#define sci_in(port, reg) sci_##reg##_in(port) +#define sci_out(port, reg, value) sci_##reg##_out(port, value) + /* * Values for the BitRate Register (SCBRR) @@ -191,22 +253,17 @@ struct sci_port { * the SCSMR register would also need to be set to non-zero values. * * -- Greg Banks 27Feb2000 + * + * Answer: The SCBRR register is only eight bits, and the value in + * it gets larger with lower baud rates. At around 2400 (depending on + * the peripherial module clock) you run out of bits. However the + * lower two bits of SCSMR allow the module clock to be divided down, + * scaling the value which is needed in SCBRR. + * + * -- Stuart Menefy - 23 May 2000 */ -/* - * XXX: Well, this is not relevant... - * Should we have config option for peripheral clock? - * Or we get the value from time.c. - */ -#if defined(__sh3__) -#if defined(CONFIG_CPU_SUBTYPE_SH7709) -#define PCLK 33333333 -#else -#define PCLK 14745600 /* Isn't it 15MHz? */ -#endif -#elif defined(__SH4__) -#define PCLK 33333333 -#endif +#define PCLK (current_cpu_data.module_clock) #define SCBRR_VALUE(bps) (PCLK/(32*bps)-1) #define BPS_2400 SCBRR_VALUE(2400) @@ -215,3 +272,107 @@ struct sci_port { #define BPS_19200 SCBRR_VALUE(19200) #define BPS_38400 SCBRR_VALUE(38400) #define BPS_115200 SCBRR_VALUE(115200) + +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB +/* Taken from sh-stub.c of GDB 4.18 */ +static const char hexchars[] = "0123456789abcdef"; + +static __inline__ char highhex(int x) +{ + return hexchars[(x >> 4) & 0xf]; +} + +static __inline__ char lowhex(int x) +{ + return hexchars[x & 0xf]; +} +#endif + +static __inline__ void put_char(struct sci_port *port, char c) +{ + unsigned long flags; + unsigned short status; + + save_and_cli(flags); + + do + status = sci_in(port, SCxSR); + while (!(status & SCxSR_TDxE(port))); + + sci_out(port, SCxTDR, c); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + + restore_flags(flags); +} + +static __inline__ void handle_error(struct sci_port *port) +{ /* Clear error flags */ + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); +} + +static __inline__ int get_char(struct sci_port *port) +{ + unsigned long flags; + unsigned short status; + int c; + + save_and_cli(flags); + do { + status = sci_in(port, SCxSR); + if (status & SCxSR_ERRORS(port)) { + handle_error(port); + continue; + } + } while (!(status & SCxSR_RDxF(port))); + c = sci_in(port, SCxRDR); + sci_in(port, SCxSR); /* Dummy read */ + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + restore_flags(flags); + + return c; +} + +/* + * Send the packet in buffer. The host get's one chance to read it. + * This routine does not wait for a positive acknowledge. + */ + +static __inline__ void put_string(struct sci_port *port, + const char *buffer, int count) +{ + int i; + const unsigned char *p = buffer; +#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB + int checksum; + +if (IN_GDB) { + /* $<packet info>#<checksum>. */ + do { + unsigned char c; + put_char(port, '$'); + put_char(port, 'O'); /* 'O'utput to console */ + checksum = 'O'; + + for (i=0; i<count; i++) { /* Don't use run length encoding */ + int h, l; + + c = *p++; + h = highhex(c); + l = lowhex(c); + put_char(port, h); + put_char(port, l); + checksum += h + l; + } + put_char(port, '#'); + put_char(port, highhex(checksum)); + put_char(port, lowhex(checksum)); + } while (get_char(port) != '+'); +} else +#endif + for (i=0; i<count; i++) { + if (*p == 10) + put_char(port, '\r'); + put_char(port, *p++); + } +} diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 1898849d8..fdaeeaea0 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -511,8 +511,6 @@ static void stl_breakctl(struct tty_struct *tty, int state); static void stl_waituntilsent(struct tty_struct *tty, int timeout); static void stl_sendxchar(struct tty_struct *tty, char ch); static void stl_hangup(struct tty_struct *tty); -static int stl_memopen(struct inode *ip, struct file *fp); -static int stl_memclose(struct inode *ip, struct file *fp); static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int stl_portinfo(stlport_t *portp, int portnr, char *pos); static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -744,9 +742,8 @@ static unsigned int sc26198_baudtable[] = { * to get at port stats - only not using the port device itself. */ static struct file_operations stl_fsiomem = { + owner: THIS_MODULE, ioctl: stl_memioctl, - open: stl_memopen, - release: stl_memclose, }; /*****************************************************************************/ @@ -2795,8 +2792,8 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) */ #if DEBUG printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__, - devp->resource[0].start, devp->resource[1].start, - devp->resource[2].start, devp->resource[3].start, devp->irq); + pci_resource_start(devp, 0), pci_resource_start(devp, 1), + pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq); #endif /* @@ -2805,22 +2802,16 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp) */ switch (brdtype) { case BRD_ECHPCI: - brdp->ioaddr2 = (devp->resource[0].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = pci_resource_start(devp, 0); + brdp->ioaddr1 = pci_resource_start(devp, 1); break; case BRD_ECH64PCI: - brdp->ioaddr2 = (devp->resource[2].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr1 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr2 = pci_resource_start(devp, 2); + brdp->ioaddr1 = pci_resource_start(devp, 1); break; case BRD_EASYIOPCI: - brdp->ioaddr1 = (devp->resource[2].start & - PCI_BASE_ADDRESS_IO_MASK); - brdp->ioaddr2 = (devp->resource[1].start & - PCI_BASE_ADDRESS_IO_MASK); + brdp->ioaddr1 = pci_resource_start(devp, 2); + brdp->ioaddr2 = pci_resource_start(devp, 1); break; default: printk("STALLION: unknown PCI board type=%d\n", brdtype); @@ -3123,27 +3114,6 @@ static int stl_getbrdstruct(unsigned long arg) /*****************************************************************************/ /* - * Memory device open code. Need to keep track of opens and close - * for module handling. - */ - -static int stl_memopen(struct inode *ip, struct file *fp) -{ - MOD_INC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -static int stl_memclose(struct inode *ip, struct file *fp) -{ - MOD_DEC_USE_COUNT; - return(0); -} - -/*****************************************************************************/ - -/* * The "staliomem" device is also required to do some special operations * on the board and/or ports. In this driver it is mostly used for stats * collection. diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c index f157d4e52..949aa9532 100644 --- a/drivers/char/stradis.c +++ b/drivers/char/stradis.c @@ -2055,10 +2055,13 @@ static int configure_saa7146(struct pci_dev *dev, int num) saa->id = dev->device; saa->irq = dev->irq; saa->video_dev.minor = -1; - saa->saa7146_adr = dev->resource[0].start; + saa->saa7146_adr = pci_resource_start(dev, 0); pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision); - saa->saa7146_mem = ioremap(((saa->saa7146_adr) & - PCI_BASE_ADDRESS_MEM_MASK), 0x200); + + saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200); + if (!saa->saa7146_mem) + return -EIO; + memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus)); memcpy(&saa->video_dev, &saa_template, sizeof(saa_template)); sprintf(saa->i2c.name, "stradis%d", num); diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 15a24851f..82e3cae1e 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -304,8 +304,6 @@ static int sx_init_board (struct sx_board *board); static int sx_init_portstructs (int nboards, int nports); static int sx_fw_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -static int sx_fw_open(struct inode *inode, struct file *filp); -static INT sx_fw_release(struct inode *inode, struct file *filp); static int sx_init_drivers(void); @@ -419,9 +417,8 @@ static struct real_driver sx_real_driver = { */ static struct file_operations sx_fw_fops = { + owner: THIS_MODULE, ioctl: sx_fw_ioctl, - open: sx_fw_open, - release: sx_fw_release, }; struct miscdevice sx_fw_device = { @@ -1418,25 +1415,6 @@ static void sx_shutdown_port (void * ptr) * interface with the rest of the system * * ********************************************************************** */ - -static int sx_fw_open(struct inode *inode, struct file *filp) -{ - func_enter (); - MOD_INC_USE_COUNT; - func_exit (); - return 0; -} - - -static INT sx_fw_release(struct inode *inode, struct file *filp) -{ - func_enter (); - MOD_DEC_USE_COUNT; - func_exit (); - return NO_ERROR; -} - - static int sx_open (struct tty_struct * tty, struct file * filp) { struct sx_port *port; diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index d29c63407..133f19aac 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -2177,10 +2177,6 @@ static int qic02_tape_open(struct inode * inode, struct file * filp) int open_error; open_error = qic02_tape_open_no_use_count(inode, filp); - if (!open_error) - { - MOD_INC_USE_COUNT; - } return open_error; } @@ -2440,9 +2436,6 @@ static int qic02_tape_release(struct inode * inode, struct file * filp) (void) do_qic_cmd(QCMD_REWIND, TIM_R); } } -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return 0; } /* qic02_tape_release */ @@ -2766,6 +2759,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, /* These are (most) of the interface functions: */ static struct file_operations qic02_tape_fops = { + owner: THIS_MODULE, llseek: qic02_tape_lseek, /* not allowed */ read: qic02_tape_read, write: qic02_tape_write, diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 1516d985e..8a03fed26 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1430,49 +1430,6 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait) return 0; } -/* - * fasync_helper() is used by some character device drivers (mainly mice) - * to set up the fasync queue. It returns negative on error, 0 if it did - * no changes and positive if it added/deleted the entry. - */ -int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -{ - struct fasync_struct *fa, **fp; - unsigned long flags; - - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { - if (fa->fa_file == filp) - break; - } - - if (on) { - if (fa) { - fa->fa_fd = fd; - return 0; - } - fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); - if (!fa) - return -ENOMEM; - fa->magic = FASYNC_MAGIC; - fa->fa_file = filp; - fa->fa_fd = fd; - save_flags(flags); - cli(); - fa->fa_next = *fapp; - *fapp = fa; - restore_flags(flags); - return 1; - } - if (!fa) - return 0; - save_flags(flags); - cli(); - *fp = fa->fa_next; - restore_flags(flags); - kfree(fa); - return 1; -} - static int tty_fasync(int fd, struct file * filp, int on) { struct tty_struct * tty; diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c index 0ed55b715..81e19a4ab 100644 --- a/drivers/char/tuner.c +++ b/drivers/char/tuner.c @@ -10,6 +10,7 @@ #include <linux/i2c.h> #include <linux/types.h> #include <linux/videodev.h> +#include <linux/init.h> #include "tuner.h" #include "audiochip.h" @@ -428,22 +429,19 @@ static struct i2c_client client_template = EXPORT_NO_SYMBOLS; -#ifdef MODULE -int init_module(void) -#else -int i2c_tuner_init(void) -#endif +int tuner_init_module(void) { i2c_add_driver(&driver); return 0; } -#ifdef MODULE -void cleanup_module(void) +void tuner_cleanup_module(void) { i2c_del_driver(&driver); } -#endif + +module_init(tuner_init_module); +module_exit(tuner_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/char/tvmixer.c b/drivers/char/tvmixer.c new file mode 100644 index 000000000..0ef5bbd03 --- /dev/null +++ b/drivers/char/tvmixer.c @@ -0,0 +1,351 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/i2c.h> +#include <linux/videodev.h> +#include <asm/semaphore.h> +#include <linux/init.h> + +#include <linux/sound.h> +#include <linux/soundcard.h> +#include <asm/uaccess.h> + +#include "audiochip.h" + +#define DEV_MAX 4 + +static int debug = 0; +static int devnr = -1; + +MODULE_PARM(debug,"i"); +MODULE_PARM(devnr,"i"); + +/* ----------------------------------------------------------------------- */ + +struct TVMIXER { + struct i2c_client *dev; + int minor; + int count; +}; + +static struct TVMIXER devices[DEV_MAX]; + +static int tvmixer_adapters(struct i2c_adapter *adap); +static int tvmixer_clients(struct i2c_client *client); + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +static int tvmixer_open(struct inode *inode, struct file *file); +static int tvmixer_release(struct inode *inode, struct file *file); +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin); + + +static struct i2c_driver driver = { + "tv card mixer driver", + 42 /* I2C_DRIVERID_FIXME */, + I2C_DF_DUMMY, + tvmixer_adapters, + tvmixer_clients, +}; + +static struct file_operations tvmixer_fops = { + owner: THIS_MODULE, + llseek: tvmixer_llseek, + ioctl: tvmixer_ioctl, + open: tvmixer_open, + release: tvmixer_release, +}; + +/* ----------------------------------------------------------------------- */ + +static int mix_to_v4l(int i) +{ + int r; + + r = ((i & 0xff) * 65536 + 50) / 100; + if (r > 65535) r = 65535; + if (r < 0) r = 0; + return r; +} + +static int v4l_to_mix(int i) +{ + int r; + + r = (i * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + return r | (r << 8); +} + +static int v4l_to_mix2(int l, int r) +{ + r = (r * 100 + 32768) / 65536; + if (r > 100) r = 100; + if (r < 0) r = 0; + l = (l * 100 + 32768) / 65536; + if (l > 100) l = 100; + if (l < 0) l = 0; + return (r << 8) | l; +} + +static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct video_audio va; + int left,right,ret,val = 0; + struct TVMIXER *mix = file->private_data; + struct i2c_client *client = mix->dev; + + if (NULL == client) + return -ENODEV; + + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + info.modify_counter = 42 /* FIXME */; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "tv card", sizeof(info.id)); + strncpy(info.name, client->name, sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + if (get_user(val, (int *)arg)) + return -EFAULT; + + /* read state */ + memset(&va,0,sizeof(va)); + client->driver->command(client,VIDIOCGAUDIO,&va); + + switch (cmd) { + case MIXER_READ(SOUND_MIXER_RECMASK): + case MIXER_READ(SOUND_MIXER_CAPS): + case MIXER_READ(SOUND_MIXER_RECSRC): + case MIXER_WRITE(SOUND_MIXER_RECSRC): + ret = 0; + break; + + case MIXER_READ(SOUND_MIXER_STEREODEVS): + ret = SOUND_MASK_VOLUME; + break; + case MIXER_READ(SOUND_MIXER_DEVMASK): + ret = SOUND_MASK_VOLUME; + if (va.flags & VIDEO_AUDIO_BASS) + ret |= SOUND_MASK_BASS; + if (va.flags & VIDEO_AUDIO_TREBLE) + ret |= SOUND_MASK_TREBLE; + break; + + case MIXER_WRITE(SOUND_MIXER_VOLUME): + left = mix_to_v4l(val); + right = mix_to_v4l(val >> 8); + va.volume = MAX(left,right); + va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1); + va.balance = (left<right) ? (65535-va.balance) : va.balance; + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_VOLUME): + left = (MIN(65536 - va.balance,32768) * + va.volume) / 32768; + right = (MIN(va.balance,32768) * + va.volume) / 32768; + ret = v4l_to_mix2(left,right); + break; + + case MIXER_WRITE(SOUND_MIXER_BASS): + va.bass = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_BASS): + ret = v4l_to_mix(va.bass); + break; + + case MIXER_WRITE(SOUND_MIXER_TREBLE): + va.treble = mix_to_v4l(val); + client->driver->command(client,VIDIOCSAUDIO,&va); + client->driver->command(client,VIDIOCGAUDIO,&va); + /* fall throuth */ + case MIXER_READ(SOUND_MIXER_TREBLE): + ret = v4l_to_mix(va.treble); + break; + + default: + return -EINVAL; + } + if (put_user(ret, (int *)arg)) + return -EFAULT; + return 0; +} + +static int tvmixer_open(struct inode *inode, struct file *file) +{ + int i, minor = MINOR(inode->i_rdev); + struct TVMIXER *mix = NULL; + struct i2c_client *client = NULL; + + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor == minor) { + mix = devices+i; + client = mix->dev; + break; + } + } + + if (NULL == client) + return -ENODEV; + + /* lock bttv in memory while the mixer is in use */ + file->private_data = mix; + if (client->adapter->inc_use) + client->adapter->inc_use(client->adapter); + return 0; +} + +static int tvmixer_release(struct inode *inode, struct file *file) +{ + struct TVMIXER *mix = file->private_data; + struct i2c_client *client = mix->dev; + + if (NULL == client) + return -ENODEV; + + if (client->adapter->dec_use) + client->adapter->dec_use(client->adapter); + return 0; +} + +static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +/* ----------------------------------------------------------------------- */ + +static int tvmixer_adapters(struct i2c_adapter *adap) +{ + return 0; +} + +static int tvmixer_clients(struct i2c_client *client) +{ + struct video_audio va; + int i,minor; + + /* TV card ??? */ + if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) { + if (debug) + printk("tvmixer: %s is not a tv card\n", + client->adapter->name); + return -1; + } + printk("tvmixer: debug: %s\n",client->name); + + /* unregister ?? */ + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].dev == client) { + /* unregister */ + unregister_sound_mixer(devices[i].minor); + devices[i].dev = NULL; + devices[i].minor = -1; + printk("tvmixer: %s unregistered (#1)\n",client->name); + return 0; + } + } + + /* look for a free slot */ + for (i = 0; i < DEV_MAX; i++) + if (NULL == devices[i].dev) + break; + if (i == DEV_MAX) { + printk(KERN_WARNING "tvmixer: DEV_MAX too small\n"); + return -1; + } + + /* audio chip with mixer ??? */ + if (NULL == client->driver->command) { + if (debug) + printk("tvmixer: %s: driver->command is NULL\n", + client->driver->name); + return -1; + } + memset(&va,0,sizeof(va)); + if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) { + if (debug) + printk("tvmixer: %s: VIDIOCGAUDIO failed\n", + client->name); + return -1; + } + if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) { + if (debug) + printk("tvmixer: %s: has no volume control\n", + client->name); + return -1; + } + + /* everything is fine, register */ + if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) { + printk(KERN_ERR "tvmixer: cannot allocate mixer device\n"); + return -1; + } + + devices[i].minor = minor; + devices[i].count = 0; + devices[i].dev = client; + printk("tvmixer: %s (%s) registered with minor %d\n", + client->name,client->adapter->name,minor); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int tvmixer_init_module(void) +{ + int i; + + for (i = 0; i < DEV_MAX; i++) + devices[i].minor = -1; + i2c_add_driver(&driver); + return 0; +} + +void tvmixer_cleanup_module(void) +{ + int i; + + i2c_del_driver(&driver); + for (i = 0; i < DEV_MAX; i++) { + if (devices[i].minor != -1) { + unregister_sound_mixer(devices[i].minor); + printk("tvmixer: %s unregistered (#2)\n", + devices[i].dev->name); + } + } +} + +module_init(tvmixer_init_module); +module_exit(tvmixer_cleanup_module); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index 98c9e9731..ababd833f 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -51,7 +51,6 @@ struct videodev_proc_data { char name[16]; struct video_device *vdev; struct proc_dir_entry *proc_entry; - struct video_capability vcap; }; static struct proc_dir_entry *video_dev_proc_entry = NULL; @@ -63,7 +62,7 @@ LIST_HEAD(videodev_proc_list); #ifdef CONFIG_VIDEO_BT848 -extern int i2c_tuner_init(struct video_init *); +extern int tuner_init_module(struct video_init *); #endif #ifdef CONFIG_VIDEO_BWQCAM extern int init_bw_qcams(struct video_init *); @@ -80,7 +79,7 @@ extern int init_zoran_cards(struct video_init *); static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 - {"i2c-tuner", i2c_tuner_init}, + {"i2c-tuner", tuner_init_module}, #endif #ifdef CONFIG_VIDEO_BWQCAM {"bw-qcam", init_bw_qcams}, @@ -287,14 +286,6 @@ static int videodev_proc_read(char *page, char **start, off_t off, PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER); out += sprintf (out, "\n"); out += sprintf (out, "hardware : 0x%x\n", vfd->hardware); -#if 0 - out += sprintf (out, "channels : %d\n", d->vcap.channels); - out += sprintf (out, "audios : %d\n", d->vcap.audios); - out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth); - out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight); - out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth); - out += sprintf (out, "minheight : %d\n", d->vcap.minheight); -#endif skip: len = out - page; @@ -360,8 +351,6 @@ static void videodev_proc_create_dev (struct video_device *vfd, char *name) d->vdev = vfd; strcpy (d->name, name); - /* How can I get capability information ? */ - list_add (&d->proc_list, &videodev_proc_list); } @@ -575,3 +564,4 @@ EXPORT_SYMBOL(video_unregister_device); MODULE_AUTHOR("Alan Cox"); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers"); + diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 831b51654..c63df1039 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -62,7 +62,7 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES]; */ unsigned char keyboard_type = KB_101; -#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); #endif @@ -472,7 +472,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ucval = keyboard_type; goto setchar; -#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) +#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__) /* * These cannot be implemented on any machine that implements * ioperm() in user level (such as Alpha PCs). @@ -592,6 +592,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDGETKEYCODE: case KDSETKEYCODE: + if(!capable(CAP_SYS_ADMIN)) + perm=0; return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm); case KDGKBENT: diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c index 0ce42945d..3ac86bf3a 100644 --- a/drivers/char/wdt.c +++ b/drivers/char/wdt.c @@ -337,7 +337,6 @@ static int wdt_open(struct inode *inode, struct file *file) case WATCHDOG_MINOR: if(wdt_is_open) return -EBUSY; - MOD_INC_USE_COUNT; /* * Activate */ @@ -353,7 +352,6 @@ static int wdt_open(struct inode *inode, struct file *file) outb_p(0, WDT_DC); /* Enable */ return 0; case TEMP_MINOR: - MOD_INC_USE_COUNT; return 0; default: return -ENODEV; @@ -382,7 +380,6 @@ static int wdt_release(struct inode *inode, struct file *file) #endif wdt_is_open=0; } - MOD_DEC_USE_COUNT; return 0; } @@ -416,6 +413,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations wdt_fops = { + owner: THIS_MODULE, llseek: wdt_llseek, read: wdt_read, write: wdt_write, diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c index 6e99a72ac..2bd09930a 100644 --- a/drivers/char/wdt_pci.c +++ b/drivers/char/wdt_pci.c @@ -28,6 +28,7 @@ * Parameterized timeout * JP Nollmann : Added support for PCI wdt501p * Alan Cox : Split ISA and PCI cards into two drivers + * Jeff Garzik : PCI cleanups */ #include <linux/config.h> @@ -53,6 +54,8 @@ #include <linux/pci.h> +#define PFX "wdt_pci: " + /* * Until Access I/O gets their application for a PCI vendor ID approved, * I don't think that it's appropriate to move these constants into the @@ -487,12 +490,86 @@ static struct notifier_block wdtpci_notifier= 0 }; -#ifdef MODULE -#define wdtpci_init init_module +static int __init wdtpci_init_one (struct pci_dev *dev, + const struct pci_device_id *ent) +{ + static int dev_count = 0; + + dev_count++; + if (dev_count > 1) { + printk (KERN_ERR PFX + "this driver only supports 1 device\n"); + return -ENODEV; + } + + irq = dev->irq; + io = pci_resource_start (dev, 2); + printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " + "(Interrupt %d)\n", io, irq); + + if (pci_enable_device (dev)) + goto err_out; + + if (request_region (io, 16, "wdt-pci") == NULL) { + printk (KERN_ERR PFX "I/O %d is not free.\n", io); + goto err_out; + } + + if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, + "wdt-pci", &wdtpci_miscdev)) { + printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); + goto err_out_free_res; + } + + misc_register (&wdtpci_miscdev); + +#ifdef CONFIG_WDT_501 + misc_register (&temp_miscdev); +#endif + + register_reboot_notifier (&wdtpci_notifier); + + return 0; + +err_out_free_res: + release_region (io, 16); +err_out: + return -EIO; +} + + +static void __exit wdtpci_remove_one (struct pci_dev *pdev) +{ + /* here we assume only one device will ever have + * been picked up and registered by probe function */ + unregister_reboot_notifier(&wdtpci_notifier); +#ifdef CONFIG_WDT_501_PCI + misc_deregister(&temp_miscdev); +#endif + misc_deregister(&wdtpci_miscdev); + free_irq(irq, &wdtpci_miscdev); + release_region(io, 16); +} + + +static struct pci_device_id wdtpci_pci_tbl[] __initdata = { + { PCI_VENDOR_ID_ACCESSIO, PCI_DEVICE_ID_WDG_CSM, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl); + + +static struct pci_driver wdtpci_driver = { + name: "wdt-pci", + id_table: wdtpci_pci_tbl, + probe: wdtpci_init_one, + remove: wdtpci_remove_one, +}; + /** - * cleanup_module: + * wdtpci_cleanup: * * Unload the watchdog. You cannot do this with any file handles open. * If your watchdog is set to continue ticking on close and you unload @@ -501,18 +578,11 @@ static struct notifier_block wdtpci_notifier= * module in 60 seconds or reboot. */ -void cleanup_module(void) +static void __exit wdtpci_cleanup(void) { - misc_deregister(&wdtpci_miscdev); -#ifdef CONFIG_WDT_501_PCI - misc_deregister(&temp_miscdev); -#endif - unregister_reboot_notifier(&wdtpci_notifier); - release_region(io,16); - free_irq(irq, &wdtpci_miscdev); + pci_unregister_driver (&wdtpci_driver); } -#endif /** * wdtpci_init: @@ -522,37 +592,16 @@ void cleanup_module(void) * The open() function will actually kick the board off. */ -int __init wdtpci_init(void) +static int __init wdtpci_init(void) { - struct pci_dev *dev = NULL; - - if (pci_present()) - { - while ((dev = pci_find_device(PCI_VENDOR_ID_ACCESSIO, - PCI_DEVICE_ID_WDG_CSM, dev))) { - /* See if we can do this device */ - irq = dev->irq; - io = dev->resource[2].start; - printk("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X " - "(Interrupt %d)\n", io, irq); - } - } - if(request_region(io, 16, "wdt-pci")==NULL) - { - printk(KERN_ERR "I/O %d is not free.\n", io); - return -EIO; - } - if(request_irq(irq, wdtpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "wdt-pci", &wdtpci_miscdev)) - { - printk(KERN_ERR "IRQ %d is not free.\n", irq); - release_region(io, 16); - return -EIO; - } - misc_register(&wdtpci_miscdev); -#ifdef CONFIG_WDT_501 - misc_register(&temp_miscdev); -#endif - register_reboot_notifier(&wdtpci_notifier); + int rc = pci_register_driver (&wdtpci_driver); + + if (rc < 1) + return -ENODEV; + return 0; } + +module_init(wdtpci_init); +module_exit(wdtpci_cleanup); |