to your /etc/modules.conf file.
+Intel IA32 microcode
+====================
+
+A driver has been added to allow updating of Intel IA32 microcode,
+accessible as both a devfs regular file and as a normal (misc)
+character device. If you are not using devfs you may need to:
+
+mkdir /dev/cpu
+mknod /dev/cpu/microcode c 10 184
+chmod 0644 /dev/cpu/microcode
+
+as root before you can use this. You'll probably also want to
+get the user-space microcode_ctl utility to use with this.
+
+If you have compiled the driver as a module you may need to add
+the following line:
+
+alias char-major-10-184 microcode
+
+to your /etc/modules.conf file.
+
+
Where to get the files
**********************
If you want to compile this as a module, say M and read
Documentation/modules.txt. The module will be called comx-hw-mixcom.o.
+i810 TCO support
+CONFIG_I810_TCO
+ Hardware driver for the TCO timer built into the Intel i810 and i815
+ chipset family. The TCO (Total Cost of Ownership) timer is a watchdog
+ timer that will reboot the machine after it's second expiration. The
+ expiration time can be configured by commandline argument
+ "i810_margin=<n>" where <n> is the counter initial value. It is
+ decremented every 0.6 secs, the default is 50 which gives a timeout
+ of 30 seconds and one minute until reset.
+
+ On some motherboards the driver may fail to reset the chipset's
+ NO_REBOOT flag which prevents the watchdog from rebooting the machine.
+ If this is the case you will get a kernel message like
+ "i810tco init: failed to reset NO_REBOOT flag".
+
+ If you want to compile this as a module, say M and read
+ Documentation/modules.txt. The module will be called
+ i810-tco.o.
+
MultiGate Cisco-HDLC and synchronous PPP protocol support
CONFIG_COMX_PROTO_PPP
Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards.
ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
support is only useful for multi user systems. If unsure, say N.
-Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
-CONFIG_ADFS_FS
- The Advanced Disk File System is the filesystem used on floppy and
- hard disks by Acorn Systems. Currently in development, as a read-
- only driver for hard disks. These should be the first partition
- (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N.
-
Support for USB
CONFIG_USB
Universal Serial Bus (USB) is a specification for a serial bus
The module will be called digi_acceleport.o. If you want to compile
it as a module, say M here and read Documentation/modules.txt.
+USB Empeg empeg-car Mark I/II Driver
+CONFIG_USB_SERIAL_EMPEG
+ Say Y here if you want to connect to your Empeg empeg-car Mark I/II
+ mp3 player via USB.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called empeg.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
USB Serial Converter verbose debug
CONFIG_USB_SERIAL_DEBUG
Say Y here if you want verbose debug messages from the USB Serial
If you have more than 3 printers, you need to increase the LP_NO
variable in lp.c.
+Amiga built-in parallel port support
+CONFIG_PARPORT_AMIGA
+ Say Y here if you need support for the parallel port hardware on
+ Amiga machines. This code is also available as a module (say M),
+ called parport_amiga.o. If in doubt, saying N is the safe plan.
+
+Atari built-in parallel port support
+CONFIG_PARPORT_ATARI
+ Say Y here if you need support for the parallel port hardware on
+ Atari machines. This code is also available as a module (say M),
+ called parport_atari.o. If in doubt, saying N is the safe plan.
+
+Multiface 3 parallel port card support
+CONFIG_PARPORT_MFC3
+ Say Y here if you need parallel port support for the MFC3 card.
+ This code is also available as a module (say M), called
+ parport_mfc3.o. If in doubt, saying N is the safe plan.
+
Support IEEE1284 status readback
CONFIG_PRINTER_READBACK
If your printer conforms to IEEE 1284, it may be able to provide a
to it. For more information on how to use the driver please read
Documentation/joystick.txt
-Atomwide Serial Support
-CONFIG_ATOMWIDE_SERIAL
- If you have an Atomwide Serial card for an Acorn system, say Y to
- this option. The driver can handle 1, 2, or 3 port cards.
- If unsure, say N
-
-The Serial Port Dual Serial Port
-CONFIG_DUALSP_SERIAL
- If you have the Serial Port's dual serial card for an Acorn system,
- say Y to this option. If unsure, say N
-
NetWinder Button
CONFIG_NWBUTTON
If you enable this driver and create a character device node
CONFIG_RADIO_ZOLTRIX_PORT
Enter the I/O port of your Zoltrix radio card.
-ADS Cadet AM/FM Tuner
-CONFIG_RADIO_CADET
- Say Y here if this is your AM/FM radio card.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
- this API and pointers to "v4l" programs may be found on the WWW at
- http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
- you need to have access to a machine on the Internet that has a
- program like lynx or netscape.
-
- If you want to compile this driver as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read Documentation/modules.txt. The module will be
- called radio-cadet.o
-
Miro PCM20 Radio
CONFIG_RADIO_MIROPCM20
Choose Y here if you have this FM radio card. You also need to say Y
+++ /dev/null
-Sun May 21 15:14:37 2000 Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
- * ymf_sb.c: Add 'master_vol' module parameter to change
- 'PCM out Vol" of AC'97.
- Should I support AC'97 mixer by implementing original mixer
- codes... ?
-
- * ymf_sb.c: remove native UART401 support. External MIDI port
- should be supported by sb_midi driver.
-
- *ymf_sb.c: add support for SPDIF OUT. Module parameter
- 'spdif_out' is now available.
-
-
-Tue May 16 19:29:29 2000 Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
- * ymf_sb.c (checkCodec): add a little delays for reset devices.
-
- * ymf_sb.c (readRegWord): fixed addressing bug.
+++ /dev/null
-Legacy audio driver for YMF7xx PCI cards.
-
-
-FIRST OF ALL
-============
-
- This code references YAMAHA's sample codes and data sheets.
- I respect and thank for all people they made open the informations
- about YMF7xx cards.
-
- And this codes heavily based on Jeff Garzik <jgarzik@pobox.com>'s
- old VIA 82Cxxx driver (via82cxxx.c). I also respect him.
-
-
-DISCLIMER
-=========
-
- This driver is currently at early ALPHA stage. It may cause serious
- damage to your computer when used.
- PLEASE USE IT AT YOUR OWN RISK.
-
-
-ABOUT THIS DRIVER
-=================
-
- This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754
- cards as "SoundBlaster Pro" compatible card. It can only play 22.05kHz /
- 8bit / Stereo samples, control external MIDI port.
- And it can handle AC'97 mixer of these cards.
-
- If you want to use your card as recent "16-bit" card, you should use
- Alsa or OSS/Linux driver. Ofcource you can write native PCI driver for
- your cards :)
-
-
-INSTALL
-=======
-
- First, it requires some sound driver modules in Linux kernel
- (soundcore.o , sound.o, sb.o and uart401.o), so you should enable
- these modules at kernel configuration (please refer some other
- documentations for configuration of kernel).
- And add the following line in /etc/modules.conf:
-
- options sb support=1
-
- (NOTE: There are no need any configuration of sb modules)
-
- To compile ymfsb module, type 'make'.
- And copy it to /lib/modules/(kernel_version)/misc, type 'depmod -a'.
-
- This module also requires /usr/src/linux/drivers/sound/ac97.[ch].
- If your kernel doesn't have these files, you should upgrade your kernel.
-
-
-USAGE
-=====
-
- # modprobe ymfsb (options)
-
-
-OPTIONS FOR YMFSB
-=================
-
- io : SB base address (0x220, 0x240, 0x260, 0x280)
- synth_io : OPL3 base address (0x388, 0x398, 0x3a0, 0x3a8)
- dma : DMA number (0,1,3)
- spdif_out : SPDIF-out flag (0:disable 1:enable)
-
- These options will change in future...
-
-
-FREQUENCY
-=========
-
- When playing sounds via this driver, you will hear its pitch is slightly
- lower than original sounds. Since this driver recognizes your card acts
- with 21.739kHz sample rates rather than 22.050kHz (I think it must be
- hardware restriction). So many players become tone deafness.
- To prevent this, you should express some options to your sound player
- that specify correct sample frequency. For example, to play your MP3 file
- correctly with mpg123, specify the frequency like following:
-
- % mpg123 -r 21739 foo.mp3
-
-
-SPDIF OUT
-=========
-
- With installing modules with option 'spdif_out=1', you can enjoy your
- sounds from SPDIF-out of your card (if it had).
- Its Fs is fixed to 48kHz (It never means the sample frequency become
- up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your
- digital-in capable components has to be able to handle 48kHz Fs.
-
-
-COPYING
-=======
-
- 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, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-TODO
-====
- * support for multiple cards
- (set the different SB_IO,MPU_IO,OPL_IO for each cards)
-
- * support for OPL (dmfm) : There will be no requirements... :-<
-
-
-AUTHOR
-======
-
- Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
-- Add everything else that is missing :)
+Empeg empeg-car Mark I/II Driver (empeg.c)
+
+ This is an experimental driver to provide connectivity support for the
+ client synchronization tools for an Empeg empeg-car mp3 player.
+
+ The driver is still pretty new, so some testing 'in the wild' would be
+ helpful. :)
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 19
-EXTRAVERSION = pre2
+EXTRAVERSION = pre3
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
LD =$(CROSS_COMPILE)ld
#
# foo-bar-gcc for cross builds
-# gcc272 for Debian's old compiler for kernels
-# kgcc for Conectiva and Red Hat 7
+# kgcc for Conectiva, Red Hat, Mandrake
+# gcc272 for Debian
# otherwise 'cc'
#
-CC =$(shell if [ -n "$(CROSS_COMPILE)" ]; then echo $(CROSS_COMPILE)gcc; else \
- $(CONFIG_SHELL) scripts/kwhich gcc272 2>/dev/null || $(CONFIG_SHELL) scripts/kwhich kgcc 2>/dev/null || echo cc; fi) \
+CCFOUND :=$(shell $(CONFIG_SHELL) scripts/kwhich kgcc gcc272 cc gcc)
+## Faster, but requires GNU make 3.78, which postdates Linux 2.2.0
+##CC =$(if $(CROSS_COMPILE),$(CROSS_COMPILE)gcc,$(CCFOUND)) -D__KERNEL__ -I$(HPATH)
+CC =$(shell if [ -n "$(CROSS_COMPILE)" ]; then echo $(CROSS_COMPILE)gcc; else echo $(CCFOUND); fi) \
-D__KERNEL__ -I$(HPATH)
CPP =$(CC) -E
AR =$(CROSS_COMPILE)ar
static void cpuid_exit(void)
{
+ unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
}
module_init(cpuid_init);
pushl %ebx
cld
movl %es,%cx
- xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
+ movl ORIG_EAX(%esp), %esi # get the error code
+ movl ES(%esp), %edi # get the function address
+ movl %eax, ORIG_EAX(%esp)
+ movl %ecx, ES(%esp)
movl %esp,%edx
- xchgl %ecx, ES(%esp) # get the address and save es.
- pushl %eax # push the error code
- pushl %edx
+ pushl %esi # push the error code
+ pushl %edx # push the pt_regs pointer
movl $(__KERNEL_DS),%edx
movl %dx,%ds
movl %dx,%es
GET_CURRENT(%ebx)
- call *%ecx
+ call *%edi
addl $8,%esp
jmp ret_from_exception
pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
-ENTRY(reserved)
- pushl $0
- pushl $ SYMBOL_NAME(do_reserved)
- jmp error_code
-
ENTRY(double_fault)
pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
* Messages for error cases (non intel & no suitable microcode).
* 1.06 07 Dec 2000, Tigran Aivazian <tigran@veritas.com>
* Pentium 4 support + backported fixes from 2.4
+ * 1.07 13 Dec 2000, Tigran Aivazian <tigran@veritas.com>
+ * More bugfixes backported from 2.4
*/
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
-#define MICROCODE_VERSION "1.06"
+#define MICROCODE_VERSION "1.07"
MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
int __init microcode_init(void)
{
- int error = 0;
-
if (misc_register(µcode_dev) < 0) {
- printk(KERN_WARNING
- "microcode: can't misc_register on minor=%d\n",
+ printk(KERN_ERR "microcode: can't misc_register on minor=%d\n",
MICROCODE_MINOR);
- error = 1;
+ return -EINVAL;
}
printk(KERN_INFO "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n",
MICROCODE_VERSION);
static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
{
- if (*ppos >= mc_fsize)
- return 0;
+ ssize_t err = 0;
+
down(µcode_sem);
+ if (*ppos >= mc_fsize)
+ goto out;
if (*ppos + len > mc_fsize)
len = mc_fsize - *ppos;
- if (copy_to_user(buf, mc_applied + *ppos, len)) {
- up(µcode_sem);
- return -EFAULT;
- }
+ err = -EFAULT;
+ if (copy_to_user(buf, mc_applied + *ppos, len))
+ goto out;
*ppos += len;
+ err = len;
+out:
up(µcode_sem);
- return len;
+ return err;
}
static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
case MICROCODE_IOCFREE:
down(µcode_sem);
if (mc_applied) {
+ int bytes = smp_num_cpus * sizeof(struct microcode);
+
memset(mc_applied, 0, mc_fsize);
kfree(mc_applied);
mc_applied = NULL;
- printk(KERN_WARNING
- "microcode: freed %d bytes\n", mc_fsize);
+ printk(KERN_WARNING "microcode: freed %d bytes\n", bytes);
mc_fsize = 0;
up(µcode_sem);
return 0;
static void msr_exit(void)
{
+ unregister_chrdev(MSR_MAJOR, "cpu/msr");
}
module_init(msr_init);
unsigned short length;
unsigned char table[0];
};
-struct e820map e820;
+struct e820map e820 __initdata = { 0, };
unsigned char aux_device_present;
visws_board_rev);
}
#endif
-void __init add_memory_region(unsigned long long start,
- unsigned long long size, int type)
+
+static void __init add_memory_region(unsigned long long start,
+ unsigned long long size, int type)
{
int x = e820.nr_map;
e820.nr_map++;
} /* add_memory_region */
+unsigned long i386_endbase __initdata = 0;
+
static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
{
/* Only one memory region (or negative)? Ignore it */
* Not right. Fix it up.
*/
if (type == E820_RAM) {
- if (start < 0x100000ULL && end > 0xA0000ULL) {
- if (start < 0xA0000ULL)
- add_memory_region(start, 0xA0000ULL-start, type);
- if (end < 0x100000ULL)
+ if (start < 0x100000ULL && end > i386_endbase) {
+ if (start < i386_endbase)
+ add_memory_region(start, i386_endbase-start, type);
+ if (end <= 0x100000ULL)
continue;
start = 0x100000ULL;
size = end - start;
return 0;
}
-#define LOWMEMSIZE() (0x9f000)
+static void __init print_memory_map(char *who)
+{
+ int i;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ printk(" %s: %08lx @ %08lx ", who,
+ (unsigned long) e820.map[i].size,
+ (unsigned long) e820.map[i].addr);
+ switch (e820.map[i].type) {
+ case E820_RAM: printk("(usable)\n");
+ break;
+ case E820_RESERVED:
+ printk("(reserved)\n");
+ break;
+ case E820_ACPI:
+ printk("(ACPI data)\n");
+ break;
+ case E820_NVS:
+ printk("(ACPI NVS)\n");
+ break;
+ default: printk("type %lu\n", e820.map[i].type);
+ break;
+ }
+ }
+}
-void __init setup_memory_region(void)
+static void __init setup_memory_region(void)
{
char *who = "BIOS-e820";
}
e820.nr_map = 0;
- add_memory_region(0, LOWMEMSIZE(), E820_RAM);
- add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+ add_memory_region(0, i386_endbase, E820_RAM);
+ add_memory_region(HIGH_MEMORY, (mem_size << 10)-HIGH_MEMORY,
+ E820_RAM);
}
printk("BIOS-provided physical RAM map:\n");
+ print_memory_map(who);
} /* setup_memory_region */
static char command_line[COMMAND_LINE_SIZE] = { 0, };
char saved_command_line[COMMAND_LINE_SIZE];
-unsigned long i386_endbase __initdata = 0;
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
- unsigned long memory_start, memory_end;
- unsigned long max_pfn;
+ unsigned long memory_start, memory_end = 0;
char c = ' ', *to = command_line, *from = COMMAND_LINE;
int len = 0;
int read_endbase_from_BIOS = 1;
int i;
+ unsigned long user_mem = 0;
#ifdef CONFIG_VISWS
visws_get_board_type_and_rev();
memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
- setup_memory_region();
-
-#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
-#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
- max_pfn = 0;
- for (i = 0; i < e820.nr_map; i++) {
- unsigned long start, end;
- /* RAM? */
- if (e820.map[i].type != E820_RAM)
- continue;
- start = PFN_UP(e820.map[i].addr);
- end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
- if (start >= end)
- continue;
- if (end > max_pfn)
- max_pfn = end;
- }
- memory_end = (max_pfn << PAGE_SHIFT);
-
-
for (;;) {
/*
* "mem=nopentium" disables the 4MB page tables.
from += 9+4;
boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
} else {
- memory_end = simple_strtoul(from+4, &from, 0);
+ user_mem = simple_strtoul(from+4, &from, 0);
if ( *from == 'K' || *from == 'k' ) {
- memory_end = memory_end << 10;
+ user_mem = user_mem << 10;
from++;
} else if ( *from == 'M' || *from == 'm' ) {
- memory_end = memory_end << 20;
+ user_mem = user_mem << 20;
from++;
}
}
{
if (to != command_line) to--;
i386_endbase = simple_strtoul(from+8, &from, 0);
- i386_endbase += PAGE_OFFSET;
read_endbase_from_BIOS = 0;
}
c = *(from++);
}
i386_endbase = BIOS_ENDBASE;
}
- i386_endbase += PAGE_OFFSET;
+ }
+
+ if (!user_mem)
+ setup_memory_region();
+ else {
+ e820.nr_map = 0;
+ add_memory_region(0, i386_endbase, E820_RAM);
+ add_memory_region(HIGH_MEMORY, user_mem-HIGH_MEMORY, E820_RAM);
+ printk("USER-provided physical RAM map:\n");
+ print_memory_map("USER");
+ }
+
+#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+ for (i = 0; i < e820.nr_map; i++) {
+ unsigned long long start, end;
+ /* RAM? */
+ if (e820.map[i].type != E820_RAM)
+ continue;
+ start = e820.map[i].addr;
+ if (start >= 0xffffffff)
+ continue;
+ end = e820.map[i].addr + e820.map[i].size;
+ if (start >= end)
+ continue;
+ if (end > 0xffffffff)
+ end = 0xffffffff;
+ if (end > memory_end)
+ memory_end = end;
}
#define VMALLOC_RESERVE (64 << 20) /* 64MB for vmalloc */
*/
unsigned long __init smp_alloc_memory(unsigned long mem_base)
{
- if (mem_base + PAGE_SIZE > i386_endbase)
+ if (mem_base + PAGE_SIZE > i386_endbase + PAGE_OFFSET)
panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base);
trampoline_base = (void *)mem_base;
return mem_base + PAGE_SIZE;
asmlinkage void general_protection(void);
asmlinkage void page_fault(void);
asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
/* I don't have documents for this but it does seem to cover the cache
flush from user space exception some people get. */
DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/fixmap.h>
+#include <asm/e820.h>
extern void show_net_buffers(void);
extern unsigned long init_smp_mappings(unsigned long);
printk(".\n");
}
-extern unsigned long i386_endbase;
-
__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
unsigned long start_low_mem = PAGE_SIZE;
#endif
start_mem = PAGE_ALIGN(start_mem);
- while (start_low_mem < i386_endbase) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
- start_low_mem += PAGE_SIZE;
- }
+ for (tmp = __pa(start_low_mem); tmp < __pa(end_mem);
+ tmp += PAGE_SIZE) {
+ struct page * page = mem_map + (tmp >> PAGE_SHIFT);
+ int i;
+ extern struct e820map e820;
- while (start_mem < end_mem) {
- clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
- start_mem += PAGE_SIZE;
+ /* don't include kernel memory and bootmem allocations */
+ if (tmp >= 0x100000 && tmp < __pa(start_mem))
+ continue;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ unsigned long long start, end;
+ /* RAM? */
+ if (e820.map[i].type != E820_RAM)
+ continue;
+ start = e820.map[i].addr;
+ if (start >= 0xffffffff)
+ continue;
+ end = e820.map[i].addr + e820.map[i].size;
+ if (start >= end)
+ continue;
+ if (end > 0xffffffff)
+ end = 0xffffffff;
+
+ /* start and end are valid here */
+ if (start <= tmp && tmp+PAGE_SIZE <= end)
+ clear_bit(PG_reserved, &page->flags);
+ }
}
+
for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
if (tmp >= MAX_DMA_ADDRESS)
clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr;
+ ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge;
+ ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base;
+ ppc_md.pci_dev_io_base = pmac_pci_dev_io_base;
+
#ifdef CONFIG_VT
#ifdef CONFIG_MAC_KEYBOARD
ppc_md.kbd_setkeycode = mackbd_setkeycode;
endmenu
source drivers/s390/Config.in
+
+mainmenu_option next_comment
comment 'Character devices'
bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
fi
+endmenu
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
EXPORT_SYMBOL(s390_device_register);
EXPORT_SYMBOL(s390_device_unregister);
+#ifdef __SMP__
EXPORT_SYMBOL(s390_bh_lock);
+#endif
EXPORT_SYMBOL(ccw_alloc_request);
EXPORT_SYMBOL(ccw_free_request);
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/smp.h>
+#include "cpcmd.h"
+
+extern void reipl(int ipl_device);
/*
* Machine setup..
-/* $Id: sys_sparc32.c,v 1.107.2.14 2000/10/10 04:50:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.16 2000/12/20 02:45:00 anton Exp $
* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
set_fs (KERNEL_DS);
sys_get_kernel_syms(tbl);
set_fs (old_fs);
- for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
+ for (i = 0; i < len; i++, table++) {
if (put_user (tbl[i].value, &table->value) ||
copy_to_user (table->name, tbl[i].name, 60))
break;
s32 gf32_version;
};
+struct nfsctl_fdparm32 {
+ struct sockaddr gd32_addr;
+ s8 gd32_path[NFS_MAXPATHLEN+1];
+ s32 gd32_version;
+};
+
struct nfsctl_arg32 {
s32 ca32_version; /* safeguard */
union {
struct nfsctl_export32 u32_export;
struct nfsctl_uidmap32 u32_umap;
struct nfsctl_fhparm32 u32_getfh;
+ struct nfsctl_fdparm32 u32_getfd;
u32 u32_debug;
} u;
#define ca32_svc u.u32_svc
#define ca32_umap u.u32_umap
#define ca32_getfh u.u32_getfh
#define ca32_authd u.u32_authd
+#define ca32_getfd u.u32_getfd
#define ca32_debug u.u32_debug
};
return err;
}
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+ int err;
+
+ err = __get_user(karg->ca_version, &arg32->ca32_version);
+ err |= copy_from_user(&karg->ca_getfd.gd_addr,
+ &arg32->ca32_getfd.gd32_addr,
+ (sizeof(struct sockaddr)));
+ err |= copy_from_user(&karg->ca_getfd.gd_path,
+ &arg32->ca32_getfd.gd32_path,
+ (NFS_MAXPATHLEN+1));
+ err |= __get_user(karg->ca_getfd.gd_version,
+ &arg32->ca32_getfd.gd32_version);
+ return err;
+}
+
static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
{
int err;
err = nfs_clnt32_trans(karg, arg32);
break;
case NFSCTL_EXPORT:
+ case NFSCTL_UNEXPORT:
err = nfs_exp32_trans(karg, arg32);
break;
/* This one is unimplemented, be we're ready for it. */
case NFSCTL_GETFH:
err = nfs_getfh32_trans(karg, arg32);
break;
+ case NFSCTL_GETFD:
+ err = nfs_getfd32_trans(karg, arg32);
+ break;
case NFSCTL_LOCKD:
/* We still have to copy over the version
* because nfsctl still checks that.
err = sys_nfsservctl(cmd, karg, kres);
set_fs(oldfs);
- if(!err && cmd == NFSCTL_GETFH)
+ if (err)
+ goto done;
+
+ if((cmd == NFSCTL_GETFH) ||
+ (cmd == NFSCTL_GETFD))
err = nfs_getfh32_res_trans(kres, res32);
done:
tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+ tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD
tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
endif
endif
+ifeq ($(CONFIG_I810_TCO),y)
+O_OBJS += i810-tco.o
+else
+ ifeq ($(CONFIG_I810_TCO),m)
+ M_OBJS += i810-tco.o
+ endif
+endif
+
# remove objects from modular that are also built in
obj-m := $(filter-out $(obj-y), $(obj-m))
--- /dev/null
+/*
+ * i810-tco 0.02: TCO timer driver for i810 chipsets
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ * http://www.kernelconcepts.de
+ *
+ * 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.
+ *
+ * Neither kernel concepts nor Nils Faerber admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
+ * developed for
+ * Jentro AG, Haar/Munich (Germany)
+ *
+ * TCO timer driver for i810/i815 chipsets
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ * The TCO timer is implemented in the 82801AA (82801AB) chip,
+ * see intel documentation from http://developer.intel.com,
+ * order number 290655-003
+ *
+ * 20000710 Nils Faerber
+ * Initial Version 0.01
+ * 20000728 Nils Faerber
+ * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include "i810-tco.h"
+
+
+/* Just in case that the PCI vendor and device IDs are not yet defined */
+#ifndef PCI_DEVICE_ID_INTEL_82801AA_0
+#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
+#endif
+
+/* Default expire timeout */
+#define TIMER_MARGIN 50 /* steps of 0.6sec, 2<n<64. Default is 30 seconds */
+
+static unsigned int ACPIBASE;
+static spinlock_t tco_lock; /* Guards the hardware */
+
+static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
+
+MODULE_PARM (i810_margin, "i");
+
+/*
+ * Timer active flag
+ */
+
+static int timer_alive;
+static int boot_status;
+
+/*
+ * Some i810 specific functions
+ */
+
+
+/*
+ * Start the timer countdown
+ */
+static int tco_timer_start (void)
+{
+ unsigned char val;
+
+ spin_lock(&tco_lock);
+ val = inb (TCO1_CNT + 1);
+ val &= 0xf7;
+ outb (val, TCO1_CNT + 1);
+ val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
+ if (val & 0x08)
+ return -1;
+ return 0;
+}
+
+/*
+ * Stop the timer countdown
+ */
+static int tco_timer_stop (void)
+{
+ unsigned char val;
+
+ spin_lock(&tco_lock);
+ val = inb (TCO1_CNT + 1);
+ val |= 0x08;
+ outb (val, TCO1_CNT + 1);
+ val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
+ if ((val & 0x08) == 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * Set the timer reload value
+ */
+static int tco_timer_settimer (unsigned char tmrval)
+{
+ unsigned char val;
+
+ /* from the specs: */
+ /* "Values of 0h-3h are ignored and should not be attempted" */
+ if (tmrval > 0x3f || tmrval < 0x03)
+ return -1;
+
+ spin_lock(&tco_lock);
+ val = inb (TCO1_TMR);
+ val &= 0xc0;
+ val |= tmrval;
+ outb (val, TCO1_TMR);
+ val = inb (TCO1_TMR);
+ spin_unlock(&tco_lock);
+
+ if ((val & 0x3f) != tmrval)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Reload (trigger) the timer. Lock is needed so we dont reload it during
+ * a reprogramming event
+ */
+
+static void tco_timer_reload (void)
+{
+ spin_lock(&tco_lock);
+ outb (0x01, TCO1_RLD);
+ spin_unlock(&tco_lock);
+}
+
+/*
+ * Read the current timer value
+ */
+static unsigned char tco_timer_read (void)
+{
+ return (inb (TCO1_RLD));
+}
+
+
+/*
+ * Allow only one person to hold it open
+ */
+
+static int i810tco_open (struct inode *inode, struct file *file)
+{
+ if (timer_alive)
+ return -EBUSY;
+
+ /*
+ * Reload and activate timer
+ */
+ tco_timer_reload ();
+ tco_timer_start ();
+ timer_alive = 1;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static int i810tco_release (struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ */
+ MOD_INC_USE_COUNT;
+ tco_timer_stop ();
+ timer_alive = 0;
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+static ssize_t i810tco_write (struct file *file, const char *data,
+ size_t len, loff_t * ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /*
+ * Refresh the timer.
+ */
+ if (len) {
+ tco_timer_reload ();
+ return 1;
+ }
+ return 0;
+}
+
+static int i810tco_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ static struct watchdog_info ident = {
+ 0,
+ 0,
+ "i810 TCO timer"
+ };
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user
+ ((struct watchdog_info *) arg, &ident, sizeof (ident)))
+ return -EFAULT;
+ return 0;
+ case WDIOC_GETSTATUS:
+ return put_user (tco_timer_read (),
+ (unsigned int *) (int) arg);
+ case WDIOC_GETBOOTSTATUS:
+ return put_user (boot_status, (int *) arg);
+ case WDIOC_KEEPALIVE:
+ tco_timer_reload ();
+ return 0;
+ }
+}
+
+static struct pci_dev *i810tco_pci;
+
+static unsigned char i810tco_getdevice (void)
+{
+ u8 val1, val2;
+ u16 badr;
+ /*
+ * Find the PCI device which has vendor id 0x8086
+ * and device ID 0x2410
+ */
+ i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82801AA_0, NULL);
+ if (i810tco_pci) {
+ /*
+ * Find the ACPI base I/O address which is the base
+ * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
+ * ACPIBASE is bits [15:7] from 0x40-0x43
+ */
+ pci_read_config_byte (i810tco_pci, 0x40, &val1);
+ pci_read_config_byte (i810tco_pci, 0x41, &val2);
+ badr = ((val2 << 1) | (val1 >> 7)) << 7;
+ ACPIBASE = badr;
+ /* Something's wrong here, ACPIBASE has to be set */
+ if (badr == 0x0001 || badr == 0x0000) {
+ printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n");
+ return 0;
+ }
+ /*
+ * Check chipset's NO_REBOOT bit
+ */
+ pci_read_config_byte (i810tco_pci, 0xd4, &val1);
+ if (val1 & 0x02) {
+ val1 &= 0xfd;
+ pci_write_config_byte (i810tco_pci, 0xd4, val1);
+ pci_read_config_byte (i810tco_pci, 0xd4, &val1);
+ if (val1 & 0x02) {
+ printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n");
+ return 0; /* Cannot reset NO_REBOOT bit */
+ }
+ }
+ /* Set the TCO_EN bit in SMI_EN register */
+ val1 = inb (SMI_EN + 1);
+ val1 &= 0xdf;
+ outb (val1, SMI_EN + 1);
+ /* Clear out the (probably old) status */
+ outb (0, TCO1_STS);
+ boot_status = (int) inb (TCO2_STS);
+ outb (3, TCO2_STS);
+ return 1;
+ }
+ return 0;
+}
+
+static struct file_operations i810tco_fops = {
+ write: i810tco_write,
+ ioctl: i810tco_ioctl,
+ open: i810tco_open,
+ release: i810tco_release,
+};
+
+static struct miscdevice i810tco_miscdev = {
+ WATCHDOG_MINOR,
+ "watchdog",
+ &i810tco_fops
+};
+
+static int __init watchdog_init (void)
+{
+ spin_lock_init(&tco_lock);
+ if (!i810tco_getdevice () || i810tco_pci == NULL)
+ return -ENODEV;
+ if (!check_region (TCOBASE, 0x10)) {
+ printk (KERN_ERR
+ "i810 TCO timer: I/O address 0x%04x already in use\n",
+ TCOBASE);
+ return -EIO;
+ }
+ request_region (TCOBASE, 0x10, "i810 TCO");
+ if (misc_register (&i810tco_miscdev) != 0) {
+ release_region (TCOBASE, 0x10);
+ printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n");
+ return -EIO;
+ }
+ tco_timer_settimer ((unsigned char) i810_margin);
+ tco_timer_reload ();
+
+ printk (KERN_INFO
+ "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
+ (int) (i810_margin * 6 / 10), TCOBASE);
+ return 0;
+}
+
+static void watchdog_cleanup (void)
+{
+ u8 val;
+
+ /* Reset the timer before we leave */
+ tco_timer_reload ();
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ pci_read_config_byte (i810tco_pci, 0xd4, &val);
+ val |= 0x02;
+ pci_write_config_byte (i810tco_pci, 0xd4, val);
+ release_region (TCOBASE, 0x10);
+ misc_deregister (&i810tco_miscdev);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
--- /dev/null
+/*
+ * i810-tco 0.02: TCO timer driver for i810 chipsets
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ * http://www.kernelconcepts.de
+ *
+ * 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.
+ *
+ * Neither kernel concepts nor Nils Faerber admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
+ * developed for
+ * Jentro AG, Haar/Munich (Germany)
+ *
+ * TCO timer driver for i810 chipsets
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ * The TCO timer is implemented in the 82801AA (82801AB) chip,
+ * see intel documentation from http://developer.intel.com,
+ * order number 290655-003
+ *
+ * For history see i810-tco.c
+ */
+
+
+/*
+ * Some address definitions for the i810 TCO
+ */
+
+#define TCOBASE ACPIBASE + 0x60 /* TCO base address */
+#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
+#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */
+#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
+#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
+#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
+#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
+#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
+#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
+
+#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
- * ==FILEDATE 20000515==
+ * $Id: n_hdlc.c,v 2.2 2000/11/08 17:08:29 paul Exp $
*
* This code is released under the GNU General Public License (GPL)
*
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.15"
+#define HDLC_VERSION "2.2"
#include <linux/version.h>
#include <linux/config.h>
#undef VERSION
#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-#if LINUX_VERSION_CODE < VERSION(2,1,14)
-#include <linux/ioport.h>
-#endif
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,23)
#include <linux/poll.h>
-#endif
-
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/tty.h>
#include <linux/kerneld.h>
#endif
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
+#if LINUX_VERSION_CODE < VERSION(2,2,18)
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define set_current_state(a) current->state = (a)
+#endif
+
#include <asm/segment.h>
#define GET_USER(error,value,addr) error = get_user(value,addr)
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
#define PUT_USER(error,value,addr) error = put_user(value,addr)
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
#include <asm/uaccess.h>
-#endif
-
-#else /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
- if (error == 0) \
- value = get_user(addr); \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_READ, (void *) src, size); \
- if (error == 0) \
- memcpy_fromfs (dest, src, size); \
-} while (0)
-
-#define PUT_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
- if (error == 0) \
- put_user (value, addr); \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) dest, size); \
- if (error == 0) \
- memcpy_tofs (dest, src, size); \
-} while (0)
-
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-#define __init
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,37)
-#define test_and_set_bit(nr, addr) set_bit(nr, addr)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,57)
-#define signal_pending(p) ((p)->signal & ~(p)->blocked)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,25)
-#define net_device_stats enet_statistics
-#endif
-#if LINUX_VERSION_CODE < VERSION(2,1,60)
-typedef int rw_ret_t;
-typedef unsigned int rw_count_t;
-#else
typedef ssize_t rw_ret_t;
typedef size_t rw_count_t;
-#endif
/*
* Buffers for individual HDLC frames
static struct n_hdlc *n_hdlc_alloc (void);
-#if LINUX_VERSION_CODE >= VERSION(2,1,19)
MODULE_PARM(debuglevel, "i");
MODULE_PARM(maxframe, "i");
-#endif
/* debug level can be set by insmod for debugging purposes */
#define DEBUG_LEVEL_INFO 1
struct file *, const __u8 *, rw_count_t);
static int n_hdlc_tty_ioctl(struct tty_struct *,
struct file *, unsigned int, unsigned long);
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
- struct file *filp, int sel_type, select_table * wait);
-#else
static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp,
poll_table * wait);
-#endif
static int n_hdlc_tty_open (struct tty_struct *);
static void n_hdlc_tty_close (struct tty_struct *);
static int n_hdlc_tty_room (struct tty_struct *tty);
wake_up_interruptible (&n_hdlc->read_wait);
wake_up_interruptible (&n_hdlc->poll_wait);
if (n_hdlc->tty->fasync != NULL)
-#if LINUX_VERSION_CODE < VERSION(2,3,0)
- kill_fasync (n_hdlc->tty->fasync, SIGIO);
-#else
+#if LINUX_VERSION_CODE >= VERSION(2,2,14) && defined(__rh_config_h__)
kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN);
+#else
+ kill_fasync (n_hdlc->tty->fasync, SIGIO);
#endif
} /* end of n_hdlc_tty_receive() */
} /* end of n_hdlc_tty_ioctl() */
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-/* n_hdlc_tty_select()
- *
- * Device select method. Determine if operation requires
- * blocking and if so put appropriate wait queue in select
- * table and return 0, otherwise return 1.
- *
- * Arguments:
- *
- * tty pointer to tty device instance data
- * inode pointer to inode for device
- * filp pointer to file object
- * sel_type identified the select type (read/write/exception)
- * wait select table for adding wait queue if appropriate
- *
- * Return Value:
- *
- * 1 if no need to block on operation
- * 0 if must block and wait queue added to select table
- */
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
- struct file *filp, int sel_type, select_table * wait)
-{
- struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
- int result = 1;
-
- if (debuglevel >= DEBUG_LEVEL_INFO)
- printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__);
-
- /* Verify the status of the device */
- if (!n_hdlc)
- return -EBADF;
-
- if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty)
- return -EBADF;
-
- switch (sel_type) {
- case SEL_IN:
- if (n_hdlc->rx_buf_list.head)
- break;
-
- case SEL_EX: /* Exceptions or read errors */
- /* Is this a pty link and the remote disconnected? */
- if (tty->flags & (1 << TTY_OTHER_CLOSED))
- break;
-
- /* Is this a local link and the modem disconnected? */
- if (tty_hung_up_p (filp))
- break;
-
- select_wait (&n_hdlc->read_wait, wait);
- result = 0;
- break;
-
- /* Write mode. A write is allowed if there is no current transmission */
- case SEL_OUT:
- if (!n_hdlc->tx_free_buf_list.head) {
- select_wait (&n_hdlc->write_wait, wait);
- result = 0;
- }
- break;
- }
- return result;
-} /* end of n_hdlc_tty_select() */
-
-#else /* 2.1.23 or later */
-
/* n_hdlc_tty_poll()
*
* TTY callback for poll system call. Determine which
if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
/* queue current process into any wait queue that */
/* may awaken in the future (read and write) */
-#if LINUX_VERSION_CODE < VERSION(2,1,89)
- poll_wait(&n_hdlc->poll_wait, wait);
-#else
poll_wait(filp, &n_hdlc->poll_wait, wait);
-#endif
+
/* set bits for operations that wont block */
if(n_hdlc->rx_buf_list.head)
mask |= POLLIN | POLLRDNORM; /* readable */
return mask;
} /* end of n_hdlc_tty_poll() */
-#endif
-
/* n_hdlc_alloc()
*
* Allocate an n_hdlc instance data structure
memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc));
n_hdlc_ldisc.magic = TTY_LDISC_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,28)
n_hdlc_ldisc.name = "hdlc";
-#endif
n_hdlc_ldisc.open = n_hdlc_tty_open;
n_hdlc_ldisc.close = n_hdlc_tty_close;
n_hdlc_ldisc.read = n_hdlc_tty_read;
n_hdlc_ldisc.write = n_hdlc_tty_write;
n_hdlc_ldisc.ioctl = n_hdlc_tty_ioctl;
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
- n_hdlc_ldisc.select = n_hdlc_tty_select;
-#else
n_hdlc_ldisc.poll = n_hdlc_tty_poll;
-#endif
n_hdlc_ldisc.receive_room = n_hdlc_tty_room;
n_hdlc_ldisc.receive_buf = n_hdlc_tty_receive;
n_hdlc_ldisc.write_wakeup = n_hdlc_tty_wakeup;
/*
* linux/drivers/char/synclink.c
*
- * ==FILEDATE 20000821==
+ * $Id: synclink.c,v 2.4 2000/12/11 20:08:18 paul Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-
#include <linux/netdevice.h>
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <asm/serial.h>
-#else
-#include <linux/bios32.h>
-#endif
-
#include <linux/delay.h>
#include <linux/ioctl.h>
#include <linux/termios.h>
#include <linux/tqueue.h>
+#if LINUX_VERSION_CODE < VERSION(2,2,18)
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX
+#define set_current_state(a) current->state = (a)
+#endif
+
#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
#define CONFIG_SYNCLINK_SYNCPPP 1
#endif
#ifdef CONFIG_SYNCLINK_SYNCPPP
-#if LINUX_VERSION_CODE < VERSION(2,3,43)
#include "../net/syncppp.h"
#define net_device device
#define netif_stop_queue(a) (a)->tbusy = 1
#define netif_start_queue(a) (a)->tbusy = 0
#define netif_wake_queue(a) (a)->tbusy = 0; mark_bh(NET_BH)
#define netif_queue_stopped(a) ((a)->tbusy)
-#else
-#include "../net/wan/syncppp.h"
-#endif
#endif
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
#include <asm/segment.h>
#define GET_USER(error,value,addr) error = get_user(value,addr)
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
#define PUT_USER(error,value,addr) error = put_user(value,addr)
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
#include <asm/uaccess.h>
-#endif
-
-#else /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
- if (error == 0) \
- value = get_user(addr); \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_READ, (void *) src, size); \
- if (error == 0) \
- memcpy_fromfs (dest, src, size); \
-} while (0)
-
-#define PUT_USER(error,value,addr) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
- if (error == 0) \
- put_user (value, addr); \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size) \
-do { \
- error = verify_area (VERIFY_WRITE, (void *) dest, size); \
- if (error == 0) \
- memcpy_tofs (dest, src, size); \
-} while (0)
-
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-#define __init
-#define ioremap(a,b) vremap((a),(b))
-#define iounmap(a) vfree((a))
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#define signal_pending(a) ((a)->signal & ~(a)->blocked)
-#endif
-
-
#include "linux/synclink.h"
static int maxframe[MAX_TOTAL_DEVICES] = {0,};
static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
MODULE_PARM(break_on_load,"i");
MODULE_PARM(ttymajor,"i");
MODULE_PARM(cuamajor,"i");
MODULE_PARM(debug_level,"i");
MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
-#endif
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.22";
+static char *driver_version = "2.3";
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
static void mgsl_change_params(struct mgsl_struct *info);
static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);
-static struct tty_struct **serial_table = NULL;
-static struct termios **serial_termios = NULL;
-static struct termios **serial_termios_locked = NULL;
+static struct tty_struct *serial_table[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES];
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
} else
info->input_signal_events.dcd_down++;
-#ifdef CONFIG_HARD_PPS
- if ((info->flags & ASYNC_HARDPPS_CD) &&
- (status & MISCSTATUS_DCD_LATCHED))
- hardpps();
-#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
{
icount->parity,icount->frame,icount->overrun);
}
- if ( tty->flip.count ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+ if ( tty->flip.count )
tty_flip_buffer_push(tty);
-#else
- queue_task(&tty->flip.tqueue, &tq_timer);
-#endif
- }
-
} /* end of mgsl_isr_receive_data() */
retval = mgsl_adapter_test(info);
if ( retval ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
if (capable(CAP_SYS_ADMIN) && info->tty)
-#else
- if (suser() && info->tty)
-#endif
set_bit(TTY_IO_ERROR, &info->tty->flags);
mgsl_release_resources(info);
return retval;
* current data rate.
*/
if (info->params.data_rate <= 460800) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
info->params.data_rate = tty_get_baud_rate(info->tty);
-#else
- int i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 4)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- info->params.data_rate = baud_table[i];
-#endif
}
if ( info->params.data_rate ) {
} /* end of set_modem_info() */
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
/* mgsl_break() Set or clear transmit break condition
*
* Arguments: tty pointer to tty instance data
spin_unlock_irqrestore(&info->irq_spinlock,flags);
} /* end of mgsl_break() */
-#endif
/* mgsl_ioctl() Service an IOCTL request
*
if (error) return error;
PUT_USER(error,cnow.dcd, &p_cuser->dcd);
if (error) return error;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
PUT_USER(error,cnow.rx, &p_cuser->rx);
if (error) return error;
PUT_USER(error,cnow.tx, &p_cuser->tx);
if (error) return error;
PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
if (error) return error;
-#endif
return 0;
default:
return -ENOIOCTLCMD;
}
}
- set_current_state(TASK_RUNNING);
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_wait_until_sent(%s) exit\n",
tmp_buf = (unsigned char *) page;
}
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-#endif
spin_lock_irqsave(&info->netlock, flags);
if (info->netcount) {
} /* end of mgsl_alloc_buffer_list_memory() */
-/*
- * mgsl_free_buffer_list_memory()
- *
- * Free the common DMA buffer allocated for use as the
- * receive and transmit buffer lists. The associated Memory
- * Descriptor List (MDL) is also freed.
- *
+/* Free DMA buffers allocated for use as the
+ * receive and transmit buffer lists.
* Warning:
*
* The data transfer buffers associated with the buffer list
* MUST be freed before freeing the buffer list itself because
* the buffer list contains the information necessary to free
* the individual buffers!
- *
- * Arguments: info pointer to device extension
- * Return Value: None
*/
void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
{
if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree_s(info->buffer_list, BUFFERLISTSIZE);
+ kfree(info->buffer_list);
info->buffer_list = NULL;
info->rx_buffer_list = NULL;
for ( i = 0 ; i < Buffercount ; i++ ) {
if ( BufferList[i].virt_addr ) {
if ( info->bus_type != MGSL_BUS_TYPE_PCI )
- kfree_s(BufferList[i].virt_addr, DMABUFFERSIZE);
+ kfree(BufferList[i].virt_addr);
BufferList[i].virt_addr = NULL;
}
}
void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info)
{
if ( info->intermediate_rxbuffer )
- kfree_s( info->intermediate_rxbuffer, info->max_frame_size);
+ kfree(info->intermediate_rxbuffer);
info->intermediate_rxbuffer = NULL;
} /* end of mgsl_free_intermediate_rxbuffer_memory() */
-/* mgsl_claim_resources()
- *
- * Claim all resources used by a device
- *
- * Arguments: info pointer to device instance data
- * Return Value: 0 if success, otherwise -ENODEV
- */
int mgsl_claim_resources(struct mgsl_struct *info)
{
/* claim 16C32 I/O base address */
info->irq_requested = 1;
if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
- /* claim shared memory range */
+
info->memory_base = ioremap(info->phys_memory_base,0x40000);
if (!info->memory_base) {
printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
return -ENODEV;
}
- /* test the shared memory range */
if ( !mgsl_memory_test(info) ) {
printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
return -ENODEV;
}
- /* claim LCR memory range */
info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
if (!info->lcr_base) {
printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
} /* end of mgsl_claim_resources() */
-/* mgsl_release_resources()
- *
- * Release all resources used by a device
- *
- * Arguments: info pointer to device instance data
- * Return Value: None
- */
void mgsl_release_resources(struct mgsl_struct *info)
{
if ( debug_level >= DEBUG_LEVEL_INFO )
printk("ISA device specified io=%04X,irq=%d,dma=%d\n",
io[i], irq[i], dma[i] );
- info = mgsl_allocate_device();
- if ( !info ) {
- /* error allocating device instance data */
+ if (!(info = mgsl_allocate_device())) {
if ( debug_level >= DEBUG_LEVEL_ERROR )
printk( "can't allocate device instance data.\n");
continue;
/* Copy user configuration info to device instance data */
info->io_base = (unsigned int)io[i];
info->irq_level = (unsigned int)irq[i];
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
info->irq_level = irq_cannonicalize(info->irq_level);
-#else
- if (info->irq_level == 2)
- info->irq_level = 9;
-#endif
info->dma_level = (unsigned int)dma[i];
info->bus_type = MGSL_BUS_TYPE_ISA;
info->io_addr_size = 16;
if ( pcibios_present() ) {
unsigned char bus;
unsigned char func;
- unsigned int shared_mem_base;
- unsigned int lcr_mem_base;
- unsigned int io_base;
- unsigned char irq_line;
for(i=0;;i++){
if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
struct pci_dev *pdev = pci_find_slot(bus,func);
- irq_line = pdev->irq;
-#else
- if (pcibios_read_config_byte(bus,func,
- PCI_INTERRUPT_LINE,&irq_line) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-#endif
-
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
- printk( "%s(%d):Shared mem addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_0,&lcr_mem_base) ) {
- printk( "%s(%d):LCR mem addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
- if (pcibios_read_config_dword(bus,func,
- PCI_BASE_ADDRESS_2,&io_base) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
- info = mgsl_allocate_device();
- if ( !info ) {
- /* error allocating device instance data */
+ if (!(info = mgsl_allocate_device())) {
if ( debug_level >= DEBUG_LEVEL_ERROR )
printk( "can't allocate device instance data.\n");
continue;
}
/* Copy user configuration info to device instance data */
+ info->irq_level = pdev->irq;
+ info->phys_lcr_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+ info->io_base = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
+ info->phys_memory_base = pdev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK;
- info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK;
- info->irq_level = (unsigned int)irq_line;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
- info->irq_level = irq_cannonicalize(info->irq_level);
-#else
- if (info->irq_level == 2)
- info->irq_level = 9;
-#endif
- info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
-
/* Because veremap only works on page boundaries we must map
* a larger area than is actually implemented for the LCR
* memory range. We map a full page starting at the page boundary.
*/
- info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
info->lcr_offset = info->phys_lcr_base & (PAGE_SIZE-1);
info->phys_lcr_base &= ~(PAGE_SIZE-1);
}
#endif
- /*
- * Allocate memory to hold the following tty/termios arrays
- * with an element for each enumerated device.
- */
-
- serial_table = (struct tty_struct**)kmalloc(sizeof(struct tty_struct*)*mgsl_device_count, GFP_KERNEL);
- serial_termios = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
- serial_termios_locked = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
-
- if (!serial_table || !serial_termios || !serial_termios_locked){
- printk("%s(%d):Can't allocate tty/termios arrays.\n",
- __FILE__,__LINE__);
- if (serial_table)
- kfree(serial_table);
- if (serial_termios)
- kfree(serial_termios);
- if (serial_termios_locked)
- kfree(serial_termios_locked);
- return -ENOMEM;
- }
-
- memset(serial_table,0,sizeof(struct tty_struct*)*mgsl_device_count);
- memset(serial_termios,0,sizeof(struct termios*)*mgsl_device_count);
- memset(serial_termios_locked,0,sizeof(struct termios*)*mgsl_device_count);
+ memset(serial_table,0,sizeof(struct tty_struct*)*MAX_TOTAL_DEVICES);
+ memset(serial_termios,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
+ memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
return 0;
{
struct mgsl_struct *info;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
EXPORT_NO_SYMBOLS;
-#else
- register_symtab(NULL);
-#endif
printk("%s version %s\n", driver_name, driver_version);
memset(&serial_driver, 0, sizeof(struct tty_driver));
serial_driver.magic = TTY_DRIVER_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
serial_driver.driver_name = "synclink";
-#endif
serial_driver.name = "ttySL";
serial_driver.major = ttymajor;
serial_driver.minor_start = 64;
serial_driver.ioctl = mgsl_ioctl;
serial_driver.throttle = mgsl_throttle;
serial_driver.unthrottle = mgsl_unthrottle;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
serial_driver.send_xchar = mgsl_send_xchar;
serial_driver.break_ctl = mgsl_break;
serial_driver.wait_until_sent = mgsl_wait_until_sent;
serial_driver.read_proc = mgsl_read_proc;
-#endif
serial_driver.set_termios = mgsl_set_termios;
serial_driver.stop = mgsl_stop;
serial_driver.start = mgsl_start;
callout_driver.name = "cuaSL";
callout_driver.major = cuamajor;
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
callout_driver.read_proc = 0;
callout_driver.proc_entry = 0;
-#endif
if (tty_register_driver(&serial_driver) < 0)
printk("%s(%d):Couldn't register serial driver\n",
} /* end of mgsl_init() */
-#ifdef MODULE
-int init_module(void)
+int __init init_module(void)
{
/* Uncomment this to kernel debug module.
* mgsl_get_text_ptr() leaves the .text address in eax
tmp_buf = NULL;
}
- if (serial_table)
- kfree_s(serial_table,sizeof(struct tty_struct*)*mgsl_device_count);
-
- if (serial_termios)
- kfree_s(serial_termios,sizeof(struct termios*)*mgsl_device_count);
-
- if (serial_termios_locked)
- kfree_s(serial_termios_locked,sizeof(struct termios*)*mgsl_device_count);
-
} /* end of cleanup_module() */
-#endif /* MODULE */
-
-
/*
* usc_RTCmd()
*
while( EndTime-- && !info->irq_occurred ) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(jiffies_from_ms(10));
- set_current_state(TASK_RUNNING);
}
spin_lock_irqsave(&info->irq_spinlock,flags);
sppp_attach(&info->pppdev);
d = info->netdev;
- strcpy(d->name, info->netname);
+ d->name = info->netname;
d->base_addr = info->io_base;
d->irq = info->irq_level;
d->dma = info->dma_level;
d->hard_start_xmit = mgsl_sppp_tx;
d->do_ioctl = mgsl_sppp_ioctl;
d->get_stats = mgsl_net_stats;
-#if LINUX_VERSION_CODE >= VERSION(2,3,43)
- d->tx_timeout = mgsl_sppp_tx_timeout;
- d->watchdog_timeo = 10*HZ;
-#endif
dev_init_buffers(d);
if (register_netdev(d) == -1) {
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgsl_sppp_tx(%s)\n",info->netname);
-#if LINUX_VERSION_CODE < VERSION(2,3,43)
if (dev->tbusy) {
if (time_before(jiffies, dev->trans_start+10*HZ))
return -EBUSY; /* 10 seconds timeout */
}
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
return -EBUSY;
-#else
- netif_stop_queue(dev);
-#endif
info->xmit_cnt = skb->len;
mgsl_load_tx_dma_buffer(info, skb->data, skb->len);
return (1);
#else
printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
+ return (0);
#endif /* CONFIG_PCI */
}
return(0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+#if CONFIG_PCI
for ( ;; )
{
-#if CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "Netjet: no PCI bus present\n");
return(0);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+#if CONFIG_PCI
for ( ;; )
{
-#if CONFIG_PCI
if (!pci_present()) {
printk(KERN_ERR "NETspider-U: no PCI bus present\n");
tristate 'Packet Engines GNIC-II (Hamachi) support' CONFIG_HAMACHI
tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
fi
- tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
+ dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
endmenu
bool 'FDDI driver support' CONFIG_FDDI
: is running from all accounts.
Alan Cox : Removed 1.2 support, added 2.1 extra counters.
+
+ Arnaldo Melo : release resources on failure in cs89x0_probe1
*/
static char *version =
struct net_local *lp;
static unsigned version_printed = 0;
int i;
+ char priv_alloced_here = 0;
unsigned rev_type = 0;
int eeprom_buff[CHKSUM_LEN];
/* Initialize the device structure. */
if (dev->priv == NULL) {
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ if (!dev->priv)
+ return -ENOMEM;
memset(dev->priv, 0, sizeof(struct net_local));
+ priv_alloced_here = 1;
}
lp = (struct net_local *)dev->priv;
if (ioaddr & 1) {
ioaddr &= ~1;
if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
- return ENODEV;
+ goto err;
outw(PP_ChipID, ioaddr + ADD_PORT);
}
if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
- return ENODEV;
+ goto err;
/* Fill in the 'dev' fields. */
dev->base_addr = ioaddr;
printk("\n");
return 0;
+err: if (priv_alloced_here) {
+ kfree(dev->priv);
+ dev->priv = NULL;
+ }
+ return -ENODEV;
}
* First release to the public
* 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing
* malloc free checks, reviewed code. <alan@redhat.com>
+ * 12/18/00 - Made it SMP safe - George Staikos <staikos@0wned.org>
*
* To Do:
*
#include <net/checksum.h>
#include <asm/io.h>
+#include <asm/spinlock.h>
#include <asm/system.h>
#include <asm/bitops.h>
streamer_priv = (struct streamer_private *) dev->priv;
streamer_mmio = streamer_priv->streamer_mmio;
+ streamer_priv->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
printk("%s \n", version);
printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n",
dev->name, (unsigned int) dev->base_addr,
__u16 misr;
__u16 sisrmask;
+ spin_lock(&(streamer_priv->lock));
sisrmask = SISR_MI;
writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
sisr = readw(streamer_mmio + SISR);
writew(~misr, streamer_mmio + MISR_RUM);
if (!sisr) { /* Interrupt isn't for us */
+ spin_unlock(&(streamer_priv->lock));
return;
}
dev->interrupt = 0;
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+ spin_unlock(&(streamer_priv->lock));
}
struct streamer_private *streamer_priv =
(struct streamer_private *) dev->priv;
__u8 *streamer_mmio = streamer_priv->streamer_mmio;
+ int flags;
if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
return 1;
}
+ spin_lock_irqsave(&(streamer_priv->lock), flags);
+
if (streamer_priv->free_tx_ring_entries) {
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
dev->tbusy = 0;
+ spin_unlock_irqrestore(&(streamer_priv->lock), flags);
return 0;
} else {
+ spin_unlock_irqrestore(&(streamer_priv->lock), flags);
return 1;
}
}
__u16 streamer_addr_table_addr, streamer_parms_addr;
__u16 mac_rx_buffer;
__u8 streamer_laa[6];
+ spinlock_t lock;
};
struct streamer_adapter_addr_table {
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
- Center of Excellence in Space Data and Information Sciences
- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
- People are making PCI ne2000 clones! Oh the horror, the horror...
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
Issues remaining:
- No full-duplex support.
+ People are making PCI ne2000 clones! Oh the horror, the horror...
+ Limited full-duplex support.
+
+ ChangeLog:
+
+ 12/15/2000 Merged Scyld v1.02 into 2.2.18
+ J.A. Magallon <jamagallon@able.es>
*/
-/* Our copyright info must remain in the binary. */
-static const char *version =
-"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"ne2k-pci.c:v1.02 10/19/2000 D. Becker/P. Gortmaker\n";
+static const char version2[] =
+" http://www.scyld.com/network/ne2k-pci.html\n";
#include <linux/module.h>
#include <linux/kernel.h>
#endif
/* Set statically or when loading the driver module. */
-static int debug = 1;
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+/* More are supported, limit only on options */
+#define MAX_UNITS 6
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+
+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
+MODULE_DESCRIPTION("PCI NE2000 clone driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
/* Some defines that people can play with if so inclined. */
/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
/* #define PACKETBUF_MEMSIZE 0x40 */
-#define ne2k_flags reg0 /* Rename an existing field to store flags! */
-
-/* Only the low 8 bits are usable for non-init-time flags! */
+/* Flags. We rename an existing ei_status field to store flags! */
+/* Thus only the low 8 bits are usable for non-init-time flags. */
+#define ne2k_flags reg0
enum {
- HOLTEK_FDX=1, /* Full duplex -> set 0x80 at offset 0x20. */
- ONLY_16BIT_IO=2, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ ONLY_16BIT_IO=8, ONLY_32BIT_IO=4, /* Chip can do only 16/32-bit xfers. */
+ FORCE_FDX=0x20, /* User override. */
+ REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
STOP_PG_0x60=0x100,
};
int flags;
}
pci_clone_list[] __initdata = {
- {0x10ec, 0x8029, "RealTek RTL-8029", 0},
- {0x1050, 0x0940, "Winbond 89C940", 0},
- {0x11f6, 0x1401, "Compex RL2000", 0},
- {0x8e2e, 0x3000, "KTI ET32P2", 0},
- {0x4a14, 0x5000, "NetVin NV5000SC", 0},
- {0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
- {0x10bd, 0x0e34, "SureCom NE34", 0},
- {0x1050, 0x5a5a, "Winbond", 0},
- {0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
- {0x12c3, 0x5598, "Holtek HT80229",
- ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
- {0,}
+{0x10ec, 0x8029, "RealTek RTL-8029", REALTEK_FDX},
+{0x1050, 0x0940, "Winbond 89C940", 0},
+{0x1050, 0x5a5a, "Winbond w89c940", 0},
+{0x8e2e, 0x3000, "KTI ET32P2", 0},
+{0x4a14, 0x5000, "NetVin NV5000SC", 0},
+{0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
+{0x10bd, 0x0e34, "SureCom NE34", 0},
+{0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO|HOLTEK_FDX},
+{0x12c3, 0x5598, "Holtek HT80229", ONLY_32BIT_IO|HOLTEK_FDX|STOP_PG_0x60 },
+{0x11f6, 0x1401, "Compex RL2000", 0},
+{0,}
};
/* ---- No user-serviceable parts below ---- */
static void ne2k_pci_block_output(struct device *dev, const int count,
const unsigned char *buf, const int start_page);
-\f
+
/* No room in the standard 8390 structure for extra info we need. */
struct ne2k_pci_card {
{
/* We must emit version information. */
if (debug)
- printk(KERN_INFO "%s", version);
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
if (ne2k_pci_probe(0)) {
printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
return cards_found ? 0 : -ENODEV;
}
-__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, long ioaddr, int irq,
- int chip_idx))
+__initfunc (static struct device *ne2k_pci_probe1(struct device *dev,
+ long ioaddr, int irq, int chip_idx))
{
int i;
unsigned char SA_prom[32];
dev = init_etherdev(dev, 0);
+ if (!dev) return 0;
+
/* Reset card. Who knows what dain-bramaged state it was left in. */
{
unsigned long reset_start_time = jiffies;
/* Note: all PCI cards have at least 16 bit access, so we don't have
to check for 8 bit cards. Most cards permit 32 bit access. */
if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
- for (i = 0; i < 4 ; i++)
+ for (i = 0; i < 8 ; i++)
((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
} else
for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
ei_status.stop_page = stop_page;
ei_status.word16 = 1;
ei_status.ne2k_flags = pci_clone_list[chip_idx].flags;
+ if (chip_idx < MAX_UNITS) {
+ if (full_duplex[chip_idx] || (options[chip_idx] & FORCE_FDX))
+ ei_status.ne2k_flags |= FORCE_FDX;
+ }
ei_status.rx_start_page = start_page + TX_PAGES;
#ifdef PACKETBUF_MEMSIZE
{
if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev))
return -EAGAIN;
- ei_open(dev);
MOD_INC_USE_COUNT;
+ /* Set full duplex for the chips that we know about. */
+ if (ei_status.ne2k_flags & FORCE_FDX) {
+ long ioaddr = dev->base_addr;
+ if (ei_status.ne2k_flags & REALTEK_FDX) {
+ outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ } else if (ei_status.ne2k_flags & HOLTEK_FDX)
+ outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+ }
+ ei_open(dev);
return 0;
}
Support and updates available at
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
-
+
This driver also contains updates by Wolfgang Walter and others.
For this specific driver variant please use linux-kernel for
bug reports.
+
+ Updated 12/17/2000 by Jim McQuillan <jam@McQuil.com> to
+ include support for the Linksys LNE100TX card based on the
+ Admtek 985 Centaur-P chipset.
*/
#define SMP_CHECK
HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
{ "ADMtek Comet", 256, 0x0001abef,
MC_HASH_ONLY, comet_timer },
+ { "ADMtek Centaur-P", 256, 0x0001abef,
+ MC_HASH_ONLY, comet_timer },
{ "Compex 9881 PMAC", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
{ "Intel DS21145 Tulip", 128, 0x0801fbff,
/* This matches the table above. Note 21142 == 21143. */
enum chips {
DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
- LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
- I21145,
+ LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMET5,
+ COMPEX9881, I21145, XIRCOM,
};
/* A full-duplex map for media types. */
{0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };
static u8 t21040_csr13[] = {2,0x0C,8,4, 4,0,0,0, 0,0,0,0, 4,0,0,0};
/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
-static u16 t21041_csr13[] = { 0xEF05, 0xEF0D, 0xEF0D, 0xEF05, 0xEF05, };
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
return -ENODEV;
for (;pci_index < 0xff; pci_index++) {
- u16 vendor, device, pci_command, new_command, subvendor;
+ u16 vendor, device, pci_command, new_command;
int chip_idx;
int irq;
long ioaddr;
PCI_VENDOR_ID, &vendor);
pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_DEVICE_ID, &device);
- pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
-
- if( subvendor == 0x1376 ){
- printk("tulip: skipping LMC card.\n");
- continue;
- }
for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
if (vendor == pci_tbl[chip_idx].vendor_id
put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
sum += value & 0xffff;
}
- } else if (chip_idx == COMET) {
+ } else if (chip_idx == COMET){
+ /* No need to read the EEPROM. */
+ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+ put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+ for (i = 0; i < 6; i ++)
+ sum += dev->dev_addr[i];
+ } else if (chip_idx == COMET5){
/* No need to read the EEPROM. */
put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
case COMET:
/* No initialization necessary. */
break;
+ case COMET5:
+ /* No initialization necessary. */
+ break;
}
if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
}
return 0xffff;
}
+ if (tp->chip_id == COMET5) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
/* Establish sync by sending at least 32 logic ones. */
for (i = 32; i >= 0; i--) {
return;
}
+ if (tp->chip_id == COMET5) {
+ if (phy_id != 1)
+ return;
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ return;
+ }
+
/* Establish sync by sending 32 logic ones. */
for (i = 32; i >= 0; i--) {
outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
outl(addr_high, ioaddr + 0xA8);
outl(0, ioaddr + 0xAC);
outl(0, ioaddr + 0xB0);
+ } else if (tp->chip_id == COMET5) {
+ outl(addr_low, ioaddr + 0xA4);
+ outl(addr_high, ioaddr + 0xA8);
+ outl(0, ioaddr + 0xAC);
+ outl(0, ioaddr + 0xB0);
}
} else {
/* This is set_rx_mode(), but without starting the transmitter. */
} else if (tp->chip_id == COMET) {
dev->if_port = 0;
tp->csr6 = 0x00040000;
+ } else if (tp->chip_id == COMET5) {
+ dev->if_port = 0;
+ tp->csr6 = 0x00040000;
} else if (tp->chip_id == AX88140) {
tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
} else
data[0] = 32;
else if (tp->chip_id == COMET)
data[0] = 1;
+ else if (tp->chip_id == COMET5)
+ data[0] = 1;
else
return -ENODEV;
case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
outl(mc_filter[0], ioaddr + 0xAC);
outl(mc_filter[1], ioaddr + 0xB0);
+ } else if (tp->chip_id == COMET5) { /* Has a simple hash filter. */
+ outl(mc_filter[0], ioaddr + 0xAC);
+ outl(mc_filter[1], ioaddr + 0xB0);
}
}
} else {
/* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
/*
- Written 1998-1999 by Donald Becker.
+ Written 1998-2000 by Donald Becker.
- This software may be used and distributed according to the terms
- of the GNU Public License (GPL), incorporated herein by reference.
- Drivers derived from this code also fall under the GPL and must retain
- this authorship and copyright notice.
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet
controller. It also works with the older 3043 Rhine-I chip.
- The author may be reached as becker@cesdis.edu, or
- Donald Becker
- 312 Severn Ave. #W302
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
Annapolis MD 21403
Support and updates available at
- http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
+ http://www.scyld.com/network/via-rhine.html
+
+
+ Linux kernel version history:
+
+ LK1.0.0:
+ - Urban Widmark: merges from Beckers 1.08b version and 2.4.0 (VT6102)
*/
-static const char *versionA =
-"via-rhine.c:v1.01 2/27/99 Written by Donald Becker\n";
-static const char *versionB =
-" http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"via-rhine.c:v1.08b-LK1.0.0 12/14/2000 Written by Donald Becker\n";
+static const char version2[] =
+" http://www.scyld.com/network/via-rhine.html\n";
-/* A few user-configurable values. These may be modified when a driver
- module is loaded.*/
+/* The user-configurable values.
+ These may be modified when a driver module is loaded.*/
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
+static int min_pci_latency = 32;
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1518 effectively disables this feature. */
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE 8
+#define TX_RING_SIZE 16
+#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
#define RX_RING_SIZE 16
/* Operational parameters that usually are not changed. */
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+
+#if !defined(__OPTIMIZE__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <asm/bitops.h>
#include <asm/io.h>
-/* This driver was written to use PCI memory space, however some x86
- motherboards only configure I/O space accesses correctly. */
-#if defined(__i386__) && !defined(VIA_USE_MEMORY)
-#define VIA_USE_IO
-#endif
-#if defined(__alpha__)
-#define VIA_USE_IO
-#endif
-#ifdef VIA_USE_IO
+/* Condensed bus+endian portability operations. */
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
+
+/* This driver was written to use PCI memory space, however most versions
+ of the Rhine only work correctly with I/O space accesses. */
+#if defined(VIA_USE_MEMORY)
+#warning Many adapters using the VIA Rhine chip are not configured to work
+#warning with PCI memory space accesses.
+#else
+#define USE_IO_OPS
#undef readb
#undef readw
#undef readl
#define writel outl
#endif
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
- This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#if (LINUX_VERSION_CODE >= 0x20100)
-static char kernel_version[] = UTS_RELEASE;
-#else
-#ifndef __alpha__
-#define ioremap vremap
-#define iounmap vfree
-#endif
-#endif
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(min_pci_latency, "i");
MODULE_PARM(rx_copybreak, "i");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155 || defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
-
/*
Theory of Operation
IVb. References
Preliminary VT86C100A manual from http://www.via.com.tw/
-http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
IVc. Errata
The VT86C100A manual is not reliable information.
-The chip does not handle unaligned transmit or receive buffers, resulting
+The 3043 chip does not handle unaligned transmit or receive buffers, resulting
in significant performance degradation for bounce buffer copies on transmit
and unaligned IP headers on receive.
The chip does not pad to minimum transmit length.
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
+
+#if defined(VIA_USE_MEMORY)
+#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR0)
+#define RHINEII_IOSIZE 4096
+#else
+#define RHINE_IOTYPE (PCI_USES_IO | PCI_USES_MASTER | PCI_ADDR1)
+#define RHINEII_IOSIZE 256
+#endif
+
struct pci_id_info {
const char *name;
u16 vendor_id, device_id, device_id_mask, flags;
static struct pci_id_info pci_tbl[] __initdata = {
{ "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
- PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
+ RHINE_IOTYPE, 128, via_probe1},
+ { "VIA VT6102 Rhine-II", 0x1106, 0x3065, 0xffff,
+ RHINE_IOTYPE, RHINEII_IOSIZE, via_probe1},
{ "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
- PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
+ RHINE_IOTYPE, 128, via_probe1},
{0,}, /* 0 terminated list. */
};
/* A chip capabilities table, matching the entries in pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
+enum chip_capability_flags {
+ CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4,
+ ReqTxAlign=0x10, HasWOL=0x20,
+};
+
struct chip_info {
int io_size;
int flags;
} static cap_tbl[] __initdata = {
- {128, CanHaveMII, },
- {128, CanHaveMII, },
+ {128, CanHaveMII | ReqTxAlign, },
+ {128, CanHaveMII | HasWOL, },
+ {128, CanHaveMII | ReqTxAlign, },
};
-/* Offsets to the device registers.
-*/
+/* Offsets to the device registers. */
enum register_offsets {
StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
IntrStatus=0x0C, IntrEnable=0x0E,
MulticastFilter0=0x10, MulticastFilter1=0x14,
RxRingPtr=0x18, TxRingPtr=0x1C,
- MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E,
+ MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
- Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E,
+ Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E,
+ StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
};
/* Bits in the interrupt status/mask registers. */
IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
IntrTxAborted=0x2000, IntrLinkChange=0x4000,
IntrRxWakeUp=0x8000,
- IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260,
+ IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
};
-
/* The Rx and Tx buffer descriptors. */
struct rx_desc {
- u16 rx_status;
- u16 rx_length;
+ s32 rx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
};
struct tx_desc {
- u16 tx_status;
- u16 tx_own;
+ s32 tx_status;
u32 desc_length;
u32 addr;
u32 next_desc;
/* Bits in *_desc.status */
enum rx_status_bits {
- RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
+ RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
+};
enum desc_status_bits {
- DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000,
+ DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
};
/* Bits in ChipCmd. */
CmdNoTxPoll=0x0800, CmdReset=0x8000,
};
+#define PRIV_ALIGN 15 /* Required alignment mask */
struct netdev_private {
/* Descriptor rings first for alignment. */
struct rx_desc rx_ring[RX_RING_SIZE];
unsigned char *tx_buf[TX_RING_SIZE]; /* Tx bounce buffers */
unsigned char *tx_bufs; /* Tx bounce buffer region. */
struct device *next_module; /* Link for devices of this type. */
+ void *priv_addr; /* Unaligned address for kfree */
struct net_device_stats stats;
struct timer_list timer; /* Media monitoring timer. */
unsigned char pci_bus, pci_devfn;
/* Frequently used values: keep some adjacent for cache effect. */
- int chip_id;
- long in_interrupt; /* Word-long for SMP locks. */
+ int chip_id, drv_flags;
struct rx_desc *rx_head_desc;
unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */
unsigned int cur_tx, dirty_tx;
static struct net_device_stats *get_stats(struct device *dev);
static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct device *dev);
+static inline void clear_tally_counters(long ioaddr);
\f
continue;
{
-#if defined(PCI_SUPPORT_VER2)
struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-#ifdef VIA_USE_IO
+#ifdef USE_IO_OPS
pciaddr = pdev->base_address[0];
#else
pciaddr = pdev->base_address[1];
#endif
irq = pdev->irq;
-#else
- u32 pci_memaddr;
- u8 pci_irq_line;
- pcibios_read_config_byte(pci_bus, pci_device_fn,
- PCI_INTERRUPT_LINE, &pci_irq_line);
-#ifdef VIA_USE_IO
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &pci_memaddr);
- pciaddr = pci_memaddr;
-#else
- pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_1, &pci_memaddr);
- pciaddr = pci_memaddr;
-#endif
- irq = pci_irq_line;
-#endif
}
if (debug > 2)
{
static int did_version = 0;
if (!did_version++)
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
return pci_etherdev_probe(dev, pci_tbl);
}
#endif
int chip_id, int card_idx)
{
struct netdev_private *np;
+ void *priv_mem;
int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
dev = init_etherdev(dev, 0);
printk(KERN_INFO "%s: %s at 0x%lx, ",
dev->name, pci_tbl[chip_id].name, ioaddr);
- /* Ideally we would be read the EEPROM but access may be locked. */
- for (i = 0; i <6; i++)
+ /* We would prefer to read the EEPROM but access may be locked. */
+ for (i = 0; i < 6; i++)
dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
for (i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-#ifdef VIA_USE_IO
+ /* Allocate driver private memory for descriptor lists.
+ Check for the very unlikely case of no memory. */
+ priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
+ if (priv_mem == NULL)
+ return NULL;
+
+#ifdef USE_IO_OPS
request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name);
#endif
dev->irq = irq;
/* Make certain the descriptor lists are cache-aligned. */
- np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);
+ dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
memset(np, 0, sizeof(*np));
- dev->priv = np;
+ np->priv_addr = priv_mem;
np->next_module = root_net_dev;
root_net_dev = dev;
np->pci_bus = pci_bus;
np->pci_devfn = pci_devfn;
np->chip_id = chip_id;
+ np->drv_flags = cap_tbl[chip_id].flags;
if (dev->mem_start)
option = dev->mem_start;
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &mii_ioctl;
- if (cap_tbl[np->chip_id].flags & CanHaveMII) {
+ if (np->drv_flags & CanHaveMII) {
int phy, phy_idx = 0;
np->phys[0] = 1; /* Standard for this chip. */
for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
static void mdio_write(struct device *dev, int phy_id, int regnum, int value)
{
+ struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
int boguscnt = 1024;
+ if (phy_id == np->phys[0]) {
+ switch (regnum) {
+ case 0: /* Is user forcing speed/duplex? */
+ if (value & 0x9000) /* Autonegotiation. */
+ np->duplex_lock = 0;
+ else
+ np->full_duplex = (value & 0x0100) ? 1 : 0;
+ break;
+ case 4:
+ np->advertising = value;
+ break;
+ }
+ }
/* Wait for a previous command to complete. */
while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)
;
/* Reset the chip. */
writew(CmdReset, ioaddr + ChipCmd);
- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+ MOD_INC_USE_COUNT;
+
+ if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
+ MOD_DEC_USE_COUNT;
return -EAGAIN;
+ }
if (debug > 1)
printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
dev->name, dev->irq);
- MOD_INC_USE_COUNT;
-
init_ring(dev);
writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
/* Initialize other registers. */
- writew(0x0006, ioaddr + PCIConfig); /* Tune configuration??? */
+ writew(0x0006, ioaddr + PCIBusConfig); /* Tune configuration??? */
/* Configure the FIFO thresholds. */
writeb(0x20, ioaddr + TxConfig); /* Initial threshold 32 bytes */
np->tx_thresh = 0x20;
dev->tbusy = 0;
dev->interrupt = 0;
- np->in_interrupt = 0;
set_rx_mode(dev);
writew(np->chip_cmd, ioaddr + ChipCmd);
check_duplex(dev);
+ /* The LED outputs of various MII xcvrs should be configured. */
+ /* For NS or Mison phys, turn on bit 1 in register 0x17 */
+ /* For ESI phys, turn on bit 7 in register 0x17. */
+ mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
+ (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
if (debug > 2)
printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
/* Set the timer to check for link beat. */
init_timer(&np->timer);
- np->timer.expires = RUN_AT(1);
+ np->timer.expires = jiffies + 2;
np->timer.data = (unsigned long)dev;
np->timer.function = &netdev_timer; /* timer handler */
add_timer(&np->timer);
struct netdev_private *np = (struct netdev_private *)dev->priv;
long ioaddr = dev->base_addr;
int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+ int negotiated = mii_reg5 & np->advertising;
int duplex;
if (np->duplex_lock || mii_reg5 == 0xffff)
return;
- duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+ duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->full_duplex != duplex) {
np->full_duplex = duplex;
if (debug)
printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
}
+ if (test_bit(0, (void*)&dev->tbusy) != 0
+ && np->cur_tx - np->dirty_tx > 1
+ && jiffies - dev->trans_start > TX_TIMEOUT)
+ tx_timeout(dev);
+
check_duplex(dev);
- np->timer.expires = RUN_AT(next_tick);
+ np->timer.expires = jiffies + next_tick;
add_timer(&np->timer);
}
dev->name, readw(ioaddr + IntrStatus),
mdio_read(dev, np->phys[0], 1));
- /* Perhaps we should reinitialize the hardware here. */
- dev->if_port = 0;
- /* Stop and restart the chip's Tx processes . */
+ /* Perhaps we should reinitialize the hardware here. */
+ dev->if_port = 0;
+ /* Stop and restart the chip's Tx processes . */
- /* Trigger an immediate transmit demand. */
+ /* Trigger an immediate transmit demand. */
- dev->trans_start = jiffies;
- np->stats.tx_errors++;
- return;
+ dev->trans_start = jiffies;
+ np->stats.tx_errors++;
+ return;
}
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = 0;
- np->rx_ring[i].desc_length = np->rx_buf_sz;
- np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
+ np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+ np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
np->rx_skbuff[i] = 0;
}
/* Mark the last entry as wrapping the ring. */
- np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
+ np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
- /* Fill in the Rx buffers. */
+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
for (i = 0; i < RX_RING_SIZE; i++) {
struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
np->rx_skbuff[i] = skb;
if (skb == NULL)
break;
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[i].addr = virt_to_bus(skb->tail);
- np->rx_ring[i].rx_status = 0;
- np->rx_ring[i].rx_length = DescOwn;
+ np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
+ np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
}
np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
for (i = 0; i < TX_RING_SIZE; i++) {
np->tx_skbuff[i] = 0;
- np->tx_ring[i].tx_own = 0;
- np->tx_ring[i].desc_length = 0x00e08000;
- np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
+ np->tx_ring[i].tx_status = 0;
+ np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+ np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
}
- np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
+ np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
return;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- if (jiffies - dev->trans_start < TX_TIMEOUT)
- return 1;
- tx_timeout(dev);
+ /* This watchdog code is redundant with the media monitor timer. */
+ if (jiffies - dev->trans_start > TX_TIMEOUT)
+ tx_timeout(dev);
return 1;
}
- /* Caution: the write order is important here, set the field
- with the "ownership" bits last. */
+ /* Explicitly flush packet data cache lines here. */
+
+ /* Caution: the write order is important here, set the descriptor word
+ with the "ownership" bit last. No SMP locking is needed if the
+ cur_tx is incremented after the descriptor is consistent. */
/* Calculate the next Tx descriptor entry. */
entry = np->cur_tx % TX_RING_SIZE;
np->tx_skbuff[entry] = skb;
- if ((long)skb->data & 3) { /* Must use alignment buffer. */
+ if ((np->drv_flags & ReqTxAlign) && ((long)skb->data & 3)) {
+ /* Must use alignment buffer. */
if (np->tx_buf[entry] == NULL &&
(np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)
return 1;
memcpy(np->tx_buf[entry], skb->data, skb->len);
- np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);
+ np->tx_ring[entry].addr = virt_to_le32desc(np->tx_buf[entry]);
} else
- np->tx_ring[entry].addr = virt_to_bus(skb->data);
+ np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
- np->tx_ring[entry].desc_length = 0x00E08000 |
- (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
- np->tx_ring[entry].tx_own = DescOwn;
+ np->tx_ring[entry].desc_length =
+ cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+ np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
np->cur_tx++;
- /* Non-x86 Todo: explicitly flush cache lines here. */
+ /* Explicitly flush descriptor cache lines here. */
/* Wake the potentially-idle transmit channel. */
writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
- if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)
+ if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1)
clear_bit(0, (void*)&dev->tbusy); /* Typical path */
else
np->tx_full = 1;
static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
{
struct device *dev = (struct device *)dev_instance;
- struct netdev_private *np;
- long ioaddr, boguscnt = max_interrupt_work;
-
- ioaddr = dev->base_addr;
- np = (struct netdev_private *)dev->priv;
-#if defined(__i386__)
- /* A lock to prevent simultaneous entry bug on Intel SMP machines. */
- if (test_and_set_bit(0, (void*)&dev->interrupt)) {
- printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
- dev->name);
- dev->interrupt = 0; /* Avoid halting machine. */
- return;
- }
-#else
- if (dev->interrupt) {
- printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
- return;
- }
- dev->interrupt = 1;
-#endif
+ struct netdev_private *np = (void *)dev->priv;
+ long ioaddr = dev->base_addr;
+ int boguscnt = max_interrupt_work;
do {
u32 intr_status = readw(ioaddr + IntrStatus);
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE;
- int txstatus;
- if (np->tx_ring[entry].tx_own)
+ int txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
+ if (txstatus & DescOwn)
break;
- txstatus = np->tx_ring[entry].tx_status;
if (debug > 6)
printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
entry, txstatus);
#endif
np->stats.collisions += (txstatus >> 3) & 15;
#if defined(NETSTATS_VER2)
- np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+ np->stats.tx_bytes += np->tx_skbuff[entry]->len;
#endif
np->stats.tx_packets++;
}
/* Free the original skb. */
- dev_free_skb(np->tx_skbuff[entry]);
+ dev_kfree_skb(np->tx_skbuff[entry]);
np->tx_skbuff[entry] = 0;
}
if (np->tx_full && dev->tbusy
- && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+ && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
/* The ring is no longer full, clear tbusy. */
np->tx_full = 0;
clear_bit(0, (void*)&dev->tbusy);
printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
dev->name, readw(ioaddr + IntrStatus));
-#if defined(__i386__)
- clear_bit(0, (void*)&dev->interrupt);
-#else
- dev->interrupt = 0;
-#endif
return;
}
int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
- printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
- entry, np->rx_head_desc->rx_length);
+ printk(KERN_DEBUG " In netdev_rx(), entry %d status %8.8x.\n",
+ entry, np->rx_head_desc->rx_status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while ( ! (np->rx_head_desc->rx_length & DescOwn)) {
+ while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
struct rx_desc *desc = np->rx_head_desc;
- int data_size = desc->rx_length;
- u16 desc_status = desc->rx_status;
+ u32 desc_status = le32_to_cpu(desc->rx_status);
+ int data_size = desc_status >> 16;
if (debug > 4)
printk(KERN_DEBUG " netdev_rx() status is %4.4x.\n",
} else {
struct sk_buff *skb;
/* Length should omit the CRC */
- u16 pkt_len = data_size - 4;
+ int pkt_len = data_size - 4;
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
-#if ! defined(__alpha__) || USE_IP_COPYSUM /* Avoid misaligned on Alpha */
- eth_copy_and_sum(skb, bus_to_virt(desc->addr),
- pkt_len, 0);
+#if HAS_IP_COPYSUM /* Call copy + cksum if available. */
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);
+ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+ pkt_len);
#endif
} else {
skb_put(skb = np->rx_skbuff[entry], pkt_len);
np->rx_skbuff[entry] = NULL;
}
skb->protocol = eth_type_trans(skb, dev);
- np->stats.rx_bytes+=skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
+#if defined(NETSTATS_VER2)
+ np->stats.rx_bytes += skb->len;
+#endif
np->stats.rx_packets++;
}
entry = (++np->cur_rx) % RX_RING_SIZE;
if (skb == NULL)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[entry].addr = virt_to_bus(skb->tail);
+ np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
}
- np->rx_ring[entry].rx_status = 0;
- np->rx_ring[entry].rx_length = DescOwn;
+ np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
}
/* Pre-emptively restart Rx engine. */
long ioaddr = dev->base_addr;
if (intr_status & (IntrMIIChange | IntrLinkChange)) {
- if (readb(ioaddr + MIIStatus) & 0x02)
+ if (readb(ioaddr + MIIStatus) & 0x02) {
/* Link failed, restart autonegotiation. */
- mdio_write(dev, np->phys[0], 0, 0x3300);
- else
+ if (np->drv_flags & HasDavicomPhy)
+ mdio_write(dev, np->phys[0], 0, 0x3300);
+ } else
check_duplex(dev);
if (debug)
printk(KERN_ERR "%s: MII status changed: Autonegotiation "
if (intr_status & IntrStatsMax) {
np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
- writel(0, RxMissed);
+ clear_tally_counters(ioaddr);
}
if (intr_status & IntrTxAbort) {
/* Stats counted in Tx-done handler, just restart Tx. */
printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
"threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
}
- if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {
+ if ((intr_status & ~(IntrLinkChange | IntrStatsMax |
+ IntrTxAbort|IntrTxAborted)) && debug) {
printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
dev->name, intr_status);
/* Recovery for other fault sources not known. */
non-critical. */
np->stats.rx_crc_errors += readw(ioaddr + RxCRCErrs);
np->stats.rx_missed_errors += readw(ioaddr + RxMissed);
- writel(0, RxMissed);
+ clear_tally_counters(ioaddr);
return &np->stats;
}
+/* Clears the "tally counters" for CRC errors and missed frames(?).
+ It has been reported that some chips need a write of 0 to clear
+ these, for others the counters are set to 1 when written to and
+ instead cleared when read. So we clear them both ways ... */
+static inline void clear_tally_counters(const long ioaddr)
+{
+ writel(0, ioaddr + RxMissed);
+ readw(ioaddr + RxCRCErrs);
+ readw(ioaddr + RxMissed);
+}
+
/* The big-endian AUTODIN II ethernet CRC calculation.
N.B. Do not use for bulk data, use a table-based routine instead.
This is common code and should be moved to net/core/crc.c */
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc(int length, unsigned char *data)
{
- int crc = -1;
+ int crc = -1;
- while(--length >= 0) {
+ while(--length >= 0) {
unsigned char current_octet = *data++;
int bit;
for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
crc = (crc << 1) ^
((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
}
- }
- return crc;
+ }
+ return crc;
}
static void set_rx_mode(struct device *dev)
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
+ writel(0xffffffff, ioaddr + MulticastFilter0);
+ writel(0xffffffff, ioaddr + MulticastFilter1);
rx_mode = 0x0C;
} else {
struct dev_mc_list *mclist;
}
writel(mc_filter[0], ioaddr + MulticastFilter0);
writel(mc_filter[1], ioaddr + MulticastFilter1);
- rx_mode = 0x08;
+ rx_mode = 0x0C;
}
writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
}
data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
return 0;
case SIOCDEVPRIVATE+2: /* Write the specified MII register */
- if (!suser())
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
return 0;
printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
dev->name, readw(ioaddr + ChipCmd));
+ del_timer(&np->timer);
+
+ /* Switch to loopback mode to avoid hardware races. */
+ writeb(np->tx_thresh | 0x01, ioaddr + TxConfig);
+
/* Disable interrupts by clearing the interrupt mask. */
writew(0x0000, ioaddr + IntrEnable);
/* Stop the chip's Tx and Rx processes. */
writew(CmdStop, ioaddr + ChipCmd);
- del_timer(&np->timer);
-
free_irq(dev->irq, dev);
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
- np->rx_ring[i].rx_length = 0;
+ np->rx_ring[i].rx_status = 0;
np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
if (np->rx_skbuff[i]) {
#if LINUX_VERSION_CODE < 0x20100
np->rx_skbuff[i]->free = 1;
#endif
- dev_free_skb(np->rx_skbuff[i]);
+ dev_kfree_skb(np->rx_skbuff[i]);
}
np->rx_skbuff[i] = 0;
}
for (i = 0; i < TX_RING_SIZE; i++) {
if (np->tx_skbuff[i])
- dev_free_skb(np->tx_skbuff[i]);
+ dev_kfree_skb(np->tx_skbuff[i]);
np->tx_skbuff[i] = 0;
+ if (np->tx_buf[i]) {
+ kfree(np->tx_buf[i]);
+ np->tx_buf[i] = 0;
+ }
}
MOD_DEC_USE_COUNT;
int init_module(void)
{
if (debug) /* Emit version even if no cards detected. */
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
- register_driver(ðerdev_ops);
- return 0;
-#else
+ printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
return pci_etherdev_probe(NULL, pci_tbl);
-#endif
}
void cleanup_module(void)
{
-
-#ifdef CARDBUS
- unregister_driver(ðerdev_ops);
-#endif
+ struct device *next_dev;
/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
while (root_net_dev) {
- struct netdev_private *np =
- (struct netdev_private *)(root_net_dev->priv);
+ struct netdev_private *np = (void *)(root_net_dev->priv);
unregister_netdev(root_net_dev);
-#ifdef VIA_USE_IO
+#ifdef USE_IO_OPS
release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);
#else
iounmap((char *)(root_net_dev->base_addr));
#endif
+ next_dev = np->next_module;
+ if (np->priv_addr)
+ kfree(np->priv_addr);
kfree(root_net_dev);
- root_net_dev = np->next_module;
-#if 0
- kfree(np); /* Assumption: no struct realignment. */
-#endif
+ root_net_dev = next_dev;
}
}
int
init_module ( void )
{
- int rc=0;
return dasd_init();
- return rc;
}
void
int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
int dasd_oper_handler ( int irq, devreg_t *devreg );
+dasd_era_t dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*/
+#include <linux/blkdev.h>
#include <asm/ccwcache.h>
#include <asm/dasd.h>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*/
+#include <linux/blkdev.h>
#include <asm/ccwcache.h>
#include <asm/dasd.h>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*/
+#include <linux/blkdev.h>
#include <asm/ccwcache.h>
#include <asm/dasd.h>
dasd_era_t
dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
{
- char *sense = stat->ii.sense.data;
-
/* check for successful execution first */
if (stat->cstat == 0x00 &&
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
*/
+#include <linux/blkdev.h>
#include <asm/ccwcache.h>
#include <asm/dasd.h>
eckd_count_t count_area;
} dasd_eckd_private_t;
+#ifdef CONFIG_DASD_DYNAMIC
static
devreg_t dasd_eckd_known_devices[] = {
{
oper_func: dasd_oper_handler
}
};
+#endif
static inline unsigned int
round_up_multiple (unsigned int no, unsigned int mult)
int
dasd_eckd_init( void ) {
int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
int i;
+#endif
printk ( KERN_INFO PRINTK_HEADER
"%s discipline initializing\n", dasd_eckd_discipline.name);
ASCEBC(dasd_eckd_discipline.ebcname,4);
void
dasd_eckd_cleanup( void ) {
- int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
int i;
+#endif
printk ( KERN_INFO PRINTK_HEADER
"%s discipline cleaning up\n", dasd_eckd_discipline.name);
#ifdef CONFIG_DASD_DYNAMIC
}
#endif /* CONFIG_DASD_DYNAMIC */
dasd_discipline_deq(&dasd_eckd_discipline);
- return rc;
+ return;
}
/*
} __attribute__ ((packed)) dasd_eckd_confdata_t;
int dasd_eckd_init( void );
+void dasd_eckd_cleanup( void );
#endif /* DASD_ECKD_H */
int rc = 0;
unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
unsigned long tracks = sectors >> 6;
- unsigned long trk_rem = sectors & ((1<<6)-1);
unsigned long cyls = tracks >> 4;
- unsigned long cyls_rem = tracks & ((1<<4)-1);
switch(device->sizes.bp_block) {
case 512:
int
dasd_fba_init( void ) {
int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
int i;
+#endif
printk ( KERN_INFO PRINTK_HEADER
"%s discipline initializing\n", dasd_fba_discipline.name);
ASCEBC(dasd_fba_discipline.ebcname,4);
void
dasd_fba_cleanup( void ) {
- int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
int i;
+#endif
printk ( KERN_INFO PRINTK_HEADER
"%s discipline cleaning up\n", dasd_fba_discipline.name);
#ifdef CONFIG_DASD_DYNAMIC
}
#endif /* CONFIG_DASD_DYNAMIC */
dasd_discipline_deq(&dasd_fba_discipline);
- return rc;
+ return;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
} __attribute__ ((packed)) dasd_fba_characteristics_t;
int dasd_fba_init( void );
+void dasd_fba_cleanup( void );
#endif /* DASD_FBA_H */
long blksize[MDISK_DEVS];
} mdisk_setup_data;
+/*
+ * The 'low level' IO function
+ */
+
+static __inline__ int
+dia250(void* iob,int cmd)
+{
+ int rc;
+
+ iob = (void*) virt_to_phys(iob);
+
+ asm volatile (" lr 2,%1\n"
+ " lr 3,%2\n"
+ " .long 0x83230250\n"
+ " lr %0,3"
+ : "=d" (rc)
+ : "d" (iob) , "d" (cmd)
+ : "2", "3" );
+ return rc;
+}
+
+/*
+ * The device characteristics function
+ */
+
+static __inline__ int
+dia210(void* devchar)
+{
+ int rc;
+
+ devchar = (void*) virt_to_phys(devchar);
+
+ asm volatile (" lr 2,%1\n"
+ " .long 0x83200210\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (rc)
+ : "d" (devchar)
+ : "2" );
+ return rc;
+}
+
+
+/*
+ * release of minidisk device
+ */
+
+static __inline__ int
+mdisk_term_io(mdisk_Dev *dev)
+{
+ mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+
+ memset(iob,0,sizeof(mdisk_init_io_t));
+
+ iob->dev_nr = dev->vdev;
+
+ return dia250(iob,TERM_BIO);
+}
+
+
+/*
+ * Init of minidisk device
+ */
+
+static __inline__ int
+mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size)
+{
+ mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+ int rc;
+
+ memset(iob,0,sizeof(mdisk_init_io_t));
+
+ iob->dev_nr = dev->vdev;
+ iob->block_size = blocksize;
+ iob->offset = offset;
+ iob->start_block= 0;
+ iob->end_block = size;
+
+ rc = dia250(iob,INIT_BIO);
+
+ /*
+ * clear for following io once
+ */
+
+ memset(iob,0,sizeof(mdisk_rw_io_t));
+
+ return rc;
+}
+
+
+/*
+ * setup and start of minidisk io request
+ */
+
+static __inline__ int
+mdisk_rw_io_clustered (mdisk_Dev *dev,
+ mdisk_bio_t* bio_array,
+ int length,
+ int req,
+ int sync)
+{
+ int rc;
+ mdisk_rw_io_t *iob = dev->iob;
+
+ iob->dev_nr = dev->vdev;
+ iob->key = 0;
+ iob->flags = sync;
+
+ iob->block_count = length;
+ iob->interrupt_params = req;
+ iob->bio_list = virt_to_phys(bio_array);
+
+ rc = dia250(iob,RW_BIO);
+ return rc;
+}
+
/*
* Parameter parsing function, called from init/main.c
* vdev : virtual device number
{
char *cur = str;
int vdev, size, offset=0,blksize;
- static i = 0;
+static int i = 0;
if (!i)
memset(&mdisk_setup_data,0,sizeof(mdisk_setup_data));
NULL, /* mdisk_lock */
};
-/*
- * The 'low level' IO function
- */
-
-
-static __inline__ int
-dia250(void* iob,int cmd)
-{
- int rc;
-
- iob = (void*) virt_to_phys(iob);
-
- asm volatile (" lr 2,%1\n"
- " lr 3,%2\n"
- " .long 0x83230250\n"
- " lr %0,3"
- : "=d" (rc)
- : "d" (iob) , "d" (cmd)
- : "2", "3" );
- return rc;
-}
-
-/*
- * The device characteristics function
- */
-
-static __inline__ int
-dia210(void* devchar)
-{
- int rc;
-
- devchar = (void*) virt_to_phys(devchar);
- asm volatile (" lr 2,%1\n"
- " .long 0x83200210\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (rc)
- : "d" (devchar)
- : "2" );
- return rc;
-}
/*
* read the label of a minidisk and extract its characteristics
*/
}
-
-/*
- * Init of minidisk device
- */
-
-static __inline__ int
-mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size)
-{
- mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
- int rc;
-
- memset(iob,0,sizeof(mdisk_init_io_t));
-
- iob->dev_nr = dev->vdev;
- iob->block_size = blocksize;
- iob->offset = offset;
- iob->start_block= 0;
- iob->end_block = size;
-
- rc = dia250(iob,INIT_BIO);
-
- /*
- * clear for following io once
- */
-
- memset(iob,0,sizeof(mdisk_rw_io_t));
-
- return rc;
-}
-
-/*
- * release of minidisk device
- */
-
-static __inline__ int
-mdisk_term_io(mdisk_Dev *dev)
-{
- mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
-
- memset(iob,0,sizeof(mdisk_init_io_t));
-
- iob->dev_nr = dev->vdev;
-
- return dia250(iob,TERM_BIO);
-}
-
-/*
- * setup and start of minidisk io request
- */
-
-static __inline__ int
-mdisk_rw_io_clustered (mdisk_Dev *dev,
- mdisk_bio_t* bio_array,
- int length,
- int req,
- int sync)
-{
- int rc;
- mdisk_rw_io_t *iob = dev->iob;
-
- iob->dev_nr = dev->vdev;
- iob->key = 0;
- iob->flags = sync;
-
- iob->block_count = length;
- iob->interrupt_params = req;
- iob->bio_list = virt_to_phys(bio_array);
-
- rc = dia250(iob,RW_BIO);
- return rc;
-}
-
-
-
/*
* this handles a clustered request in success case
* all buffers are detach and marked uptodate to the kernel
*/
void do_mdisk_interrupt(struct pt_regs *regs, __u16 code)
{
- u16 code;
mdisk_Dev *dev;
- code = S390_lowcore.cpu_addr;
-
if ((code >> 8) != 0x03) {
printk("mnd: wrong sub-interruption code %d",code>>8);
return;
* along with this kernel; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
- * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test4 *
+ * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test10 *
* *
* $Log: gdth.c,v $
+ * Revision 1.45 2000/11/16 12:02:24 achim
+ * Changes for kernel 2.4
+ *
+ * Revision 1.44 2000/10/11 08:44:10 achim
+ * Clustering changes: New flag media_changed added
+ *
+ * Revision 1.43 2000/09/20 12:59:01 achim
+ * DPMEM remap functions for all PCI controller types implemented
+ * Small changes for ia64 platform
+ *
* Revision 1.42 2000/07/20 09:04:50 achim
* Small changes for kernel 2.4
*
* Initial revision
*
************************************************************************/
-#ident "$Id: gdth.c,v 1.42 2000/07/20 09:04:50 achim Exp $"
+#ident "$Id: gdth.c,v 1.45 2000/11/16 12:02:24 achim Exp $"
/* All GDT Disk Array Controllers are fully supported by this driver.
* This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
return 0;
}
+ /* check and reset interface area */
dp6_ptr = (gdt6_dpram_str *)ha->brd;
- /* reset interface area */
+ gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+ printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
+ pcistr->dpmem);
+ found = FALSE;
+ for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+ gdth_munmap(ha->brd);
+ ha->brd = gdth_mmap(i, sizeof(ushort));
+ if (ha->brd == NULL) {
+ printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+ return 0;
+ }
+ if (gdth_readw(ha->brd) != 0xffff) {
+ TRACE2(("init_pci_old() address 0x%x busy\n", i));
+ continue;
+ }
+ gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+ pci_write_config_dword(pcistr->pdev,
+ PCI_BASE_ADDRESS_0, i);
+#else
+ pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+ PCI_BASE_ADDRESS_0, i);
+#endif
+ ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str));
+ if (ha->brd == NULL) {
+ printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+ return 0;
+ }
+ dp6_ptr = (gdt6_dpram_str *)ha->brd;
+ gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+ if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+ printk("GDT-PCI: Use free address at 0x%x\n", i);
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ printk("GDT-PCI: No free address found!\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ }
memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
if (gdth_readl(&dp6_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
gdth_munmap(ha->brd);
return 0;
}
+ /* check and reset interface area */
dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
- /* reset interface area */
+ gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+ printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n",
+ pcistr->dpmem);
+ found = FALSE;
+ for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+ gdth_munmap(ha->brd);
+ ha->brd = gdth_mmap(i, sizeof(ushort));
+ if (ha->brd == NULL) {
+ printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+ return 0;
+ }
+ if (gdth_readw(ha->brd) != 0xffff) {
+ TRACE2(("init_pci_plx() address 0x%x busy\n", i));
+ continue;
+ }
+ gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+ pci_write_config_dword(pcistr->pdev,
+ PCI_BASE_ADDRESS_2, i);
+#else
+ pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+ PCI_BASE_ADDRESS_2, i);
+#endif
+ ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str));
+ if (ha->brd == NULL) {
+ printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+ return 0;
+ }
+ dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+ gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+ if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+ printk("GDT-PCI: Use free address at 0x%x\n", i);
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) {
+ printk("GDT-PCI: No free address found!\n");
+ gdth_munmap(ha->brd);
+ return 0;
+ }
+ }
memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
if (gdth_readl(&dp6c_ptr->u) != 0) {
printk("GDT-PCI: Initialization error (DPMEM write error)\n");
TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
/* set/get features raw service (scatter/gather) */
- ha->raw_feat = 0;
if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
0,0)) {
TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
hdrive,ha->info));
ha->hdr[hdrive].cluster_type = (unchar)ha->info;
- } else {
- ha->hdr[hdrive].cluster_type = 0;
- }
+ }
/* R/W attributes */
if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
hdrive,ha->info));
ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
- } else {
- ha->hdr[hdrive].rw_attribs = 0;
- }
+ }
return 1;
}
TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
nscp->cmnd[0], b, t, nscp->lun));
nscp->result = DID_BAD_TARGET << 16;
- GDTH_UNLOCK_HA(ha,flags);
- /* io_request_lock already active ! */
- nscp->scsi_done(nscp);
- GDTH_LOCK_HA(ha,flags);
+ if (!nscp->SCp.have_data_in)
+ nscp->SCp.have_data_in++;
+ else {
+ GDTH_UNLOCK_HA(ha,flags);
+ /* io_request_lock already active ! */
+ nscp->scsi_done(nscp);
+ GDTH_LOCK_HA(ha,flags);
+ }
} else {
switch (nscp->cmnd[0]) {
case TEST_UNIT_READY:
TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
nscp->cmnd[4],nscp->cmnd[5]));
- if (gdth_internal_cache_cmd(hanum,nscp)) {
+ if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) {
+ /* return UNIT_ATTENTION */
+ TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+ nscp->cmnd[0], t));
+ ha->hdr[t].media_changed = FALSE;
+ memset((char*)nscp->sense_buffer,0,16);
+ nscp->sense_buffer[0] = 0x70;
+ nscp->sense_buffer[2] = UNIT_ATTENTION;
+ nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ if (!nscp->SCp.have_data_in)
+ nscp->SCp.have_data_in++;
+ else {
+ GDTH_UNLOCK_HA(ha,flags);
+ /* io_request_lock already active ! */
+ nscp->scsi_done(nscp);
+ GDTH_LOCK_HA(ha,flags);
+ }
+ } else if (gdth_internal_cache_cmd(hanum,nscp)) {
GDTH_UNLOCK_HA(ha,flags);
/* io_request_lock already active ! */
nscp->scsi_done(nscp);
case WRITE_6:
case READ_10:
case WRITE_10:
- if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+ if (ha->hdr[t].media_changed) {
+ /* return UNIT_ATTENTION */
+ TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+ nscp->cmnd[0], t));
+ ha->hdr[t].media_changed = FALSE;
+ memset((char*)nscp->sense_buffer,0,16);
+ nscp->sense_buffer[0] = 0x70;
+ nscp->sense_buffer[2] = UNIT_ATTENTION;
+ nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ if (!nscp->SCp.have_data_in)
+ nscp->SCp.have_data_in++;
+ else {
+ GDTH_UNLOCK_HA(ha,flags);
+ /* io_request_lock already active ! */
+ nscp->scsi_done(nscp);
+ GDTH_LOCK_HA(ha,flags);
+ }
+ } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
this_cmd = FALSE;
break;
TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
break;
}
+
scp->result = DID_OK << 16;
scp->sense_buffer[0] = 0;
register gdth_ha_str *ha;
register gdth_cmd_str *cmdp;
struct scatterlist *sl;
- ushort i;
+ ushort i, cnt;
+ ulong32 no;
int cmd_index, read_write;
ha = HADATA(gdth_ctr_tab[hanum]);
if (read_write) {
if (scp->cmd_len != 6) {
- cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]);
- cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]);
+ memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
+ cmdp->u.cache.BlockNo = ntohl(no);
+ memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
+ cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt);
} else {
- cmdp->u.cache.BlockNo =
- ntohl(*(ulong32*)&scp->cmnd[0]) & 0x001fffffUL;
+ memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
+ cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL;
cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
}
cmdp->u.raw.lun = l;
cmdp->u.raw.bus = b;
cmdp->u.raw.priority = 0;
- cmdp->u.raw.link_p = NULL;
+ cmdp->u.raw.link_p = 0;
cmdp->u.raw.sdlen = scp->request_bufflen;
cmdp->u.raw.sense_len = 16;
cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
e->first_stamp = e->last_stamp = tv.tv_sec;
e->same_count = 1;
e->event_data = *evt;
+ e->application = 0;
}
return e;
}
if (!(ha->hdr[scp->target].cluster_type &
CLUSTER_MOUNTED)) {
/* NOT MOUNTED -> MOUNT */
- if (!(ha->hdr[scp->target].cluster_type &
- CLUSTER_RESERVED)) {
- /* cluster drive NOT RESERVED */
- scp->SCp.Status = GDT_MOUNT;
- } else {
+ scp->SCp.Status = GDT_MOUNT;
+ if (ha->hdr[scp->target].cluster_type &
+ CLUSTER_RESERVED) {
/* cluster drive RESERVED (on the other node) */
- scp->SCp.Status = GDT_MOUNT;
scp->SCp.phase = -2; /* reservation conflict */
}
} else {
scp->SCp.Status = -1;
}
- /* retry */
- scp->SCp.this_residual = HIGH_PRI;
- return 2;
- } else if (scp->SCp.Status == GDT_MOUNT) {
- ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+ } else {
+ if (scp->SCp.Status == GDT_MOUNT) {
+ ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+ ha->hdr[scp->target].media_changed = TRUE;
+ } else if (scp->SCp.Status == GDT_UNMOUNT) {
+ ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED;
+ ha->hdr[scp->target].media_changed = TRUE;
+ }
scp->SCp.Status = -1;
- /* return UNIT_ATTENTION */
- memset((char*)scp->sense_buffer,0,16);
- scp->sense_buffer[0] = 0x70;
- scp->sense_buffer[2] = UNIT_ATTENTION;
- scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- scp->SCp.Message = (int)(ha->info<<16|S_BSY);
- } else {
- scp->SCp.Status = -1;
- /* retry */
- scp->SCp.this_residual = HIGH_PRI;
- return 2;
}
+ /* retry */
+ scp->SCp.this_residual = HIGH_PRI;
+ return 2;
} else {
/* RESERVE/RELEASE ? */
if (scp->cmnd[0] == RESERVE) {
scp->sense_buffer[0] = 0x70;
scp->sense_buffer[2] = NOT_READY;
scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- } else if (scp->cmnd[0] == RESERVE ||
- scp->cmnd[0] == RELEASE) {
- memset((char*)scp->sense_buffer,0,16);
- scp->sense_buffer[0] = 0x70;
- scp->sense_buffer[2] = NOT_READY;
- scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
} else if (service == CACHESERVICE) {
if (ha->status == S_CACHE_UNKNOWN &&
(ha->hdr[scp->target].cluster_type &
}
} else {
/* sense buffer filled from controller firmware (DMA) */
- if (ha->status!=S_RAW_SCSI || ha->info>=0x100) {
+ if (ha->status != S_RAW_SCSI || ha->info >= 0x100) {
scp->result = DID_BAD_TARGET << 16;
} else {
scp->result = (DID_OK << 16) | ha->info;
}
}
-
+#if LINUX_VERSION_CODE < 0x020400
#ifdef MODULE
Scsi_Host_Template driver_template = GDTH;
#include "scsi_module.c"
#endif
+#else
+Scsi_Host_Template driver_template = GDTH;
+#include "scsi_module.c"
+#endif
*
* <achim@vortex.de>
*
- * $Id: gdth.h,v 1.33 2000/07/24 09:29:25 achim Exp $
+ * $Id: gdth.h,v 1.35 2000/10/11 08:42:38 achim Exp $
*/
#include <linux/version.h>
/* defines, macros */
/* driver version */
-#define GDTH_VERSION_STR "1.23"
+#define GDTH_VERSION_STR "1.25"
#define GDTH_VERSION 1
-#define GDTH_SUBVERSION 23
+#define GDTH_SUBVERSION 25
/* protocol version */
#define PROTOCOL_VERSION 1
unchar priority; /* only 0 used */
ulong32 sense_len; /* sense data length */
ulong32 sense_data; /* sense data addr. */
- struct raw *link_p; /* linked cmds (not supp.) */
+ ulong32 link_p; /* linked cmds (not supp.) */
ulong32 sg_ranz; /* s/g element count */
gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */
} PACKED raw; /* raw service cmd. struct. */
Scsi_Cmnd *req_first; /* top of request queue */
struct {
unchar present; /* Flag: host drive present? */
- unchar is_logdrv; /* Flag: logical drive (master)? */
+ unchar is_logdrv; /* Flag: log. drive (master)? */
unchar is_arraydrv; /* Flag: array drive? */
unchar is_master; /* Flag: array drive master? */
unchar is_parity; /* Flag: parity drive? */
unchar ldr_no; /* log. drive no. */
unchar rw_attribs; /* r/w attributes */
unchar cluster_type; /* cluster properties */
- unchar reserved;
+ unchar media_changed; /* Flag:MOUNT/UNMOUNT occured */
ulong32 start_sec; /* start sector */
} hdr[MAX_LDRIVES]; /* host drives */
struct {
#define _GDTH_IOCTL_H
/* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.6 2000/07/24 09:29:43 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.7 2000/10/11 08:43:35 achim Exp $
*/
/* IOCTLs */
#define GDTIOCTL_SCSI (GDTIOCTL_MASK | 9) /* SCSI command */
#define GDTIOCTL_RESET_BUS (GDTIOCTL_MASK |10) /* reset SCSI bus */
#define GDTIOCTL_RESCAN (GDTIOCTL_MASK |11) /* rescan host drives */
+#define GDTIOCTL_RESET_DRV (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
#define GDTIOCTL_MAGIC 0xaffe0003UL
#define EVENT_SIZE 294
/* gdth_proc.c
- * $Id: gdth_proc.c,v 1.22 2000/07/24 09:30:28 achim Exp $
+ * $Id: gdth_proc.c,v 1.23 2000/10/11 08:43:11 achim Exp $
*/
#include "gdth_ioctl.h"
GDTH_UNLOCK_HA(ha, flags);
break;
+ case GDTIOCTL_RESET_DRV:
+ if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+ return(-EBUSY);
+ piord = (gdth_iord_str *)ha->pscratch;
+ piord->size = sizeof(gdth_iord_str);
+ piord->status = S_OK;
+ i = piowr->iu.scsi.target;
+ if (ha->hdr[i].present) {
+ gdtcmd.BoardNode = LOCALBOARD;
+ gdtcmd.Service = CACHESERVICE;
+ gdtcmd.OpCode = GDT_CLUST_RESET;
+ gdtcmd.u.cache.DeviceNo = i;
+ gdtcmd.u.cache.BlockNo = 0;
+ gdtcmd.u.cache.sg_canz = 0;
+#if LINUX_VERSION_CODE >= 0x020322
+ gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+ piord->status = (ulong32)scp->SCp.Message;
+#else
+ gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+ piord->status = (ulong32)scp.SCp.Message;
+#endif
+ }
+ break;
+
default:
return(-EINVAL);
}
(inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
{
int flags;
- save_flags(flags);
printk("Ux4F: abort while completed command pending\n");
- restore_flags(flags);
+ save_flags(flags);
cli();
ultrastor_interrupt(0, NULL, NULL);
restore_flags(flags);
fi
dep_tristate 'NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
- dep_tristate 'Yamaha PCI legacy mode support' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS
- if [ "$CONFIG_SOUND_YMPCI" = "n" ]; then
- dep_tristate 'Yamaha PCI native mode support (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS
- fi
+ dep_tristate 'Yamaha PCI native mode support (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS
# Additional low level drivers.
obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o
+obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o uart401.o
ifeq ($(CONFIG_SOUND_EMU10K1),y)
obj-y += emu10k1/emu10k1.o
wavefront-objs := wavfront.o wf_midi.o yss225.o
nm256-objs := nm256_audio.o ac97.o
via82cxxx-objs := via82cxxx_audio.o ac97.o
-ymfsb-objs := ymf_sb.o ac97.o
# Extract lists of the multi-part drivers.
via82cxxx.o: $(via82cxxx-objs)
$(LD) -r -o $@ $(via82cxxx-objs)
-ymfsb.o: $(ymfsb-objs)
- $(LD) -r -o $@ $(ymfsb-objs)
-
# Firmware files that need translation
#
# The translated files are protected by a file that keeps track
module_init(emu10k1_init_module);
module_exit(emu10k1_cleanup_module);
-
-#ifndef MODULE
-int __init init_emu10k1(void)
-{
- return emu10k1_init_module();
-}
-#endif
* 03.09.1999 0.30 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
* 28.10.1999 0.31 More waitqueue races fixed
+ * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ * 12.12.2000 0.35 More dma buffer initializations, patch from
+ * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
*
* some important things missing in Ensoniq documentation:
*
VALIDATE_STATE(s);
if (cmd == SOUND_MIXER_PRIVATE1) {
/* enable/disable/query mixer preamp */
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != -1) {
s->mix.micpreamp = !!val;
wrcodec(s, 0x19, s->mix.micpreamp);
}
if (cmd == SOUND_MIXER_PRIVATE2) {
/* enable/disable/query use of linein as second lineout */
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != -1) {
spin_lock_irqsave(&s->lock, flags);
if (val)
}
if (cmd == SOUND_MIXER_PRIVATE3) {
/* enable/disable/query microphone impedance setting */
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != -1) {
spin_lock_irqsave(&s->lock, flags);
if (val)
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_IMIX:
- get_user_ret(s->mix.imix, (int *)arg, -EFAULT);
+ if (get_user(s->mix.imix, (int *)arg))
+ return -EFAULT;
set_recsrc(s, s->mix.recsrc);
return 0;
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
set_recsrc(s, val);
return 0;
i = _IOC_NR(cmd);
if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
l = val & 0xff;
if (l > 100)
l = 100;
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
VALIDATE_STATE(s);
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
return -EINVAL;
return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
- abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac2.dmasize - count;
abinfo.fragstotal = s->dma_dac2.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
- val = s->dma_dac2.count;
+ count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
- cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac2.fragshift;
cinfo.ptr = s->dma_dac2.hwptr;
if (s->dma_dac2.mapped)
s->dma_dac2.count &= s->dma_dac2.fragsize-1;
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
(file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
unsigned ctrl;
int val, ret;
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
stop_dac1(s);
s->dma_dac1.ready = 0;
return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
stop_dac1(s);
s->dma_dac1.ready = 0;
spin_lock_irqsave(&s->lock, flags);
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
if (s->dma_dac1.mapped)
return -EINVAL;
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
stop_dac1(s);
s->dma_dac1.ready = 0;
return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val & PCM_ENABLE_OUTPUT) {
if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
return ret;
return 0;
case SNDCTL_DSP_GETOSPACE:
- if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_dac1.fragsize;
- abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac1.dmasize - count;
abinfo.fragstotal = s->dma_dac1.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
return 0;
case SNDCTL_DSP_GETODELAY:
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
- val = s->dma_dac1.count;
+ count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_dac1.total_bytes;
- cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac1.fragshift;
cinfo.ptr = s->dma_dac1.hwptr;
if (s->dma_dac1.mapped)
s->dma_dac1.count &= s->dma_dac1.fragsize-1;
return put_user(s->dma_dac1.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
s->dma_dac1.ossfragshift = val & 0xffff;
s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
if (s->dma_dac1.ossfragshift < 4)
case SNDCTL_DSP_SUBDIVIDE:
if (s->dma_dac1.subdivision)
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
s->dma_dac1.subdivision = val;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1370: version v0.35 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
if (pcidev->base_address[0] == 0 ||
* detect ES137x chip and derivatives.
* 05.01.2000 0.22 Should now work with rev7 boards; patch by
* Eric Lemar, elemar@cs.washington.edu
+ * 08.01.2000 0.23 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * 01.03.2000 0.26 SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com>
+ * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ * 12.12.2000 0.28 More dma buffer initializations, patch from
+ * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
*/
/*****************************************************************************/
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
VALIDATE_STATE(s);
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
stop_adc(s);
s->dma_adc.ready = 0;
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
- abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac2.dmasize - count;
abinfo.fragstotal = s->dma_dac2.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
- val = s->dma_dac2.count;
+ count = s->dma_dac2.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
- cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+ count = s->dma_dac2.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac2.fragshift;
cinfo.ptr = s->dma_dac2.hwptr;
if (s->dma_dac2.mapped)
s->dma_dac2.count &= s->dma_dac2.fragsize-1;
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
(file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, ret;
VALIDATE_STATE(s);
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
stop_dac1(s);
s->dma_dac1.ready = 0;
return put_user(s->dac1rate, (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
stop_dac1(s);
s->dma_dac1.ready = 0;
spin_lock_irqsave(&s->lock, flags);
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
stop_dac1(s);
s->dma_dac1.ready = 0;
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
stop_dac1(s);
s->dma_dac1.ready = 0;
return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val & PCM_ENABLE_OUTPUT) {
if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
return ret;
return 0;
case SNDCTL_DSP_GETOSPACE:
- if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_dac1.fragsize;
- abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac1.dmasize - count;
abinfo.fragstotal = s->dma_dac1.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
return 0;
case SNDCTL_DSP_GETODELAY:
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
- val = s->dma_dac1.count;
+ count = s->dma_dac1.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
+ if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_dac1.total_bytes;
- cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+ count = s->dma_dac1.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac1.fragshift;
cinfo.ptr = s->dma_dac1.hwptr;
if (s->dma_dac1.mapped)
s->dma_dac1.count &= s->dma_dac1.fragsize-1;
return put_user(s->dma_dac1.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
s->dma_dac1.ossfragshift = val & 0xffff;
s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
if (s->dma_dac1.ossfragshift < 4)
case SNDCTL_DSP_SUBDIVIDE:
if (s->dma_dac1.subdivision)
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
s->dma_dac1.subdivision = val;
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "es1371: version v0.28 time " __TIME__ " " __DATE__ "\n");
for (pcidev = pci_devices; pcidev && index < NR_DEVICE; pcidev = pcidev->next) {
if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) {
if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 &&
* 28.10.1999 0.10 More waitqueue races fixed
* 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
* Disabling recording on Alpha
- *
+ * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * Integrated (aka redid 8-)) APM support patch by Zach Brown
+ * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ * 12.12.2000 0.17 More dma buffer initializations, patch from
+ * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
*/
/*****************************************************************************/
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
stop_adc(s);
stop_dac(s);
return put_user(s->rate, (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
stop_adc(s);
stop_dac(s);
s->dma_adc.ready = s->dma_dac.ready = 0;
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
stop_adc(s);
stop_dac(s);
return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
stop_adc(s);
stop_dac(s);
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
count = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
+ cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac.fragshift;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
(file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "solo1: version v0.17 time " __TIME__ " " __DATE__ "\n");
while (index < NR_DEVICE &&
(pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
if (pcidev->base_address[0] == 0 ||
* 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource
* 31.08.1999 0.20 add spin_lock_init
* __initlocaldata to fix gcc 2.7.x problems
- * use new resource allocation to allocate DDMA IO space
* replaced current->state = x with set_current_state(x)
* 03.09.1999 0.21 change read semantics for MIDI to match
* OSS more closely; remove possible wakeup race
* 28.10.1999 0.22 More waitqueue races fixed
+ * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
+ * Tim Janik's BSE (Bedevilled Sound Engine) found this
+ * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ * 12.12.2000 0.28 More dma buffer initializations, patch from
+ * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
*
*/
unsigned long flags;
audio_buf_info abinfo;
count_info cinfo;
+ int count;
int val, mapped, ret;
unsigned char fmtm, fmtd;
return 0;
case SNDCTL_DSP_SPEED:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val >= 0) {
if (file->f_mode & FMODE_READ) {
stop_adc(s);
return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
case SNDCTL_DSP_STEREO:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
fmtd = 0;
fmtm = ~0;
if (file->f_mode & FMODE_READ) {
return 0;
case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 0) {
fmtd = 0;
fmtm = ~0;
return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != AFMT_QUERY) {
fmtd = 0;
fmtm = ~0;
return put_user(val, (int *)arg);
case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->enable & SV_CENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
+ if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = s->dma_dac.dmasize - count;
abinfo.fragstotal = s->dma_dac.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & SV_CENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
+ if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
return val;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ abinfo.bytes = count;
abinfo.fragstotal = s->dma_adc.numfrag;
abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
spin_unlock_irqrestore(&s->lock, flags);
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
- val = s->dma_dac.count;
+ count = s->dma_dac.count;
spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
+ if (count < 0)
+ count = 0;
+ return put_user(count, (int *)arg);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+ count = s->dma_adc.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_adc.fragshift;
cinfo.ptr = s->dma_adc.hwptr;
if (s->dma_adc.mapped)
s->dma_adc.count &= s->dma_adc.fragsize-1;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+ return val;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+ count = s->dma_dac.count;
+ if (count < 0)
+ count = 0;
+ cinfo.blocks = count >> s->dma_dac.fragshift;
cinfo.ptr = s->dma_dac.hwptr;
if (s->dma_dac.mapped)
s->dma_dac.count &= s->dma_dac.fragsize-1;
return put_user(s->dma_adc.fragsize, (int *)arg);
case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (file->f_mode & FMODE_READ) {
s->dma_adc.ossfragshift = val & 0xffff;
s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
(file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
return -EINVAL;
- get_user_ret(val, (int *)arg, -EFAULT);
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
if (val != 1 && val != 2 && val != 4)
return -EINVAL;
if (file->f_mode & FMODE_READ)
if (!pci_present()) /* No PCI bus in this machine! */
return -ENODEV;
- printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "sv: version v0.28 time " __TIME__ " " __DATE__ "\n");
#if 0
if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
extern int init_solo1(void);
extern int init_ymf7xxsb_module(void);
extern int cs_probe(void);
-extern int init_emu10k1(void);
extern int cs4281_probe(void);
extern void init_vwsnd(void);
extern int ymf_probe(void);
#ifdef CONFIG_SOUND_CS4281
cs4281_probe();
#endif
-#ifdef CONFIG_SOUND_EMU10K1
- init_emu10k1();
-#endif
#ifdef CONFIG_SOUND_YMFPCI
ymf_probe();
#endif
+++ /dev/null
-/*
- Legacy audio driver for YMF724, 740, 744, 754 series.
- Copyright 2000 Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
- Based on the VIA 82Cxxx driver by Jeff Garzik <jgarzik@pobox.com>
-
- Distribued under the GNU PUBLIC LICENSE (GPL) Version 2.
- See the "COPYING" file distributed with kernel source tree for more info.
-
- -------------------------------------------------------------------------
-
- It only supports SBPro compatible function of YMF7xx series s.t.
- * 22.05kHz, 8-bit and stereo sample
- * OPL3-compatible FM synthesizer
- * MPU-401 compatible "external" MIDI interface
-
- and AC'97 mixer of these cards.
-
- -------------------------------------------------------------------------
-
- Revision history
-
- Tue May 14 19:00:00 2000 0.0.1
- * initial release
-
- Tue May 16 19:29:29 2000 0.0.2
-
- * add a little delays for reset devices.
- * fixed addressing bug.
-
- Sun May 21 15:14:37 2000 0.0.3
-
- * Add 'master_vol' module parameter to change 'PCM out Vol' of AC'97.
- * remove native UART401 support. External MIDI port should be supported
- by sb_midi driver.
- * add support for SPDIF OUT. Module parameter 'spdif_out' is now available.
-
- Wed May 31 00:13:57 2000 0.0.4
-
- * remove entries in Hwmcode.h. Now YMF744 / YMF754 sets instructions
- in 724hwmcode.h.
- * fixed wrong legacy_io setting on YMF744/YMF754 .
-
- Sat Jun 3 23:44:08 2000 0.0.5
-
- * correct all return value -1 to appropriate -E* value.
- * add pci_enable_device() for linux-2.3.x.
-
- Sat Jun 7 00:17:32 2000 0.1.0
-
- * Remove SBPro mixer support.
- * Added AC'97 mixer support and remove option 'master_volume'.
- * Correct all separated valuables into struct ymf_cards.
-
- Mon Jun 12 21:36:50 2000 0.1.1
-
- * Invalid dma setting fixed.
- -- John A. Boyd Jr. <jaboydjr@netwalk.com>
-
- * ymfsb only compiled as module: fixed
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "sound_config.h"
-#include "soundmodule.h"
-#include "sb.h"
-#include "724hwmcode.h"
-
-#include "ac97.h"
-
-#undef YMF_DEBUG
-
-/* ---------------------------------------------------------------------- */
-
-#ifndef SOUND_LOCK
-# define SOUND_LOCK do {} while (0)
-# define SOUND_LOCK_END do {} while (0)
-#endif
-
-#ifndef PCI_VENDOR_ID_YAMAHA
-# define PCI_VENDOR_ID_YAMAHA 0x1073
-#endif
-#ifndef PCI_DEVICE_ID_YMF724
-# define PCI_DEVICE_ID_YMF724 0x0004
-#endif
-#ifndef PCI_DEVICE_ID_YMF740
-# define PCI_DEVICE_ID_YMF740 0x000A
-#endif
-#ifndef PCI_DEVICE_ID_YMF740C
-# define PCI_DEVICE_ID_YMF740C 0x000C
-#endif
-#ifndef PCI_DEVICE_ID_YMF724F
-# define PCI_DEVICE_ID_YMF724F 0x000D
-#endif
-#ifndef PCI_DEVICE_ID_YMF744
-# define PCI_DEVICE_ID_YMF744 0x0010
-#endif
-#ifndef PCI_DEVICE_ID_YMF754
-# define PCI_DEVICE_ID_YMF754 0x0012
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-#define YMFSB_RESET_DELAY 5
-
-#define YMFSB_REGSIZE 0x8000
-
-#define YMFSB_AC97TIMEOUT 2000
-
-#define YMFSB_WORKBITTIMEOUT 250000
-
-#define YMFSB_DSPLENGTH 0x0080
-#define YMFSB_CTRLLENGTH 0x3000
-
-#define YMFSB_PCIR_VENDORID 0x00
-#define YMFSB_PCIR_DEVICEID 0x02
-#define YMFSB_PCIR_CMD 0x04
-#define YMFSB_PCIR_REVISIONID 0x08
-#define YMFSB_PCIR_BASEADDR 0x10
-#define YMFSB_PCIR_IRQ 0x3c
-
-#define YMFSB_PCIR_LEGCTRL 0x40
-#define YMFSB_PCIR_ELEGCTRL 0x42
-#define YMFSB_PCIR_DSXGCTRL 0x48
-#define YMFSB_PCIR_OPLADR 0x60
-#define YMFSB_PCIR_SBADR 0x62
-#define YMFSB_PCIR_MPUADR 0x64
-
-#define YMFSB_INTFLAG 0x0004
-#define YMFSB_ACTIVITY 0x0006
-#define YMFSB_GLOBALCTRL 0x0008
-#define YMFSB_ZVCTRL 0x000A
-#define YMFSB_TIMERCTRL 0x0010
-#define YMFSB_TIMERCOUNT 0x0012
-#define YMFSB_SPDIFOUTCTRL 0x0018
-#define YMFSB_SPDIFOUTSTATUS 0x001C
-#define YMFSB_EEPROMCTRL 0x0020
-#define YMFSB_SPDIFINCTRL 0x0034
-#define YMFSB_SPDIFINSTATUS 0x0038
-#define YMFSB_DSPPROGRAMDL 0x0048
-#define YMFSB_DLCNTRL 0x004C
-#define YMFSB_GPIOININTFLAG 0x0050
-#define YMFSB_GPIOININTENABLE 0x0052
-#define YMFSB_GPIOINSTATUS 0x0054
-#define YMFSB_GPIOOUTCTRL 0x0056
-#define YMFSB_GPIOFUNCENABLE 0x0058
-#define YMFSB_GPIOTYPECONFIG 0x005A
-#define YMFSB_AC97CMDDATA 0x0060
-#define YMFSB_AC97CMDADR 0x0062
-#define YMFSB_PRISTATUSDATA 0x0064
-#define YMFSB_PRISTATUSADR 0x0066
-#define YMFSB_SECSTATUSDATA 0x0068
-#define YMFSB_SECSTATUSADR 0x006A
-#define YMFSB_SECCONFIG 0x0070
-#define YMFSB_LEGACYOUTVOL 0x0080
-#define YMFSB_LEGACYOUTVOLL 0x0080
-#define YMFSB_LEGACYOUTVOLR 0x0082
-#define YMFSB_NATIVEDACOUTVOL 0x0084
-#define YMFSB_NATIVEDACOUTVOLL 0x0084
-#define YMFSB_NATIVEDACOUTVOLR 0x0086
-#define YMFSB_SPDIFOUTVOL 0x0088
-#define YMFSB_SPDIFOUTVOLL 0x0088
-#define YMFSB_SPDIFOUTVOLR 0x008A
-#define YMFSB_AC3OUTVOL 0x008C
-#define YMFSB_AC3OUTVOLL 0x008C
-#define YMFSB_AC3OUTVOLR 0x008E
-#define YMFSB_PRIADCOUTVOL 0x0090
-#define YMFSB_PRIADCOUTVOLL 0x0090
-#define YMFSB_PRIADCOUTVOLR 0x0092
-#define YMFSB_LEGACYLOOPVOL 0x0094
-#define YMFSB_LEGACYLOOPVOLL 0x0094
-#define YMFSB_LEGACYLOOPVOLR 0x0096
-#define YMFSB_NATIVEDACLOOPVOL 0x0098
-#define YMFSB_NATIVEDACLOOPVOLL 0x0098
-#define YMFSB_NATIVEDACLOOPVOLR 0x009A
-#define YMFSB_SPDIFLOOPVOL 0x009C
-#define YMFSB_SPDIFLOOPVOLL 0x009E
-#define YMFSB_SPDIFLOOPVOLR 0x009E
-#define YMFSB_AC3LOOPVOL 0x00A0
-#define YMFSB_AC3LOOPVOLL 0x00A0
-#define YMFSB_AC3LOOPVOLR 0x00A2
-#define YMFSB_PRIADCLOOPVOL 0x00A4
-#define YMFSB_PRIADCLOOPVOLL 0x00A4
-#define YMFSB_PRIADCLOOPVOLR 0x00A6
-#define YMFSB_NATIVEADCINVOL 0x00A8
-#define YMFSB_NATIVEADCINVOLL 0x00A8
-#define YMFSB_NATIVEADCINVOLR 0x00AA
-#define YMFSB_NATIVEDACINVOL 0x00AC
-#define YMFSB_NATIVEDACINVOLL 0x00AC
-#define YMFSB_NATIVEDACINVOLR 0x00AE
-#define YMFSB_BUF441OUTVOL 0x00B0
-#define YMFSB_BUF441OUTVOLL 0x00B0
-#define YMFSB_BUF441OUTVOLR 0x00B2
-#define YMFSB_BUF441LOOPVOL 0x00B4
-#define YMFSB_BUF441LOOPVOLL 0x00B4
-#define YMFSB_BUF441LOOPVOLR 0x00B6
-#define YMFSB_SPDIFOUTVOL2 0x00B8
-#define YMFSB_SPDIFOUTVOL2L 0x00B8
-#define YMFSB_SPDIFOUTVOL2R 0x00BA
-#define YMFSB_SPDIFLOOPVOL2 0x00BC
-#define YMFSB_SPDIFLOOPVOL2L 0x00BC
-#define YMFSB_SPDIFLOOPVOL2R 0x00BE
-#define YMFSB_ADCSLOTSR 0x00C0
-#define YMFSB_RECSLOTSR 0x00C4
-#define YMFSB_ADCFORMAT 0x00C8
-#define YMFSB_RECFORMAT 0x00CC
-#define YMFSB_P44SLOTSR 0x00D0
-#define YMFSB_STATUS 0x0100
-#define YMFSB_CTRLSELECT 0x0104
-#define YMFSB_MODE 0x0108
-#define YMFSB_SAMPLECOUNT 0x010C
-#define YMFSB_NUMOFSAMPLES 0x0110
-#define YMFSB_CONFIG 0x0114
-#define YMFSB_PLAYCTRLSIZE 0x0140
-#define YMFSB_RECCTRLSIZE 0x0144
-#define YMFSB_EFFCTRLSIZE 0x0148
-#define YMFSB_WORKSIZE 0x014C
-#define YMFSB_MAPOFREC 0x0150
-#define YMFSB_MAPOFEFFECT 0x0154
-#define YMFSB_PLAYCTRLBASE 0x0158
-#define YMFSB_RECCTRLBASE 0x015C
-#define YMFSB_EFFCTRLBASE 0x0160
-#define YMFSB_WORKBASE 0x0164
-#define YMFSB_DSPINSTRAM 0x1000
-#define YMFSB_CTRLINSTRAM 0x4000
-
-
-/* ---------------------------------------------------------------------- */
-
-#define MAX_CARDS 4
-
-#define PFX "ymf_sb: "
-
-#define YMFSB_VERSION "0.1.1"
-#define YMFSB_CARD_NAME "YMF7xx Legacy Audio driver " YMFSB_VERSION
-
-#define ymf7xxsb_probe_midi probe_sbmpu
-#define ymf7xxsb_attach_midi attach_sbmpu
-#define ymf7xxsb_unload_midi unload_sbmpu
-
-/* ---------------------------------------------------------------------- */
-
-static struct ymf_card {
- int card;
- unsigned short *ymfbase;
-
- struct address_info sb_data, opl3_data, mpu_data;
-
- struct ac97_hwint ac97_dev;
- int mixer_oss_dev;
-} ymf_cards[MAX_CARDS];
-
-static unsigned int cards = 0;
-
-/* ---------------------------------------------------------------------- */
-
-#ifdef MODULE
-static int mpu_io = 0;
-static int synth_io = 0;
-static int io = 0;
-static int dma = 0;
-static int spdif_out = 1;
-MODULE_PARM(mpu_io, "i");
-MODULE_PARM(synth_io, "i");
-MODULE_PARM(io,"i");
-MODULE_PARM(dma,"i");
-MODULE_PARM(spdif_out,"i");
-#else
-static int mpu_io = 0x330;
-static int synth_io = 0x388;
-static int io = 0x220;
-static int dma = 1;
-static int spdif_out = 1;
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-static int readRegWord( struct ymf_card *card, int adr ) {
-
- if (card->ymfbase==NULL) return 0;
-
- return readw(card->ymfbase+adr/2);
-}
-
-static void writeRegWord( struct ymf_card *card, int adr, int val ) {
-
- if (card->ymfbase==NULL) return;
-
- writew((unsigned short)(val&0xffff), card->ymfbase + adr/2);
-
- return;
-}
-
-static int readRegDWord( struct ymf_card *card, int adr ) {
-
- if (card->ymfbase==NULL) return 0;
-
- return (readl(card->ymfbase+adr/2));
-}
-
-static void writeRegDWord( struct ymf_card *card, int adr, int val ) {
-
- if (card->ymfbase==NULL) return;
-
- writel((unsigned int)(val&0xffffffff), card->ymfbase+adr/2);
-
- return;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int checkPrimaryBusy( struct ymf_card *card )
-{
- int timeout=0;
-
- while ( timeout++ < YMFSB_AC97TIMEOUT )
- {
- if ( (readRegWord(card, YMFSB_PRISTATUSADR) & 0x8000) == 0x0000 )
- return 0;
- }
- return -EBUSY;
-}
-
-static int checkCodec( struct ymf_card *card, struct pci_dev *pcidev )
-{
- u8 tmp8;
-
- pci_read_config_byte( pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8 );
- if ( tmp8 & 0x03 ) {
- pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc);
- mdelay(YMFSB_RESET_DELAY);
- pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8|0x03);
- mdelay(YMFSB_RESET_DELAY);
- pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc);
- mdelay(YMFSB_RESET_DELAY);
- }
-
- if ( checkPrimaryBusy( card ) ) return -EBUSY;
-
- return 0;
-}
-
-static int setupLegacyIO( struct ymf_card *card, struct pci_dev *pcidev )
-{
- int v;
- int sbio=0, mpuio=0, oplio=0,dma=0;
-
- switch(card->sb_data.io_base) {
- case 0x220:
- sbio = 0;
- break;
- case 0x240:
- sbio = 1;
- break;
- case 0x260:
- sbio = 2;
- break;
- case 0x280:
- sbio = 3;
- break;
- default:
- return -EINVAL;
- break;
- }
-#ifdef YMF_DEBUG
- printk(PFX "set SBPro I/O at 0x%x\n",card->sb_data.io_base);
-#endif
-
- switch(card->mpu_data.io_base) {
- case 0x330:
- mpuio = 0;
- break;
- case 0x300:
- mpuio = 1;
- break;
- case 0x332:
- mpuio = 2;
- break;
- case 0x334:
- mpuio = 3;
- break;
- default:
- mpuio = 0;
- break;
- }
-#ifdef YMF_DEBUG
- printk(PFX "set MPU401 I/O at 0x%x\n",card->mpu_data.io_base);
-#endif
-
- switch(card->opl3_data.io_base) {
- case 0x388:
- oplio = 0;
- break;
- case 0x398:
- oplio = 1;
- break;
- case 0x3a0:
- oplio = 2;
- break;
- case 0x3a8:
- oplio = 3;
- break;
- default:
- return -EINVAL;
- break;
- }
-#ifdef YMF_DEBUG
- printk(PFX "set OPL3 I/O at 0x%x\n",card->opl3_data.io_base);
-#endif
-
- dma = card->sb_data.dma;
-#ifdef YMF_DEBUG
- printk(PFX "set DMA address at 0x%x\n",card->sb_data.dma);
-#endif
-
- v = 0x0000 | ((dma&0x03)<<6) | 0x003f;
- pci_write_config_word(pcidev, YMFSB_PCIR_LEGCTRL, v);
-#ifdef YMF_DEBUG
- printk(PFX "LEGCTRL: 0x%x\n",v);
-#endif
- switch( pcidev->device ) {
- case PCI_DEVICE_ID_YMF724:
- case PCI_DEVICE_ID_YMF740:
- case PCI_DEVICE_ID_YMF724F:
- case PCI_DEVICE_ID_YMF740C:
- v = 0x8800 | ((mpuio<<4)&0x03) | ((sbio<<2)&0x03) | (oplio&0x03);
- pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v);
-#ifdef YMF_DEBUG
- printk(PFX "ELEGCTRL: 0x%x\n",v);
-#endif
- break;
-
- case PCI_DEVICE_ID_YMF744:
- case PCI_DEVICE_ID_YMF754:
- v = 0x8800;
- pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v);
- pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, card->opl3_data.io_base);
- pci_write_config_word(pcidev, YMFSB_PCIR_SBADR, card->sb_data.io_base);
- pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, card->mpu_data.io_base);
- break;
-
- default:
- printk(KERN_ERR PFX "Invalid device ID: %d\n",pcidev->device);
- return -EINVAL;
- break;
- }
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* AC'97 stuff */
-static int ymfsb_readAC97Reg( struct ac97_hwint *dev, u8 reg )
-{
- struct ymf_card *card = (struct ymf_card *)dev->driver_private;
- unsigned long flags;
- int ret;
-
- if ( reg > 0x7f ) return -EINVAL;
-
- save_flags(flags);
- cli();
- writeRegWord( card, YMFSB_AC97CMDADR, 0x8000 | reg );
- if ( checkPrimaryBusy( card ) ) {
- restore_flags(flags);
- return -EBUSY;
- }
- ret = readRegWord( card, YMFSB_AC97CMDDATA );
- restore_flags(flags);
-
- return ret;
-}
-
-static int ymfsb_writeAC97Reg( struct ac97_hwint *dev, u8 reg, u16 value )
-{
- struct ymf_card *card = (struct ymf_card *)dev->driver_private;
- unsigned long flags;
-
- if ( reg > 0x7f ) return -EINVAL;
-
- save_flags(flags);
- cli();
- if ( checkPrimaryBusy( card ) ) {
- restore_flags(flags);
- return -EBUSY;
- }
-
- writeRegWord( card, YMFSB_AC97CMDADR, 0x0000 | reg );
- writeRegWord( card, YMFSB_AC97CMDDATA, value );
-
- restore_flags(flags);
- return 0;
-}
-
-struct initialValues
-{
- unsigned short port;
- unsigned short value;
-};
-
-static struct initialValues ymfsb_ac97_initial_values[] =
-{
- { AC97_RESET, 0x0000 },
- { AC97_MASTER_VOL_STEREO, 0x0000 },
- { AC97_HEADPHONE_VOL, 0x8000 },
- { AC97_PCMOUT_VOL, 0x0606 },
- { AC97_MASTER_VOL_MONO, 0x0000 },
- { AC97_PCBEEP_VOL, 0x0000 },
- { AC97_PHONE_VOL, 0x0008 },
- { AC97_MIC_VOL, 0x8000 },
- { AC97_LINEIN_VOL, 0x8808 },
- { AC97_CD_VOL, 0x8808 },
- { AC97_VIDEO_VOL, 0x8808 },
- { AC97_AUX_VOL, 0x8808 },
- { AC97_RECORD_SELECT, 0x0000 },
- { AC97_RECORD_GAIN, 0x0B0B },
- { AC97_GENERAL_PURPOSE, 0x0000 },
- { 0xffff, 0xffff }
-};
-
-static int ymfsb_resetAC97( struct ac97_hwint *dev )
-{
- int i;
-
- for ( i=0 ; ymfsb_ac97_initial_values[i].port != 0xffff ; i++ )
- {
- ac97_put_register ( dev,
- ymfsb_ac97_initial_values[i].port,
- ymfsb_ac97_initial_values[i].value );
- }
-
- return 0;
-}
-
-static int ymfsb_ac97_mixer_ioctl( int dev, unsigned int cmd, caddr_t arg )
-{
- int i;
-
- for ( i=0 ; i < MAX_CARDS ; i++ )
- {
- if ( ymf_cards[i].mixer_oss_dev == dev ) break;
- }
-
- if ( i < MAX_CARDS )
- return ac97_mixer_ioctl(&(ymf_cards[i].ac97_dev), cmd, arg);
- else
- return -ENODEV;
-}
-
-static struct mixer_operations ymfsb_ac97_mixer_operations = {
- "YAMAHA",
- "YAMAHA PCI",
- ymfsb_ac97_mixer_ioctl
-};
-
-static struct ac97_mixer_value_list ymfsb_ac97_mixer_defaults[] = {
- { SOUND_MIXER_VOLUME, { { 85, 85 } } },
- { SOUND_MIXER_SPEAKER, { { 100 } } },
- { SOUND_MIXER_PCM, { { 65, 65 } } },
- { SOUND_MIXER_CD, { { 65, 65 } } },
- { -1, { { 0, 0 } } }
-};
-
-/* ---------------------------------------------------------------------- */
-
-static void enableDSP( struct ymf_card *card )
-{
- writeRegDWord( card, YMFSB_CONFIG, 0x00000001 );
- return;
-}
-
-static void disableDSP( struct ymf_card *card )
-{
- int val;
- int i;
-
- val = readRegDWord( card, YMFSB_CONFIG );
- if ( val ) {
- writeRegDWord( card, YMFSB_CONFIG, 0 );
- }
-
- i=0;
- while( ++i < YMFSB_WORKBITTIMEOUT ) {
- val = readRegDWord( card, YMFSB_STATUS );
- if ( (val & 0x00000002) == 0x00000000 ) break;
- }
-
- return;
-}
-
-static int setupInstruction( struct ymf_card *card, struct pci_dev *pcidev )
-{
- int i;
- int val;
-
- writeRegDWord( card, YMFSB_NATIVEDACOUTVOL, 0 ); /* mute dac */
- disableDSP( card );
-
- writeRegDWord( card, YMFSB_MODE, 0x00010000 );
-
- /* DS-XG Software Reset */
- writeRegDWord( card, YMFSB_MODE, 0x00000000 );
- writeRegDWord( card, YMFSB_MAPOFREC, 0x00000000 );
- writeRegDWord( card, YMFSB_MAPOFEFFECT, 0x00000000 );
- writeRegDWord( card, YMFSB_PLAYCTRLBASE, 0x00000000 );
- writeRegDWord( card, YMFSB_RECCTRLBASE, 0x00000000 );
- writeRegDWord( card, YMFSB_EFFCTRLBASE, 0x00000000 );
-
- val = readRegWord( card, YMFSB_GLOBALCTRL );
- writeRegWord( card, YMFSB_GLOBALCTRL, (val&~0x0007) );
-
- /* setup DSP instruction code */
- for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
- writeRegDWord( card, YMFSB_DSPINSTRAM+i, DspInst[i>>2] );
- }
-
- switch( pcidev->device ) {
- case PCI_DEVICE_ID_YMF724:
- case PCI_DEVICE_ID_YMF740:
- /* setup Control instruction code */
- for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
- writeRegDWord( card, YMFSB_CTRLINSTRAM+i, CntrlInst[i>>2] );
- }
- break;
-
- case PCI_DEVICE_ID_YMF724F:
- case PCI_DEVICE_ID_YMF740C:
- case PCI_DEVICE_ID_YMF744:
- case PCI_DEVICE_ID_YMF754:
- /* setup Control instruction code */
-
- for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
- writeRegDWord( card, YMFSB_CTRLINSTRAM+i, CntrlInst1E[i>>2] );
- }
- break;
-
- default:
- return -ENXIO;
- }
-
- enableDSP( card );
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int __init ymf7xx_init( struct ymf_card *card, struct pci_dev *pcidev )
-{
- unsigned short v;
- int mixer;
-
- /* Read hardware information */
-#ifdef YMF_DEBUG
- unsigned int dv;
- pci_read_config_word(pcidev, YMFSB_PCIR_VENDORID, &v);
- printk(KERN_INFO PFX "Vendor ID = 0x%x\n",v);
- pci_read_config_word(pcidev, YMFSB_PCIR_DEVICEID, &v);
- printk(KERN_INFO PFX "Device ID = 0x%x\n",v);
- pci_read_config_word(pcidev, YMFSB_PCIR_REVISIONID, &v);
- printk(KERN_INFO PFX "Revision ID = 0x%x\n",v&0xff);
- pci_read_config_dword(pcidev, YMFSB_PCIR_BASEADDR, &dv);
- printk(KERN_INFO PFX "Base address = 0x%x\n",dv);
- pci_read_config_word(pcidev, YMFSB_PCIR_IRQ, &v);
- printk(KERN_INFO PFX "IRQ line = 0x%x\n",v&0xff);
-#endif
-
- /* enables memory space access / bus mastering */
- pci_read_config_word(pcidev, YMFSB_PCIR_CMD, &v);
- pci_write_config_word(pcidev, YMFSB_PCIR_CMD, v|0x06);
-
- /* check codec */
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "check codec...\n");
-#endif
- if (checkCodec(card, pcidev)) return -EBUSY;
-
- /* setup legacy I/O */
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "setup legacy I/O...\n");
-#endif
- if (setupLegacyIO(card, pcidev)) return -EBUSY;
-
- /* setup instruction code */
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "setup instructions...\n");
-#endif
- if (setupInstruction(card, pcidev)) return -EBUSY;
-
- /* AC'97 setup */
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "setup AC'97...\n");
-#endif
- if ( ac97_init( &card->ac97_dev ) ) return -EBUSY;
-
- mixer = sound_alloc_mixerdev();
- if ( num_mixers >= MAX_MIXER_DEV ) return -EBUSY;
-
- mixer_devs[mixer] = &ymfsb_ac97_mixer_operations;
- card->mixer_oss_dev = mixer;
- ac97_set_values( &card->ac97_dev, ymfsb_ac97_mixer_defaults );
-
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "setup Legacy Volume...\n");
-#endif
- /* Legacy Audio Output Volume L & R ch */
- writeRegDWord( card, YMFSB_LEGACYOUTVOL, 0x3fff3fff );
-
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "setup SPDIF output control...\n");
-#endif
- /* SPDIF Output control */
- v = spdif_out != 0 ? 0x0001 : 0x0000;
- writeRegWord( card, YMFSB_SPDIFOUTCTRL, v );
- /* no copyright protection,
- sample-rate converted,
- re-recorded software comercially available (the 1st generation),
- original */
- writeRegWord( card, YMFSB_SPDIFOUTSTATUS, 0x9a04 );
-
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void __init ymf7xxsb_attach_sb(struct address_info *hw_config)
-{
- hw_config->driver_use_1 |= SB_NO_MIXER;
- if(!sb_dsp_init(hw_config))
- hw_config->slots[0] = -1;
-}
-
-static int __init ymf7xxsb_probe_sb(struct address_info *hw_config)
-{
- if (check_region(hw_config->io_base, 16))
- {
- printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
- hw_config->io_base);
- return 0;
- }
- return sb_dsp_detect(hw_config, SB_PCI_YAMAHA, 0);
-}
-
-
-static void ymf7xxsb_unload_sb(struct address_info *hw_config, int unload_mpu)
-{
- if(hw_config->slots[0]!=-1)
- sb_dsp_unload(hw_config, unload_mpu);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int __init ymf7xxsb_install (struct pci_dev *pcidev)
-{
- struct {
- unsigned short deviceid;
- char *devicename;
- } devicetable[] =
- {
- { PCI_DEVICE_ID_YMF724, "YMF724A-E" },
- { PCI_DEVICE_ID_YMF724F, "YMF724F" },
- { PCI_DEVICE_ID_YMF740, "YMF740A-B" },
- { PCI_DEVICE_ID_YMF740C, "YMF740C" },
- { PCI_DEVICE_ID_YMF744, "YMF744" },
- { PCI_DEVICE_ID_YMF754, "YMF754" },
- };
-
- char *devicename = "unknown";
- int i;
- unsigned long iobase;
- struct ymf_card *card;
-
- if ( pcidev->irq == 0 ) return -ENODEV;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
- if ( pci_enable_device(pcidev) ) {
- printk (KERN_ERR PFX "cannot enable PCI device\n");
- return -EIO;
- }
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
- iobase = pcidev->base_address[0]&PCI_BASE_ADDRESS_MEM_MASK;
-#else
- iobase = pcidev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK;
-#endif
- if ( iobase == 0x00000000 ) return -ENODEV;
-
- for ( i=0 ; i<sizeof(devicetable) / sizeof(devicetable[0]); i++ )
- {
- if (devicetable[i].deviceid == pcidev->device)
- {
- devicename = devicetable[i].devicename;
- break;
- }
- }
-
- card = &ymf_cards[cards];
-
- /* remap memory mapped I/O onto kernel virtual memory */
- if ( (card->ymfbase = ioremap_nocache(iobase, YMFSB_REGSIZE)) == 0 )
- {
- printk(KERN_ERR PFX "ioremap (0x%lx) returns zero\n", iobase);
- return -ENODEV;
- }
- printk(KERN_INFO PFX "found %s at 0x%lx\n", devicename, iobase);
-#ifdef YMF_DEBUG
- printk(KERN_INFO PFX "remappling to 0x%p\n", card->ymfbase);
-#endif
-
- memset (&card->sb_data, 0, sizeof (struct address_info));
- memset (&card->opl3_data, 0, sizeof (struct address_info));
- memset (&card->mpu_data, 0, sizeof (struct address_info));
- memset (&card->ac97_dev, 0, sizeof (struct ac97_hwint));
-
- card->card = cards;
-
- card->sb_data.name = YMFSB_CARD_NAME;
- card->opl3_data.name = YMFSB_CARD_NAME;
- card->mpu_data.name = YMFSB_CARD_NAME;
-
- card->sb_data.card_subtype = MDL_YMPCI;
-
- if ( io == 0 ) io = 0x220;
- card->sb_data.io_base = io;
- card->sb_data.irq = pcidev->irq;
- card->sb_data.dma = dma;
-
- if ( synth_io == 0 ) synth_io = 0x388;
- card->opl3_data.io_base = synth_io;
- card->opl3_data.irq = -1;
-
- if ( mpu_io == 0 ) mpu_io = 0x330;
- card->mpu_data.io_base = mpu_io;
- card->mpu_data.irq = -1;
-
- card->ac97_dev.reset_device = ymfsb_resetAC97;
- card->ac97_dev.read_reg = ymfsb_readAC97Reg;
- card->ac97_dev.write_reg = ymfsb_writeAC97Reg;
- card->ac97_dev.driver_private = (void *)card;
-
- if ( ymf7xx_init(card, pcidev) ) {
- printk (KERN_ERR PFX
- "Cannot initialize %s, aborting\n",
- devicename);
- return -ENODEV;
- }
-
- /* regist legacy SoundBlaster Pro */
- if (!ymf7xxsb_probe_sb(&card->sb_data)) {
- printk (KERN_ERR PFX
- "SB probe at 0x%X failed, aborting\n",
- io);
- return -ENODEV;
- }
- ymf7xxsb_attach_sb (&card->sb_data);
-
- /* regist legacy MIDI */
- if ( mpu_io > 0 && 0)
- {
- if (!ymf7xxsb_probe_midi (&card->mpu_data)) {
- printk (KERN_ERR PFX
- "MIDI probe @ 0x%X failed, aborting\n",
- mpu_io);
- ymf7xxsb_unload_sb (&card->sb_data, 0);
- return -ENODEV;
- }
- ymf7xxsb_attach_midi (&card->mpu_data);
- }
-
- /* regist legacy OPL3 */
-
- cards++;
- return 0;
-}
-
-static int __init probe_ymf7xxsb (void)
-{
- struct pci_dev *pcidev = NULL;
- int i;
-
- for (i=0 ; i<MAX_CARDS ; i++ )
- ymf_cards[i].ymfbase = NULL;
-
- while ( pcidev == NULL && (
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF724, pcidev)) ||
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF724F,pcidev)) ||
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF740, pcidev)) ||
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF740C,pcidev)) ||
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF744, pcidev)) ||
- (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
- PCI_DEVICE_ID_YMF754, pcidev)))) {
- if (ymf7xxsb_install (pcidev)) {
- printk (KERN_ERR PFX "audio init failed\n");
- return -ENODEV;
- }
-
- if (cards == MAX_CARDS) {
- printk (KERN_DEBUG PFX "maximum number of cards reached\n");
- break;
- }
- }
-
- return 0;
-}
-
-static void free_iomaps( void )
-{
- int i;
-
- for ( i=0 ; i<MAX_CARDS ; i++ ) {
- if ( ymf_cards[i].ymfbase!=NULL )
- iounmap(ymf_cards[i].ymfbase);
- }
-
- return;
-}
-
-int __init init_ymf7xxsb_module(void)
-{
- if (!pci_present ()) {
- printk (KERN_DEBUG PFX "PCI not present, exiting\n");
- return -ENODEV;
- }
-
- if (probe_ymf7xxsb()) {
- printk(KERN_ERR PFX "probe failed, aborting\n");
- /* XXX unload cards registered so far, if any */
- free_iomaps();
- return -ENODEV;
- }
-
- if (cards == 0) {
- printk(KERN_DEBUG PFX "No chips found, aborting\n");
- free_iomaps();
- return -ENODEV;
- }
-
- printk (KERN_INFO PFX YMFSB_CARD_NAME " loaded\n");
-
- /*
- * Binds us to the sound subsystem
- */
- SOUND_LOCK;
- return 0;
-}
-
-static void cleanup_ymf7xxsb_module(void)
-{
- int i;
-
- for (i = 0; i < cards; i++) {
- ymf7xxsb_unload_sb (&(ymf_cards[i].sb_data), 0);
- ymf7xxsb_unload_midi (&(ymf_cards[i].mpu_data));
- if ( ymf_cards[i].mixer_oss_dev >= 0 )
- sound_unload_mixerdev( ymf_cards[i].mixer_oss_dev );
- }
-
- free_iomaps();
-
- /*
- * Final clean up with the sound layer
- */
- SOUND_LOCK_END;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Daisuke Nagano, breeze.nagano@nifty.ne.jp");
-MODULE_DESCRIPTION("YMF7xx Legacy Audio Driver");
-
-int init_module(void)
-{
- return init_ymf7xxsb_module();
-}
-
-void cleanup_module(void)
-{
- cleanup_ymf7xxsb_module();
-}
-
-#endif
* ? underused structure members
*/
+#define YMFPCI_HAVE_MIDI_SUPPORT
+
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/dma.h>
#include <asm/uaccess.h>
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+# include "sound_config.h"
+#endif
+
#include "ymfpci.h"
#define snd_magic_cast(t, p, err) ((t *)(p))
return -ENOTTY;
}
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+/* MIDI stuff */
+
+/* */
+
+static int ymfpci_setup_legacy( ymfpci_t *codec, struct pci_dev *pcidev )
+{
+ int v;
+ int mpuio=-1, oplio=-1;
+
+ switch(codec->iomidi) {
+ case 0x330:
+ mpuio = 0;
+ break;
+ case 0x300:
+ mpuio = 1;
+ break;
+ case 0x332:
+ mpuio = 2;
+ break;
+ case 0x334:
+ mpuio = 3;
+ break;
+ default:
+ break;
+ }
+
+ switch(codec->iosynth) {
+ case 0x388:
+ oplio = 0;
+ break;
+ case 0x398:
+ oplio = 1;
+ break;
+ case 0x3a0:
+ oplio = 2;
+ break;
+ case 0x3a8:
+ oplio = 3;
+ break;
+ default:
+ break;
+ }
+
+ if ( mpuio >= 0 || oplio >= 0 ) {
+ v = 0x003e;
+ pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
+
+ switch( pcidev->device ) {
+ case PCI_DEVICE_ID_YAMAHA_724:
+ case PCI_DEVICE_ID_YAMAHA_740:
+ case PCI_DEVICE_ID_YAMAHA_724F:
+ case PCI_DEVICE_ID_YAMAHA_740C:
+ v = 0x8800;
+ if ( mpuio >= 0 ) { v|= (mpuio<<4)&0x03; }
+ if ( oplio >= 0 ) { v|= (oplio&0x03); }
+ pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+ break;
+
+ case PCI_DEVICE_ID_YAMAHA_744:
+ case PCI_DEVICE_ID_YAMAHA_754:
+ v = 0x8800;
+ pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+ if ( mpuio >= 0 ) {
+ pci_write_config_word(pcidev, PCIR_OPLADR, codec->iosynth);
+ }
+ if ( oplio >= 0 ) {
+ pci_write_config_word(pcidev, PCIR_MPUADR, codec->iomidi);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "ymfpci: Invalid device ID: %d\n",pcidev->device);
+ return -EINVAL;
+ break;
+ }
+ }
+
+ return 0;
+}
+#endif /* YMFPCI_HAVE_MIDI_SUPPORT */
+
+/* */
+
static int ymf_open(struct inode *inode, struct file *file)
{
ymfpci_t *unit;
/* XXX Semaphore here! */
for (unit = ymf_devs; unit != NULL; unit = unit->next) {
+#if 0
if (unit->inst == instance) break;
+#else
+ if (!((unit->dev_audio ^ minor) & ~0x0f)) break;
+#endif
}
if (unit == NULL) return -ENODEV;
return 0;
}
+/* */
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+# ifdef MODULE
+static int mpu_io = 0;
+static int synth_io = 0;
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(synth_io, "i");
+# else
+static int mpu_io = 0x330;
+static int synth_io = 0x388;
+# endif
+#endif /* YMFPCI_HAVE_MIDI_SUPPORT */
+/* */
+
static int /* __init */
ymf_install(struct pci_dev *pcidev, int instance, int devx)
{
return -ENODEV;
}
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+ codec->iomidi = mpu_io;
+ codec->iosynth = synth_io;
+ if (ymfpci_setup_legacy(codec, pcidev) < 0) {
+ ymfpci_free(codec);
+ return -ENODEV;
+ }
+#endif
+
ymfpci_download_image(codec);
udelay(100); /* seems we need some delay after downloading image.. */
return err;
}
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+ memset (&codec->opl3_data, 0, sizeof (struct address_info));
+ memset (&codec->mpu_data, 0, sizeof (struct address_info));
+
+ codec->opl3_data.name = "ymfpci";
+ codec->mpu_data.name = "ymfpci";
+
+ codec->opl3_data.io_base = codec->iosynth;
+ codec->opl3_data.irq = -1;
+
+ codec->mpu_data.io_base = codec->iomidi;
+ codec->mpu_data.irq = -1;
+
+ if ( mpu_io > 0 )
+ {
+ if ( probe_uart401(&codec->mpu_data) ) {
+ attach_uart401(&codec->mpu_data);
+ }
+ }
+
+#endif /* YMFPCI_HAVE_MIDI_SUPPORT */
+
codec->next = ymf_devs;
ymf_devs = codec;
unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
kfree(codec->ac97_codec[0]);
}
+#ifdef YMFPCI_HAVE_MIDI_SUPPORT
+ if (codec->iomidi) {
+ unload_uart401(&(codec->mpu_data));
+ }
+#endif /* YMFPCI_HAVE_MIDI_SUPPORT */
kfree(codec);
}
#define YDSXG_AC97READCMD 0x8000
#define YDSXG_AC97WRITECMD 0x0000
+#define PCIR_VENDORID 0x00
+#define PCIR_DEVICEID 0x02
+#define PCIR_CMD 0x04
+#define PCIR_REVISIONID 0x08
+#define PCIR_BASEADDR 0x10
+#define PCIR_IRQ 0x3c
+
+#define PCIR_LEGCTRL 0x40
+#define PCIR_ELEGCTRL 0x42
#define PCIR_DSXGCTRL 0x48
+#define PCIR_OPLADR 0x60
+#define PCIR_SBADR 0x62
+#define PCIR_MPUADR 0x64
#define YDSXG_DSPLENGTH 0x0080
#define YDSXG_CTRLLENGTH 0x3000
int irq;
int inst; /* Unit number (instance) */
+ /* legacy hardware resources */
+ unsigned int iosynth, iomidi;
+ struct address_info opl3_data, mpu_data;
+
spinlock_t reg_lock;
spinlock_t voice_lock;
fi
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
+ dep_tristate ' USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
fi
// process if URB was not killed
if (purb->status != -ENOENT) {
- unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
- int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+ unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
+ int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
for (i = 0; i < purb->number_of_packets; i++)
if (!purb->iso_frame_desc[i].status) {
len = purb->iso_frame_desc[i].actual_length;
end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
+ end->purb->dev=s->usbdev;
+
ret = usb_submit_urb (end->purb);
if (ret) {
err("usb_submit_urb returned:%d", ret);
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
# Objects that export symbols.
export-objs := usbserial.o
--- /dev/null
+/*
+ * USB Empeg empeg-car player driver
+ *
+ * Copyright (C) 2000
+ * Gary Brubaker (xavyer@ix.netcom.com)
+ *
+ * Copyright (C) 1999, 2000
+ * Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * 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, version 2.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (11/13/2000) gb
+ * Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
+ * (It only needs to be set once - Doh!)
+ *
+ * (11/11/2000) gb
+ * Updated to work with id_table structure.
+ *
+ * (11/04/2000) gb
+ * Forked this from visor.c, and hacked it up to work with an
+ * Empeg ltd. empeg-car player. Constructive criticism welcomed.
+ * I would like to say, 'Thank You' to Greg Kroah-Hartman for the
+ * use of his code, and for his guidance, advice and patience. :)
+ * A 'Thank You' is in order for John Ripley of Empeg ltd for his
+ * advice, and patience too.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#define EMPEG_VENDOR_ID 0x084f
+#define EMPEG_PRODUCT_ID 0x0001
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+/* function prototypes for an empeg-car player */
+static int empeg_open (struct usb_serial_port *port, struct file *filp);
+static void empeg_close (struct usb_serial_port *port, struct file *filp);
+static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static void empeg_throttle (struct usb_serial_port *port);
+static void empeg_unthrottle (struct usb_serial_port *port);
+static int empeg_startup (struct usb_serial *serial);
+static void empeg_shutdown (struct usb_serial *serial);
+static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
+static void empeg_write_bulk_callback (struct urb *urb);
+static void empeg_read_bulk_callback (struct urb *urb);
+
+static __u16 empeg_vendor_id = EMPEG_VENDOR_ID;
+static __u16 empeg_product_id = EMPEG_PRODUCT_ID;
+struct usb_serial_device_type empeg_device = {
+ name: "Empeg",
+ idVendor: &empeg_vendor_id,
+ idProduct: &empeg_product_id,
+ needs_interrupt_in: MUST_HAVE_NOT, /* must not have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* must have a bulk out endpoint */
+ num_interrupt_in: 0,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: empeg_open,
+ close: empeg_close,
+ throttle: empeg_throttle,
+ unthrottle: empeg_unthrottle,
+ startup: empeg_startup,
+ shutdown: empeg_shutdown,
+ ioctl: empeg_ioctl,
+ set_termios: empeg_set_termios,
+ write: empeg_write,
+ write_bulk_callback: empeg_write_bulk_callback,
+ read_bulk_callback: empeg_read_bulk_callback,
+};
+
+#define NUM_URBS 16
+#define URB_TRANSFER_BUFFER_SIZE 4096
+
+static struct urb *write_urb_pool[NUM_URBS];
+static spinlock_t write_urb_pool_lock;
+static int bytes_in;
+static int bytes_out;
+
+/******************************************************************************
+ * Empeg specific driver functions
+ ******************************************************************************/
+static int empeg_open (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+ int result;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return -ENODEV;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ /* gb - 2000/11/05
+ *
+ * personally, I think these termios should be set in
+ * empeg_startup(), but it appears doing so leads to one
+ * of those chicken/egg problems. :)
+ *
+ */
+ port->tty->termios->c_iflag
+ &= ~(IGNBRK
+ | BRKINT
+ | PARMRK
+ | ISTRIP
+ | INLCR
+ | IGNCR
+ | ICRNL
+ | IXON);
+
+ port->tty->termios->c_oflag
+ &= ~OPOST;
+
+ port->tty->termios->c_lflag
+ &= ~(ECHO
+ | ECHONL
+ | ICANON
+ | ISIG
+ | IEXTEN);
+
+ port->tty->termios->c_cflag
+ &= ~(CSIZE
+ | PARENB);
+
+ port->tty->termios->c_cflag
+ |= CS8;
+
+ /* gb - 2000/11/05
+ *
+ * force low_latency on
+ *
+ * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
+ * force the data through if low_latency is set. Otherwise the pushes are
+ * scheduled; this is bad as it opens up the possibility of dropping bytes
+ * on the floor. We are trying to sustain high data transfer rates; and
+ * don't want to drop bytes on the floor.
+ * Moral: use low_latency - drop no bytes - life is good. :)
+ *
+ */
+ port->tty->low_latency = 1;
+
+ if (!port->active) {
+ port->active = 1;
+ bytes_in = 0;
+ bytes_out = 0;
+
+ /* Start reading from the device */
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
+}
+
+
+static void empeg_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial;
+ unsigned char *transfer_buffer;
+ unsigned long flags;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ serial = get_usb_serial (port, __FUNCTION__);
+ if (!serial)
+ return;
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+
+ if (!transfer_buffer) {
+ err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+ } else {
+ kfree (transfer_buffer);
+ }
+
+ /* shutdown our bulk read */
+ usb_unlink_urb (port->read_urb);
+ port->active = 0;
+ port->open_count = 0;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ /* Uncomment the following line if you want to see some statistics in your syslog */
+ /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
+
+}
+
+
+static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ const unsigned char *current_position = buf;
+ unsigned long flags;
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
+
+ while (count > 0) {
+
+ /* try to find a free urb in our list of them */
+ urb = NULL;
+
+ spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = write_urb_pool[i];
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " - no more free urbs");
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ err(__FUNCTION__" no more kernel memory...");
+ goto exit;
+ }
+ }
+
+ transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
+
+ if (from_user) {
+ copy_from_user (urb->transfer_buffer, current_position, transfer_size);
+ } else {
+ memcpy (urb->transfer_buffer, current_position, transfer_size);
+ }
+
+ count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ /* build up our urb */
+ FILL_BULK_URB (
+ urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer,
+ transfer_size,
+ empeg_write_bulk_callback,
+ port);
+
+ urb->transfer_flags |= USB_QUEUE_BULK;
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb);
+ if (status)
+ dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+
+ current_position += transfer_size;
+ bytes_sent += transfer_size;
+ count -= transfer_size;
+ bytes_out += transfer_size;
+
+ }
+
+exit:
+ return bytes_sent;
+
+}
+
+
+static void empeg_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+
+ return;
+
+}
+
+
+static void empeg_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int i;
+ int result;
+
+ if (port_paranoia_check (port, __FUNCTION__))
+ return;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ /* gb - 2000/11/13
+ * If we insert too many characters we'll overflow the buffer.
+ * This means we'll lose bytes - Decidedly bad.
+ */
+ if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+ tty_flip_buffer_push(tty);
+ }
+ /* gb - 2000/11/13
+ * This doesn't push the data through unless tty->low_latency is set.
+ */
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ /* gb - 2000/11/13
+ * Goes straight through instead of scheduling - if tty->low_latency is set.
+ */
+ tty_flip_buffer_push(tty);
+ bytes_in += urb->actual_length;
+ }
+
+ /* Continue trying to always read */
+ port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+ return;
+
+}
+
+
+static void empeg_throttle (struct usb_serial_port *port)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ usb_unlink_urb (port->read_urb);
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return;
+
+}
+
+
+static void empeg_unthrottle (struct usb_serial_port *port)
+{
+ unsigned long flags;
+ int result;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ port->read_urb->dev = port->serial->dev;
+
+ result = usb_submit_urb(port->read_urb);
+
+ if (result)
+ err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return;
+
+}
+
+
+static int empeg_startup (struct usb_serial *serial)
+{
+
+ dbg(__FUNCTION__);
+
+ dbg(__FUNCTION__ " - Set config to 1");
+ usb_set_configuration (serial->dev, 1);
+
+ /* continue on with initialization */
+ return 0;
+
+}
+
+
+static void empeg_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ empeg_close (&serial->port[i], NULL);
+ }
+ }
+
+}
+
+
+static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+ return -ENOIOCTLCMD;
+}
+
+
+/* This function is all nice and good, but we don't change anything based on it :) */
+static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ unsigned int cflag = port->tty->termios->c_cflag;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg(__FUNCTION__ " - nothing to change...");
+ return;
+ }
+ }
+
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg(__FUNCTION__" - no tty structures");
+ return;
+ }
+
+ /* get the byte size */
+ switch (cflag & CSIZE) {
+ case CS5: dbg(__FUNCTION__ " - data bits = 5"); break;
+ case CS6: dbg(__FUNCTION__ " - data bits = 6"); break;
+ case CS7: dbg(__FUNCTION__ " - data bits = 7"); break;
+ default:
+ case CS8: dbg(__FUNCTION__ " - data bits = 8"); break;
+ }
+
+ /* determine the parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ dbg(__FUNCTION__ " - parity = odd");
+ else
+ dbg(__FUNCTION__ " - parity = even");
+ else
+ dbg(__FUNCTION__ " - parity = none");
+
+ /* figure out the stop bits requested */
+ if (cflag & CSTOPB)
+ dbg(__FUNCTION__ " - stop bits = 2");
+ else
+ dbg(__FUNCTION__ " - stop bits = 1");
+
+ /* figure out the flow control settings */
+ if (cflag & CRTSCTS)
+ dbg(__FUNCTION__ " - RTS/CTS is enabled");
+ else
+ dbg(__FUNCTION__ " - RTS/CTS is disabled");
+
+ /* determine software flow control */
+ if (I_IXOFF(port->tty))
+ dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+ else
+ dbg(__FUNCTION__ " - XON/XOFF is disabled");
+
+ /* get the baud rate wanted */
+ dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+
+ return;
+
+}
+
+
+static int __init empeg_init (void)
+{
+ struct urb *urb;
+ int i;
+
+ usb_serial_register (&empeg_device);
+
+ /* create our write urb pool and transfer buffers */
+ spin_lock_init (&write_urb_pool_lock);
+ for (i = 0; i < NUM_URBS; ++i) {
+ urb = usb_alloc_urb(0);
+ write_urb_pool[i] = urb;
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = NULL;
+ urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err (__FUNCTION__ " - out of memory for urb buffers.");
+ continue;
+ }
+ }
+
+ return 0;
+
+}
+
+
+static void __exit empeg_exit (void)
+{
+ int i;
+ unsigned long flags;
+
+ usb_serial_deregister (&empeg_device);
+
+ spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (write_urb_pool[i]) {
+ /* FIXME - uncomment the following usb_unlink_urb call when
+ * the host controllers get fixed to set urb->dev = NULL after
+ * the urb is finished. Otherwise this call oopses. */
+ /* usb_unlink_urb(write_urb_pool[i]); */
+ if (write_urb_pool[i]->transfer_buffer)
+ kfree(write_urb_pool[i]->transfer_buffer);
+ usb_free_urb (write_urb_pool[i]);
+ }
+ }
+
+ spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+}
+
+
+module_init(empeg_init);
+module_exit(empeg_exit);
+
+MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>");
+MODULE_DESCRIPTION("USB Empeg Mark I/II Driver");
static struct vc_data *mda_display_fg = NULL;
-#ifdef MODULE_PARM
MODULE_PARM(mda_first_vc, "1-255i");
MODULE_PARM(mda_last_vc, "1-255i");
-#endif
-
-/* MDA register values
- */
+/* MDA register values */
#define MDA_CURSOR_BLINKING 0x00
#define MDA_CURSOR_OFF 0x20
}
#endif
-#ifdef MODULE
-static int mda_detect(void)
-#else
__initfunc(static int mda_detect(void))
-#endif
{
int count=0;
u16 *p, p_save;
return 1;
}
-#ifdef MODULE
-static void mda_initialize(void)
-#else
__initfunc(static void mda_initialize(void))
-#endif
{
write_mda_b(97, 0x00); /* horizontal total */
write_mda_b(80, 0x01); /* horizontal displayed */
outb_p(0x00, mda_gfx_port);
}
-#ifdef MODULE
-static const char *mdacon_startup(void)
-#else
__initfunc(static const char *mdacon_startup(void))
-#endif
{
mda_num_columns = 80;
mda_num_lines = 25;
mdacon_invert_region, /* con_invert_region */
};
-#ifdef MODULE
-void mda_console_init(void)
-#else
__initfunc(void mda_console_init(void))
-#endif
{
if (mda_first_vc > mda_last_vc)
return;
#undef DUMP_SEEK
#define DUMP_WRITE(addr, nr) \
- if (!dump_write(file, (addr), (nr))) \
+ if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
goto close_coredump;
#define DUMP_SEEK(off) \
if (!dump_seek(file, (off))) \
char corefile[6+sizeof(current->comm)];
int segs;
int i;
- size_t size;
+ size_t size = 0;
struct vm_area_struct *vma;
struct elfhdr elf;
off_t offset = 0, dataoff;
MOD_INC_USE_COUNT;
#endif
- /* Count what's needed to dump, up to the limit of coredump size */
- segs = 0;
- size = 0;
- for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
- if (maydump(vma))
- {
- unsigned long sz = vma->vm_end-vma->vm_start;
-
- if (size+sz >= limit)
- break;
- else
- size += sz;
- }
+ segs = current->mm->map_count;
- segs++;
- }
#ifdef DEBUG
- printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+ printk("elf_core_dump: %d segs %lu limit\n", segs, limit);
#endif
/* Set up header */
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
/* Write program headers for segments dump */
- for(vma = current->mm->mmap, i = 0;
- i < segs && vma != NULL; vma = vma->vm_next) {
+ for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
struct elf_phdr phdr;
size_t sz;
- i++;
-
sz = vma->vm_end - vma->vm_start;
phdr.p_type = PT_LOAD;
DUMP_SEEK(dataoff);
- for(i = 0, vma = current->mm->mmap;
- i < segs && vma != NULL;
- vma = vma->vm_next) {
- unsigned long addr = vma->vm_start;
- unsigned long len = vma->vm_end - vma->vm_start;
+ for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ unsigned long addr;
- i++;
if (!maydump(vma))
continue;
#ifdef DEBUG
printk("elf_core_dump: writing %08lx %lx\n", addr, len);
#endif
- DUMP_WRITE((void *)addr, len);
+ for (addr = vma->vm_start;
+ addr < vma->vm_end;
+ addr += PAGE_SIZE) {
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = pgd_offset(vma->vm_mm, addr);
+ pmd = pmd_alloc(pgd, addr);
+
+ if (!pmd)
+ goto end_coredump;
+ pte = pte_alloc(pmd, addr);
+ if (!pte)
+ goto end_coredump;
+ if (!pte_present(*pte) &&
+ pte_none(*pte)) {
+ DUMP_SEEK (file->f_pos + PAGE_SIZE);
+ } else {
+ DUMP_WRITE((void*)addr, PAGE_SIZE);
+ }
+ }
}
if ((off_t) file->f_pos != offset) {
* linux/fs/fat/misc.c
*
* Written 1992,1993 by Werner Almesberger
+ * 22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
+ * and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
*/
#include <linux/fs.h>
{
int month,year,secs;
- month = ((date >> 5) & 15)-1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
unix_date -= sys_tz.tz_minuteswest*60;
if (sys_tz.tz_dsttime) unix_date += 3600;
+ /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+ if (unix_date < 315532800)
+ unix_date = 315532800;
+
*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
(((unix_date/3600) % 24) << 11);
day = unix_date/86400-3652;
ChangeLog for smbfs.
+2000-11-22 Igor Zhbanov <bsg@uniyar.ac.ru>
+
+ * proc.c: fixed date_unix2dos for dates earlier than 01/01/1980
+ and date_dos2unix for date==0
+
2000-11-04 Urban Widmark <urban@svenskatest.se>
* proc.c, sock.c: adjust max parameters & max data to follow max_xmit
* proc.c: removed support for old protocol levels. It didn't work
anyway and was cluttering things up a lot.
-2000-01-?? cpg@aladdin.de
+2000-01-03 Christian Groessler <cpg@aladdin.de>
* proc.c: added posix semantics for unlink
int month, year;
time_t secs;
- month = ((date >> 5) & 15) - 1;
+ /* first subtract and mask after that... Otherwise, if
+ date == 0, bad things happen */
+ month = ((date >> 5) - 1) & 15;
year = date >> 9;
secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
int day, year, nl_day, month;
unix_date = utc2local(server, unix_date);
+
+ /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+ if (unix_date < 315532800)
+ unix_date = 315532800;
+
*time = (unix_date % 60) / 2 +
(((unix_date / 60) % 60) << 5) +
(((unix_date / 3600) % 24) << 11);
__initfunc(static void check_amd_k6(void))
{
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 == 5 &&
boot_cpu_data.x86_model == 6 &&
boot_cpu_data.x86_mask == 1)
{
" popl %0\n" \
" shl $2,%0\n" \
" addl $3,%0\n" \
- " jmp 2b\n" \
+ " jmp 3b\n" \
"5: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosw\n" \
" stosb\n" \
" popl %%eax\n" \
" addl $3,%0\n" \
- " jmp 2b\n" \
+ " jmp 3b\n" \
"6: pushl %%eax\n" \
" xorl %%eax,%%eax\n" \
" stosb\n" \
" popl %%eax\n" \
" incl %0\n" \
- " jmp 2b\n" \
+ " jmp 3b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
#include <linux/kernel.h>
#include <asm/bitops.h>
#include <asm/atomic.h>
+#include <asm/ptrace.h>
struct irqaction {
void (*handler)(int, void *, struct pt_regs *);
* (and according to card ID within vendor). Send all updates to
* <linux-pcisupport@cck.uni-kl.de>.
*/
+#define PCI_VENDOR_ID_DYNALINK 0x0675
+#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702
+
+#define PCI_VENDOR_ID_BERKOM 0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T 0xFFA1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xFFA2
+#define PCI_DEVICE_ID_BERKOM_A4T 0xFFA4
+#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xFFA8
+
#define PCI_VENDOR_ID_COMPAQ 0x0e11
#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508
#define PCI_DEVICE_ID_COMPAQ_1280 0x3033
#define PCI_DEVICE_ID_CT_65554 0x00e4
#define PCI_DEVICE_ID_CT_65555 0x00e5
+#define PCI_DEVICE_ID_PLX_R685 0x1030
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
+#define PCI_DEVICE_ID_PLX_R753 0x1152
+
#define PCI_VENDOR_ID_MIRO 0x1031
#define PCI_DEVICE_ID_MIRO_36050 0x5601
#define PCI_DEVICE_ID_OPTI_82C861 0xc861
#define PCI_DEVICE_ID_OPTI_82C825 0xd568
+#define PCI_VENDOR_ID_ELSA 0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
+
#define PCI_VENDOR_ID_SGS 0x104a
#define PCI_DEVICE_ID_SGS_2000 0x0008
#define PCI_DEVICE_ID_SGS_1764 0x0009
/* Winbond have two vendor IDs! See 0x10ad as well */
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940 0x0940
+#define PCI_DEVICE_ID_WINBOND2_6692 0x6692
+
+#define PCI_VENDOR_ID_ANIGMA 0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
#define PCI_VENDOR_ID_MOTOROLA 0x1057
#define PCI_VENDOR_ID_MOTOROLA_OOPS 0x1507
#define PCI_DEVICE_ID_PHILIPS_SAA7145 0x7145
#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
+#define PCI_VENDOR_ID_EICON 0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20PRO 0xe001
+#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20PRO_U 0xe003
+#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
+#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
+
#define PCI_VENDOR_ID_CYCLONE 0x113c
#define PCI_DEVICE_ID_CYCLONE_SDK 0x0001
#define PCI_DEVICE_ID_DIGI_XRJ 0x0009
#define PCI_DEVICE_ID_DIGI_EPCJ 0x000a
#define PCI_DEVICE_ID_DIGI_XR_920 0x0027
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
#define PCI_VENDOR_ID_MUTECH 0x1159
#define PCI_DEVICE_ID_MUTECH_MV1000 0x0001
#define PCI_VENDOR_ID_AVM 0x1244
#define PCI_DEVICE_ID_AVM_A1 0x0a00
+#define PCI_DEVICE_ID_AVM_B1 0x0700
+#define PCI_DEVICE_ID_AVM_C4 0x0800
+#define PCI_DEVICE_ID_AVM_T1 0x1200
#define PCI_VENDOR_ID_DIPIX 0x1246
#define PCI_DEVICE_ID_OPTIBASE_VQUEST 0x2130
#define PCI_VENDOR_ID_SATSAGEM 0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
#define PCI_DEVICE_ID_SATSAGEM_PCR2101 0x5352
#define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_VENDOR_ID_HYPERCOPE 0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050
+#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104
+#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106
+#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107
+#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108
+#define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS 0x0109
+
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
+#define PCI_VENDOR_ID_CCD 0x1397
+#define PCI_DEVICE_ID_CCD_2BD0 0x2BD0
+#define PCI_DEVICE_ID_CCD_B000 0xB000
+#define PCI_DEVICE_ID_CCD_B006 0xB006
+#define PCI_DEVICE_ID_CCD_B007 0xB007
+#define PCI_DEVICE_ID_CCD_B008 0xB008
+#define PCI_DEVICE_ID_CCD_B009 0xB009
+#define PCI_DEVICE_ID_CCD_B00A 0xB00A
+#define PCI_DEVICE_ID_CCD_B00B 0xB00B
+#define PCI_DEVICE_ID_CCD_B00C 0xB00C
+#define PCI_DEVICE_ID_CCD_B100 0xB100
+
+#define PCI_VENDOR_ID_ABOCOM 0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1
+
#define PCI_VENDOR_ID_LAVA 0x1407
#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */
#define PCI_VENDOR_ID_AFAVLAB 0x14db
#define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120
+#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2BD0
+
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
#define PCI_DEVICE_ID_SYMPHONY_101 0x0001
#define PCI_VENDOR_ID_TIGERJET 0xe159
#define PCI_DEVICE_ID_TIGERJET_300 0x0001
+#define PCI_DEVICE_ID_TIGERJET_100 0x0002
#define PCI_VENDOR_ID_ARK 0xedd8
#define PCI_DEVICE_ID_ARK_STING 0xa091
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
- * ==FILEDATE 19990810==
+ * $Id: synclink.h,v 2.2 2000/11/08 17:08:30 paul Exp $
*
- * Copyright (C) 1998 by Microgate Corporation
+ * Copyright (C) 1998-2000 by Microgate Corporation
*
* Redistribution of this file is permitted under
* the terms of the GNU Public License (GPL)
#ifndef _SYNCLINK_H_
#define _SYNCLINK_H_
+#define SYNCLINK_H_VERSION 2.2
#define BOOLEAN int
#define TRUE 1
* (there is some stuff that will be added in the future...)
* I just plan to increment with each new version.
*/
-#define WIRELESS_EXT 9
+#define WIRELESS_EXT 10
/*
* Changes :
* - Change encoding to support larger tokens (>64 bits)
* - Updated iw_params (disable, flags) and use it for NWID
* - Extracted iw_point from iwreq for clarity
+ *
+ * V9 to V10
+ * ---------
+ * - Add PM capability to range structure
+ * - Add PM modifier : MAX/MIN/RELATIVE
+ * - Add encoding option : IW_ENCODE_NOKEY
+ * - Add TxPower ioctls (work like TxRate)
*/
/* -------------------------- IOCTL LIST -------------------------- */
/* Basic operations */
-#define SIOCSIWNAME 0x8B00 /* Unused ??? */
-#define SIOCGIWNAME 0x8B01 /* get name */
+#define SIOCSIWNAME 0x8B00 /* Unused */
+#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
#define SIOCSIWNWID 0x8B02 /* set network id (the cell) */
#define SIOCGIWNWID 0x8B03 /* get network id */
-#define SIOCSIWFREQ 0x8B04 /* set channel/frequency */
-#define SIOCGIWFREQ 0x8B05 /* get channel/frequency */
+#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */
+#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */
#define SIOCSIWMODE 0x8B06 /* set operation mode */
#define SIOCGIWMODE 0x8B07 /* get operation mode */
-#define SIOCSIWSENS 0x8B08 /* set sensitivity */
-#define SIOCGIWSENS 0x8B09 /* get sensitivity */
+#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */
+#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */
/* Informative stuff */
-#define SIOCSIWRANGE 0x8B0A /* Unused ??? */
+#define SIOCSIWRANGE 0x8B0A /* Unused */
#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */
-#define SIOCSIWPRIV 0x8B0C /* Unused ??? */
+#define SIOCSIWPRIV 0x8B0C /* Unused */
#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */
/* Mobile IP support */
#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */
#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */
#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */
+#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */
+#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */
/* Encoding stuff (scrambling, hardware security, WEP...) */
#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */
/* Maximum bit rates in the range struct */
#define IW_MAX_BITRATES 8
+/* Maximum tx powers in the range struct */
+#define IW_MAX_TXPOWER 8
+
/* Maximum of address that you may set with SPY */
#define IW_MAX_SPY 8
/* Flags for encoding (along with the token) */
#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */
-#define IW_ENCODE_FLAGS 0xF000 /* Flags defined below */
+#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */
+#define IW_ENCODE_MODE 0xF000 /* Modes defined below */
#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */
#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
+#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
/* Power management flags available (along with the value, if any) */
#define IW_POWER_ON 0x0000 /* No details... */
#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */
#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */
#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */
+#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */
+#define IW_POWER_MIN 0x0001 /* Value is a minimum */
+#define IW_POWER_MAX 0x0002 /* Value is a maximum */
+#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
+
+/* Transmit Power flags available */
+#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
+#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
/****************************** TYPES ******************************/
struct iw_param sens; /* signal level threshold */
struct iw_param bitrate; /* default bit rate */
+ struct iw_param txpower; /* default transmit power */
struct iw_param rts; /* RTS threshold threshold */
struct iw_param frag; /* Fragmentation threshold */
__u32 mode; /* Operation mode */
__s32 max_frag; /* Maximal frag threshold */
/* Power Management duration & timeout */
- __s32 min_pmd; /* Minimal PM duration */
- __s32 max_pmd; /* Maximal PM duration */
+ __s32 min_pmp; /* Minimal PM period */
+ __s32 max_pmp; /* Maximal PM period */
__s32 min_pmt; /* Minimal PM timeout */
__s32 max_pmt; /* Maximal PM timeout */
+ __u16 pmp_flags; /* How to decode max/min PM period */
+ __u16 pmt_flags; /* How to decode max/min PM timeout */
+ __u16 pm_capa; /* What PM options are supported */
/* Encoder stuff */
__u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
__u8 num_encoding_sizes; /* Number of entry in the list */
__u8 max_encoding_tokens; /* Max number of tokens */
+
+ /* Transmit power */
+ __u16 txpower_capa; /* What options are supported */
+ __u8 num_txpower; /* Number of entries in the list */
+ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */
};
/*
shp->u.shm_perm.mode |= SHM_DEST;
if (shp->u.shm_nattch <= 0)
killseg (id);
+ /* Do not find it any more */
+ shp->u.shm_perm.key = IPC_PRIVATE;
break;
}
err = -EPERM;
function string () {
old=$(eval echo "\${$2}")
def=${old:-$3}
- readln "$1 ($2) [$def] " "$def" "$old"
+ while :; do
+ if [ "$old" = "?" ]; then
+ readln "$1 ($2) [$def] " "$def" ""
+ else
+ readln "$1 ($2) [$def] " "$def" "$old"
+ fi
+ if [ "$ans" = "?" ]; then
+ help "$2"
+ else
+ break
+ fi
+ done
define_string "$2" "$ans"
}
#