# # Main patch # diff -urN linux-2.4.5-rmk7-np2/Makefile linux-2.4.5-rmk7-np2-ssv1/Makefile --- linux-2.4.5-rmk7-np2/Makefile Sat Jul 13 19:40:17 2002 +++ linux-2.4.5-rmk7-np2-ssv1/Makefile Fri Dec 7 11:32:28 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 5 -EXTRAVERSION =-rmk7-np2 +EXTRAVERSION =-rmk7-np2-ssv1 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -19,7 +19,8 @@ HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -CROSS_COMPILE = arm-linux- +CROSS_COMPILE = /usr/local/arm/2.95.2/bin/arm-linux- +#CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux- # # Include the make variables (CC, etc...) diff -urN linux-2.4.5-rmk7-np2/arch/arm/config.in linux-2.4.5-rmk7-np2-ssv1/arch/arm/config.in --- linux-2.4.5-rmk7-np2/arch/arm/config.in Sat Jul 13 19:40:17 2002 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/config.in Wed Oct 10 21:01:03 2001 @@ -65,6 +65,11 @@ mainmenu_option next_comment comment 'SA11x0 Implementations' + +#-------------------- SSV-CHANGE --------------------------- +dep_bool ' DNP/1110' CONFIG_SA1100_DNP1110 $CONFIG_ARCH_SA1100 +#---------------------------------------------------------------- + dep_bool ' Assabet' CONFIG_SA1100_ASSABET $CONFIG_ARCH_SA1100 dep_bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET $CONFIG_SA1100_ASSABET dep_bool ' Brutus' CONFIG_SA1100_BRUTUS $CONFIG_ARCH_SA1100 diff -urN linux-2.4.5-rmk7-np2/arch/arm/def-configs/dnp1110 linux-2.4.5-rmk7-np2-ssv1/arch/arm/def-configs/dnp1110 --- linux-2.4.5-rmk7-np2/arch/arm/def-configs/dnp1110 Thu Jan 1 01:00:00 1970 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/def-configs/dnp1110 Fri Nov 23 12:52:14 2001 @@ -0,0 +1,548 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_ANAKIN is not set + +# +# Archimedes/A5000 Implementations +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +CONFIG_SA1100_DNP1110=y +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_SA110 is not set +CONFIG_CPU_SA1100=y +CONFIG_DISCONTIGMEM=y +# CONFIG_CPU_BIG_ENDIAN is not set + +# +# General setup +# +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_APM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/ram0 mem=32M" +# CONFIG_PFS168_CMDLINE is not set +# CONFIG_LEDS is not set +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_SUN_UFLASH is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_SC520CDP is not set +# CONFIG_MTD_NETSC520 is not set +# CONFIG_MTD_SBC_GXX is not set +# CONFIG_MTD_ELAN_104NC is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set +# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_DBOX2 is not set +# CONFIG_MTD_CSTM_MIPS_IXX is not set +# CONFIG_MTD_CFI_FLAGADM is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_VMAX is not set +# CONFIG_MTD_OCELOT is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_SPIA is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=m +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=m +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +CONFIG_NET_VENDOR_SMC=y +# CONFIG_WD80x3 is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRA32 is not set +# CONFIG_SMC9194 is not set +CONFIG_SMC91111=m +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +# CONFIG_SERIAL_SA1100_OLD is not set +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_SA1100_DEFAULT_BAUDRATE=115200 +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +# CONFIG_UCB1200 is not set +# CONFIG_TOUCHSCREEN_UCB1200 is not set +# CONFIG_AUDIO_UCB1200 is not set +# CONFIG_ADC_UCB1200 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set +# CONFIG_PROFILER is not set +# CONFIG_PFS168_SPI is not set +# CONFIG_PFS168_DTMF is not set +# CONFIG_PFS168_MISC is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +CONFIG_SA1100_RTC=m +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=y +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_EXT2_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=m +CONFIG_NFS_V3=y +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=m +CONFIG_LOCKD=m +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set diff -urN linux-2.4.5-rmk7-np2/arch/arm/mach-sa1100/Makefile linux-2.4.5-rmk7-np2-ssv1/arch/arm/mach-sa1100/Makefile --- linux-2.4.5-rmk7-np2/arch/arm/mach-sa1100/Makefile Sat Jul 13 19:40:17 2002 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/mach-sa1100/Makefile Wed Oct 10 21:01:28 2001 @@ -31,6 +31,11 @@ endif # Specific board support + +#------------- SSV-CHANGE -------------- +obj-$(CONFIG_SA1100_DNP1110) += dnp1110.o +#------------------------------------------- + obj-$(CONFIG_SA1100_ASSABET) += assabet.o obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o obj-$(CONFIG_SA1100_BITSY) += bitsy.o diff -urN linux-2.4.5-rmk7-np2/arch/arm/mach-sa1100/dnp1110.c linux-2.4.5-rmk7-np2-ssv1/arch/arm/mach-sa1100/dnp1110.c --- linux-2.4.5-rmk7-np2/arch/arm/mach-sa1100/dnp1110.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/mach-sa1100/dnp1110.c Mon Nov 26 09:36:04 2001 @@ -0,0 +1,92 @@ +/* + * linux/arch/arm/mach-sa1100/dnp1110.c + * + * Author: Marco Hasewinkel + * + * This file contains all DNP/1110 specific tweaks + * for "DNP/1110 - mha@ssv " + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "generic.h" + +static int __init dnp1110_init(void) +{ + GPDR = 0x08000000; /* GPIO0-GPIO26 to Input */ + /* GPIO27 to Output */ + + GAFR = 0x08000000; /* alternate function on GPIO27 */ + + TUCR = 0x20000000; /* set 3.6864 MHz out to GPIO27 */ + + MECR = 0x1CE71CE7; /* PCMCIA Socket 0 & 1 Timing */ + /* 3*(7+1)*9,7ns = 233ns - FIXME !!!*/ + return 0; +} + +__initcall(dnp1110_init); + + +static void __init +fixup_dnp1110(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + SET_BANK(0, 0xc0000000, 32*1024*1024); /* DNP/1110 32MB */ +// SET_BANK(0, 0xc0000000, 16*1024*1024); /* DNP/1110 16MB */ + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + setup_initrd(0xc0400000, 3*1024*1024); /* max 3MB INITRAMDISK */ +} + +static struct map_desc dnp1110_io_desc[] __initdata = { + /* virtual physical length domain r w c b */ + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + LAST_DESC +}; + +static void __init dnp1110_map_io(void) +{ + sa1100_map_io(); + iotable_init(dnp1110_io_desc); + + sa1100_register_uart(0, 1); /* COM1 = ttySA0 (SA UART 1) */ + sa1100_register_uart(1, 3); /* COM2 = ttySA1 (SA UART 3) */ +} + +static void __init dnp1110_init_irq(void) +{ + +/* first default SA11X0 IRQ mapping */ + sa1100_init_irq(); + +/* then dnp/1110 special IRQ mapping */ + set_GPIO_IRQ_edge(GPIO_GPIO(0), GPIO_RISING_EDGE); /* USER INT 1 */ + set_GPIO_IRQ_edge(GPIO_GPIO(1), GPIO_RISING_EDGE); /* USER INT 2 */ + set_GPIO_IRQ_edge(GPIO_GPIO(2), GPIO_RISING_EDGE); /* USER INT 3 */ + set_GPIO_IRQ_edge(GPIO_GPIO(3), GPIO_RISING_EDGE); /* USER INT 4 */ + set_GPIO_IRQ_edge(GPIO_GPIO(4), GPIO_RISING_EDGE); /* USER INT 4 */ + + set_GPIO_IRQ_edge(GPIO_GPIO(5), GPIO_RISING_EDGE); /* LAN */ + set_GPIO_IRQ_edge(GPIO_GPIO(6), GPIO_RISING_EDGE); /* SSV only */ +} + +MACHINE_START(DNP1110, "DNP/1110 - SSV Embedded Systems") + MAINTAINER("mha@ssv - ") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_dnp1110) + MAPIO(dnp1110_map_io) + INITIRQ(dnp1110_init_irq) +MACHINE_END diff -urN linux-2.4.5-rmk7-np2/arch/arm/tools/mach-types linux-2.4.5-rmk7-np2-ssv1/arch/arm/tools/mach-types --- linux-2.4.5-rmk7-np2/arch/arm/tools/mach-types Sat Jul 13 19:35:15 2002 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/tools/mach-types Wed Oct 10 21:04:45 2001 @@ -99,4 +99,8 @@ pda1 ARCH_PDA1 PDA1 88 lubbock ARCH_LUBBOCK LUBBOCK 89 +#--------------------- SSV-CHANGE --------------------------------- +dnp1110 SA1100_DNP1110 DNP1110 255 +#-------------------------------------------------------------------------- + # The following are unallocated diff -urN linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/dnp1110.h linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/dnp1110.h --- linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/dnp1110.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/dnp1110.h Wed Oct 10 21:24:33 2001 @@ -0,0 +1,13 @@ +/* + * linux/include/asm-arm/arch-sa1100/dnp1110.h + * + * Created 2001/08/18 by mha@ssv + * + * This file contains the hardware specific definitions for + * DNP/1110 + * + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#error "include instead" +#endif diff -urN linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/hardware.h linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/hardware.h --- linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/hardware.h Sat Jul 13 19:35:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/hardware.h Fri Dec 7 11:35:29 2001 @@ -86,6 +86,12 @@ * Implementation specifics */ +//---------- SSV-CHANGE ---------- +#ifdef CONFIG_SA1100_SSV +#include "dnp1110.h" +#endif +//---------------------------------------- + #ifdef CONFIG_SA1100_PANGOLIN #include "pangolin.h" #endif diff -urN linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/uncompress.h linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/uncompress.h --- linux-2.4.5-rmk7-np2/include/asm-arm/arch-sa1100/uncompress.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/include/asm-arm/arch-sa1100/uncompress.h Mon Oct 22 15:40:04 2001 @@ -40,8 +40,14 @@ else if (machine_is_empeg() || machine_is_bitsy() || machine_is_victor() || machine_is_lart() || machine_is_sherman() || machine_is_yopy() || - machine_is_huw_webpanel() || machine_is_itsy() ) + machine_is_huw_webpanel() || machine_is_itsy()) serial_port = _Ser3UTCR0; + +//--------------- SSV-CHANGE --------------- + else if (machine_is_dnp1110()) + serial_port = _Ser1UTCR0; +//------------------------------------------------------------ + else return; diff -urN linux-2.4.5-rmk7-np2/include/linux/mmzone.h linux-2.4.5-rmk7-np2-ssv1/include/linux/mmzone.h --- linux-2.4.5-rmk7-np2/include/linux/mmzone.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/include/linux/mmzone.h Fri Dec 7 11:35:16 2001 @@ -12,11 +12,7 @@ * Free memory management - zoned buddy allocator. */ -#ifdef CONFIG_SA1111 -#define MAX_ORDER 9 -#else #define MAX_ORDER 10 -#endif typedef struct free_area_struct { struct list_head free_list; diff -urN linux-2.4.5-rmk7-np2/init/version.c linux-2.4.5-rmk7-np2-ssv1/init/version.c --- linux-2.4.5-rmk7-np2/init/version.c Mon Oct 2 20:57:01 2000 +++ linux-2.4.5-rmk7-np2-ssv1/init/version.c Fri Nov 23 13:09:10 2001 @@ -23,4 +23,4 @@ const char *linux_banner = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; + LINUX_COMPILE_HOST ") SSV20011123 (" LINUX_COMPILER ") " UTS_VERSION "\n"; # # Unclear # diff -urN linux-2.4.5-rmk7-np2/arch/arm/def-configs/assabet linux-2.4.5-rmk7-np2-ssv1/arch/arm/def-configs/assabet --- linux-2.4.5-rmk7-np2/arch/arm/def-configs/assabet Sat Jul 13 19:40:17 2002 +++ linux-2.4.5-rmk7-np2-ssv1/arch/arm/def-configs/assabet Wed Oct 10 18:56:02 2001 @@ -139,7 +139,7 @@ # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set -CONFIG_PM=y +# CONFIG_PM is not set # CONFIG_APM is not set # CONFIG_ARTHUR is not set CONFIG_CMDLINE="" @@ -566,6 +566,7 @@ # CONFIG_NVRAM is not set # CONFIG_RTC is not set CONFIG_SA1100_RTC=y +CONFIG_SA1100_RTC=y # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -756,8 +757,8 @@ # Sound # CONFIG_SOUND=y -CONFIG_SOUND_ASSABET_UDA1341=y -# CONFIG_SOUND_UDA1341 is not set +CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_SA1100_SSP is not set # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set diff -urN linux-2.4.5-rmk7-np2/drivers/pcmcia/sa1100.h linux-2.4.5-rmk7-np2-ssv1/drivers/pcmcia/sa1100.h --- linux-2.4.5-rmk7-np2/drivers/pcmcia/sa1100.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/pcmcia/sa1100.h Wed Oct 10 18:56:03 2001 @@ -45,6 +45,15 @@ /* MECR: Expansion Memory Configuration Register * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) * + * BS_xx = ( PCMCIA_CYCLE / ( 2 * 3 * CPU_CYCLE ) ) - 1 + * + * Official PCMCIA cycle times: + * + * - I/O: 255ns + * - attribute: 300ns + * - common memory (3.3V): 600, 250, 200, 150, 100ns + * - common memory (5V): 250, 200, 150, 100ns + * * MECR layout is: * * FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0> diff -urN linux-2.4.5-rmk7-np2/drivers/pcmcia/sa1100_generic.c linux-2.4.5-rmk7-np2-ssv1/drivers/pcmcia/sa1100_generic.c --- linux-2.4.5-rmk7-np2/drivers/pcmcia/sa1100_generic.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/pcmcia/sa1100_generic.c Wed Oct 10 18:56:03 2001 @@ -1062,33 +1062,6 @@ #ifdef CONFIG_CPU_FREQ -/* sa1100_pcmcia_update_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due - * to a core clock frequency change) is needed, this routine establishes - * new BS_xx values consistent with the clock speed `clock'. - */ -static void sa1100_pcmcia_update_mecr(unsigned int clock){ - unsigned int sock; - unsigned long mecr = MECR; - - for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){ - - MECR_BSIO_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io, - clock)); - MECR_BSA_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr, - clock)); - MECR_BSM_SET(mecr, sock, - sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem, - clock)); - } - - MECR = mecr; - -} - /* sa1100_pcmcia_notifier() * ^^^^^^^^^^^^^^^^^^^^^^^^ * When changing the processor core clock frequency, it is necessary @@ -1101,41 +1074,29 @@ */ static int sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, void *data){ + unsigned int sock, clock; + unsigned long mecr = MECR; struct cpufreq_info *ci = data; - switch(val){ - case CPUFREQ_MINMAX: - - break; - - case CPUFREQ_PRECHANGE: - - if(ci->new_freq > ci->old_freq){ - DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", - __FUNCTION__, - ci->new_freq / 1000, (ci->new_freq / 100) % 10, - ci->old_freq / 1000, (ci->old_freq / 100) % 10); - sa1100_pcmcia_update_mecr(ci->new_freq); - } - - break; + clock = ci->new_freq; + switch(val){ case CPUFREQ_POSTCHANGE: - if(ci->new_freq < ci->old_freq){ - DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", - __FUNCTION__, - ci->new_freq / 1000, (ci->new_freq / 100) % 10, - ci->old_freq / 1000, (ci->old_freq / 100) % 10); - sa1100_pcmcia_update_mecr(ci->new_freq); + for(sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock){ + + MECR_BSIO_SET(mecr, sock, + sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_io, + clock)); + MECR_BSA_SET(mecr, sock, + sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_attr, + clock)); + MECR_BSM_SET(mecr, sock, + sa1100_pcmcia_mecr_bs(sa1100_pcmcia_socket[sock].speed_mem, + clock)); } - break; - - default: - printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__, - val); - return -1; + MECR = mecr; } # # Watchdog Driver # diff -urN linux-2.4.5-rmk7-np2/drivers/char/sa1100_wdt.c linux-2.4.5-rmk7-np2-ssv1/drivers/char/sa1100_wdt.c --- linux-2.4.5-rmk7-np2/drivers/char/sa1100_wdt.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/char/sa1100_wdt.c Wed Oct 10 18:56:02 2001 @@ -1,5 +1,5 @@ /* - * Watchdog driver for the SA11x0 + * SA-1100 Watchdog 0.01: A Software Watchdog Device * * (c) Copyright 2000 Oleg Drokin * Based on SoftDog driver by Alan Cox @@ -31,7 +31,8 @@ #include #include #include -#include +// #include +#include #define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ @@ -48,15 +49,22 @@ static int sa1100dog_open(struct inode *inode, struct file *file) { - if(test_and_set_bit(1,&sa1100wdt_users)) + int temp; + if(sa1100wdt_users) return -EBUSY; MOD_INC_USE_COUNT; +// printk("OSCR = %d, OSMR3 = %d OSSR = %d OIER = %d OWER = %d\n",OSCR, OSMR3, OSSR, OIER, OWER); /* Activate SA1100 Watchdog timer */ pre_margin=3686400 * sa1100_margin; OSMR3 = OSCR + pre_margin; - OSSR = OSSR_M3; - OWER = OWER_WME; - OIER |= OIER_E3; + OWER = 1; + temp = OIER; + temp |= 8; + OIER = temp; + +// printk("OSCR = %d, OSMR3 = %d OSSR = %d OIER = %d OWER = %d\n",OSCR, OSMR3, OSSR, OIER, OWER); + + sa1100wdt_users++; return 0; } @@ -67,10 +75,9 @@ * Lock it in if it's a module and we defined ...NOWAYOUT */ OSMR3 = OSCR + pre_margin; -#ifndef CONFIG_WATCHDOG_NOWAYOUT - OIER &= ~OIER_E3; -#endif - sa1100wdt_users = 0; + sa1100wdt_users--; + printk("Warning! Expect armageddon in %d seconds\n",sa1100_margin); +// printk("OSCR = %d, OSMR3 = %d OSSR = %d\n",OSCR, OSMR3, OSSR); MOD_DEC_USE_COUNT; return 0; } @@ -81,6 +88,7 @@ if (ppos != &file->f_pos) return -ESPIPE; +// printk("OSCR = %d, OSMR3 = %d OSSR = %d\n",OSCR, OSMR3, OSSR); /* Refresh OSMR3 timer. */ if(len) { OSMR3 = OSCR + pre_margin; @@ -92,22 +100,27 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - static struct watchdog_info ident = { - identity: "SA1100 Watchdog", + static struct watchdog_info ident= + { + 0, + 0, + "SA1100 Watchdog" }; - - switch(cmd){ - default: - return -ENOIOCTLCMD; - case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); - case WDIOC_GETSTATUS: - return put_user(0,(int *)arg); - case WDIOC_GETBOOTSTATUS: - return put_user((RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0, (int *)arg); - case WDIOC_KEEPALIVE: - OSMR3 = OSCR + pre_margin; - return 0; + 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: + case WDIOC_GETBOOTSTATUS: + return put_user(0,(int *)arg); + + case WDIOC_KEEPALIVE: + OSMR3 = OSCR + pre_margin; + return 0; } } @@ -136,7 +149,7 @@ if (ret) return ret; - printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin); + printk("SA1100 Watchdog Timer: 0.01, timer margin: %d sec\n", sa1100_margin); return 0; } # # Serial Driver # diff -urN linux-2.4.5-rmk7-np2/drivers/char/serial_core.c linux-2.4.5-rmk7-np2-ssv1/drivers/char/serial_core.c --- linux-2.4.5-rmk7-np2/drivers/char/serial_core.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/char/serial_core.c Wed Oct 10 18:56:02 2001 @@ -1230,7 +1230,6 @@ struct uart_register *reg = (struct uart_register *)tty->driver.driver_state; struct uart_info *info; int retval, line = MINOR(tty->device) - tty->driver.minor_start; - int changed_termios = 0; #ifdef DEBUG printk("uart_open(%d) called\n", line); @@ -1277,15 +1276,15 @@ goto out; } +#ifdef CONFIG_PM /* * Make sure the device is in D0 state. */ if (info->state->count == 1) -#ifdef CONFIG_PM pm_send(info->state->pm, PM_RESUME, (void *)0); #else - if (info->port->ops->pm) - info->port->ops->pm(info->port, 0, 3); + if (info->port->ops->pm) + info->port->ops->pm(info->port, 0, 3); #endif /* @@ -1305,7 +1304,7 @@ *tty->termios = info->state->normal_termios; else *tty->termios = info->state->callout_termios; - changed_termios = 1; + uart_change_speed(info, NULL); } #ifdef CONFIG_SERIAL_CORE_CONSOLE /* @@ -1316,13 +1315,9 @@ if (c && c->cflag && c->index == line) { tty->termios->c_cflag = c->cflag; c->cflag = 0; - changed_termios = 1; } } #endif - if (changed_termios) - uart_change_speed(info, NULL); - info->session = current->session; info->pgrp = current->pgrp; return 0; diff -urN linux-2.4.5-rmk7-np2/drivers/char/serial_sa1100.c linux-2.4.5-rmk7-np2-ssv1/drivers/char/serial_sa1100.c --- linux-2.4.5-rmk7-np2/drivers/char/serial_sa1100.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/char/serial_sa1100.c Wed Oct 10 18:56:02 2001 @@ -680,10 +680,10 @@ static struct uart_register sa1100_reg = { owner: THIS_MODULE, normal_major: SERIAL_SA1100_MAJOR, - normal_name: "ttySA%d", + normal_name: "ttySA", normal_driver: &normal, callout_major: CALLOUT_SA1100_MAJOR, - callout_name: "cusa%d", + callout_name: "cusa", callout_driver: &callout, table: sa1100_table, termios: sa1100_termios, # # SMC 9111 Ethernet Driver # diff -urN linux-2.4.5-rmk7-np2/drivers/net/Config.in linux-2.4.5-rmk7-np2-ssv1/drivers/net/Config.in --- linux-2.4.5-rmk7-np2/drivers/net/Config.in Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/Config.in Wed Oct 10 22:09:52 2001 @@ -92,6 +92,7 @@ tristate ' SMC Ultra support' CONFIG_ULTRA dep_tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA tristate ' SMC 9194 support' CONFIG_SMC9194 + tristate ' SMC 91111 support for DNP/1110' CONFIG_SMC91111 fi bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then diff -urN linux-2.4.5-rmk7-np2/drivers/net/Makefile linux-2.4.5-rmk7-np2-ssv1/drivers/net/Makefile --- linux-2.4.5-rmk7-np2/drivers/net/Makefile Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/Makefile Wed Oct 10 22:03:59 2001 @@ -113,6 +113,7 @@ obj-$(CONFIG_SK_G16) += sk_g16.o obj-$(CONFIG_HP100) += hp100.o obj-$(CONFIG_SMC9194) += smc9194.o +obj-$(CONFIG_SMC91111) += smc91111.o obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o obj-$(CONFIG_CERF_CS8900A) += cerf89x0.o obj-$(CONFIG_ARM_ETHERH) += 8390.o diff -urN linux-2.4.5-rmk7-np2/drivers/net/Space.c linux-2.4.5-rmk7-np2-ssv1/drivers/net/Space.c --- linux-2.4.5-rmk7-np2/drivers/net/Space.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/Space.c Wed Oct 10 22:08:06 2001 @@ -254,6 +254,9 @@ #ifdef CONFIG_SMC9194 {smc_init, 0}, #endif +#ifdef CONFIG_SMC91111 + {smc_init, 0}, +#endif #ifdef CONFIG_SEEQ8005 {seeq8005_probe, 0}, #endif diff -urN linux-2.4.5-rmk7-np2/drivers/net/smc91111.c linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc91111.c --- linux-2.4.5-rmk7-np2/drivers/net/smc91111.c Thu Jan 1 01:00:00 1970 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc91111.c Fri Nov 23 12:32:06 2001 @@ -0,0 +1,3800 @@ +/*------------------------------------------------------------------------ + . smc91111.c + . This is a driver for SMSC's 91C111 single-chip Ethernet device. + . + . Copyright (C) 2001 Standard Microsystems Corporation (SMSC) + . Developed by Simple Network Magic Corporation (SNMC) + . Copyright (C) 1996 by Erik Stahlman (ES) + . + . 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. + . + . 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + . + . Information contained in this file was obtained from the LAN91C111 + . manual from SMC. To get a copy, if you really want one, you can find + . information under www.smsc.com. + . + . + . "Features" of the SMC chip: + . Integrated PHY/MAC for 10/100BaseT Operation + . Supports internal and external MII + . Integrated 8K packet memory + . EEPROM interface for configuration + . + . Arguments: + . io = for the base address + . irq = for the IRQ + . + . author: + . Erik Stahlman ( erik@vt.edu ) + . Daris A Nevil ( dnevil@snmc.com ) + . + . + . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) + . + . Sources: + . o SMSC LAN91C111 databook (www.smsc.com) + . o smc9194.c by Erik Stahlman + . o skeleton.c by Donald Becker ( becker@cesdis.gsfc.nasa.gov ) + . + . History: + . 10/17/01 Marco Hasewinkel Modify for DNP/1110 + . 07/25/01 Woojung Huh Modify for ADS Bitsy + . 04/25/01 Daris A Nevil Initial public release through SMSC + . 03/16/01 Daris A Nevil Modified smc9194.c for use with LAN91C111 + ----------------------------------------------------------------------------*/ + +// Use power-down feature of the chip +#define POWER_DOWN 0 + +#define NO_AUTOPROBE + +static const char version[] = + "smc91111.c:v1.0 04/25/01 by Daris A Nevil (dnevil@snmc.com)\n"; + +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SYSCTL +#include +#include +#endif + +#include "smc91111.h" +/*------------------------------------------------------------------------ + . + . Configuration options, for the experienced user to change. + . + -------------------------------------------------------------------------*/ + +/* + . Do you want to use 32 bit xfers? This should work on all chips, as + . the chipset is designed to accommodate them. +*/ +#ifdef CONFIG_ISA +#define USE_32_BIT 1 + +/* + .the LAN91C111 can be at any of the following port addresses. To change, + .for a slightly different card, you can add it to the array. Keep in + .mind that the array must end in zero. +*/ +static unsigned int smc_portlist[] __initdata = + { 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, + 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0}; + +#endif + +/* + . Wait time for memory to be free. This probably shouldn't be + . tuned that much, as waiting for this means nothing else happens + . in the system +*/ +#define MEMORY_WAIT_TIME 16 + + +#if (SMC_DEBUG > 2 ) +#define PRINTK3(args...) printk(args) +#else +#define PRINTK3(args...) +#endif + +#if SMC_DEBUG > 1 +#define PRINTK2(args...) printk(args) +#else +#define PRINTK2(args...) +#endif + +#ifdef SMC_DEBUG +#define PRINTK(args...) printk(args) +#else +#define PRINTK(args...) +#endif + + +/*------------------------------------------------------------------------ + . + . The internal workings of the driver. If you are changing anything + . here with the SMC stuff, you should have the datasheet and know + . what you are doing. + . + -------------------------------------------------------------------------*/ +#define CARDNAME "LAN91C111" + +// Memory sizing constant +#define LAN91C111_MEMORY_MULTIPLIER (1024*2) + +/* store this information for the driver.. */ +struct smc_local { + + // these are things that the kernel wants me to keep, so users + // can find out semi-useless statistics of how well the card is + // performing + struct net_device_stats stats; + + // If I have to wait until memory is available to send + // a packet, I will store the skbuff here, until I get the + // desired memory. Then, I'll send it out and free it. + struct sk_buff * saved_skb; + + // This keeps track of how many packets that I have + // sent out. When an TX_EMPTY interrupt comes, I know + // that all of these have been sent. + int packets_waiting; + + // Set to true during the auto-negotiation sequence + int autoneg_active; + + // Address of our PHY port + word phyaddr; + + // Type of PHY + word phytype; + + // Last contents of PHY Register 18 + word lastPhy18; + + // Contains the current active transmission mode + word tcr_cur_mode; + + // Contains the current active receive mode + word rcr_cur_mode; + + // Contains the current active receive/phy mode + word rpc_cur_mode; + + +#ifdef CONFIG_SYSCTL + + // Root directory /proc/sys/dev + // Second entry must be null to terminate the table + ctl_table root_table[2]; + + // Directory for this device /proc/sys/dev/ethX + // Again the second entry must be zero to terminate + ctl_table eth_table[2]; + + // This is the parameters (file) table + ctl_table param_table[CTL_SMC_LAST_ENTRY]; + + // Saves the sysctl header returned by register_sysctl_table() + // we send this to unregister_sysctl_table() + struct ctl_table_header *sysctl_header; + + // Parameter variables (files) go here + char ctl_info[1024]; + int ctl_swfdup; + int ctl_ephloop; + int ctl_miiop; + int ctl_autoneg; + int ctl_rfduplx; + int ctl_rspeed; + int ctl_afduplx; + int ctl_aspeed; + int ctl_lnkfail; + int ctl_forcol; + int ctl_filtcar; + int ctl_freemem; + int ctl_totmem; + int ctl_leda; + int ctl_ledb; + int ctl_chiprev; +#ifdef SMC_DEBUG + int ctl_reg_bsr; + int ctl_reg_tcr; + int ctl_reg_esr; + int ctl_reg_rcr; + int ctl_reg_ctrr; + int ctl_reg_mir; + int ctl_reg_rpcr; + int ctl_reg_cfgr; + int ctl_reg_bar; + int ctl_reg_iar0; + int ctl_reg_iar1; + int ctl_reg_iar2; + int ctl_reg_gpr; + int ctl_reg_ctlr; + int ctl_reg_mcr; + int ctl_reg_pnr; + int ctl_reg_fpr; + int ctl_reg_ptr; + int ctl_reg_dr; + int ctl_reg_isr; + int ctl_reg_mtr1; + int ctl_reg_mtr2; + int ctl_reg_mtr3; + int ctl_reg_mtr4; + int ctl_reg_miir; + int ctl_reg_revr; + int ctl_reg_ercvr; + int ctl_reg_extr; + int ctl_phy_ctrl; + int ctl_phy_stat; + int ctl_phy_id1; + int ctl_phy_id2; + int ctl_phy_adc; + int ctl_phy_remc; + int ctl_phy_cfg1; + int ctl_phy_cfg2; + int ctl_phy_int; + int ctl_phy_mask; +#endif // SMC_DEBUG + + +#endif // CONFIG_SYSCTL + +}; + + +/*----------------------------------------------------------------- + . + . The driver can be entered at any of the following entry points. + . + .------------------------------------------------------------------ */ + +/* + . This is called by register_netdev(). It is responsible for + . checking the portlist for the SMC9000 series chipset. If it finds + . one, then it will initialize the device, find the hardware information, + . and sets up the appropriate device parameters. + . NOTE: Interrupts are *OFF* when this procedure is called. + . + . NB:This shouldn't be static since it is referred to externally. +*/ +int smc_init(struct net_device *dev); + +/* + . This is called by unregister_netdev(). It is responsible for + . cleaning up before the driver is finally unregistered and discarded. +*/ +void smc_destructor(struct net_device *dev); + +/* + . The kernel calls this function when someone wants to use the device, + . typically 'ifconfig ethX up'. +*/ +static int smc_open(struct net_device *dev); + +#if 0 //;my +/* + . This is called by the kernel to send a packet out into the net. it's + . responsible for doing a best-effort send, but if it's simply not possible + . to send it, the packet gets dropped. +*/ +static int smc_send_packet(struct sk_buff *skb, struct net_device *dev); +#endif //;my + +/* + . This is called by the kernel in response to 'ifconfig ethX down'. It + . is responsible for cleaning up everything that the open routine + . does, and maybe putting the card into a powerdown state. +*/ +static int smc_close(struct net_device *dev); + +/* + . This routine allows the proc file system to query the driver's + . statistics. +*/ +static struct net_device_stats * smc_query_statistics( struct net_device *dev); + +/* + . Finally, a call to set promiscuous mode ( for TCPDUMP and related + . programs ) and multicast modes. +*/ +static void smc_set_multicast_list(struct net_device *dev); + +/* + . Configures the PHY through the MII Management interface +*/ +static void smc_phy_configure(struct net_device* dev); + +/*--------------------------------------------------------------- + . + . Interrupt level calls.. + . + ----------------------------------------------------------------*/ + +/* + . Handles the actual interrupt +*/ +static void smc_interrupt(int irq, void *, struct pt_regs *regs); +/* + . This is a separate procedure to handle the receipt of a packet, to + . leave the interrupt code looking slightly cleaner +*/ +inline static void smc_rcv( struct net_device *dev ); +/* + . This handles a TX interrupt, which is only called when an error + . relating to a packet is sent. +*/ +inline static void smc_tx( struct net_device * dev ); + +/* + . This handles interrupts generated from PHY register 18 +*/ +static void smc_phy_interrupt(struct net_device* dev); + +/* + ------------------------------------------------------------ + . + . Internal routines + . + ------------------------------------------------------------ +*/ + +/* + . Test if a given location contains a chip, trying to cause as + . little damage as possible if it's not a SMC chip. +*/ +static int smc_probe( struct net_device *, int ioaddr ); + +/* + . A rather simple routine to print out a packet for debugging purposes. +*/ +#if SMC_DEBUG > 2 +static void print_packet( byte *, int ); +#endif + +#define tx_done(dev) 1 + +/* this is called to actually send the packet to the chip */ +static void smc_hardware_send_packet( struct net_device * dev ); + +/* Since I am not sure if I will have enough room in the chip's ram + . to store the packet, I call this routine, which either sends it + . now, or generates an interrupt when the card is ready for the + . packet */ +static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev ); + +/* this does a soft reset on the device */ +static void smc_reset( struct net_device* dev ); + +/* Enable Interrupts, Receive, and Transmit */ +static void smc_enable( struct net_device *dev ); + +/* this puts the device in an inactive state */ +static void smc_shutdown( int ioaddr ); + +#ifndef NO_AUTOPROBE +/* This routine will find the IRQ of the driver if one is not + . specified in the input to the device. */ +static int smc_findirq( int ioaddr ); +#endif + +/* + this routine will set the hardware multicast table to the specified + values given it by the higher level routines +*/ +static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * ); +static int crc32( char *, int ); + +/* Routines to Read and Write the PHY Registers across the + MII Management Interface +*/ + +static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg); +static void smc_write_phy_register(int ioaddr, + byte phyaddr, byte phyreg, word phydata); + +/* + Initilizes our device's sysctl proc filesystem +*/ + +#ifdef CONFIG_SYSCTL +static void smc_sysctl_register(struct net_device *dev); +static void smc_sysctl_unregister(struct net_device *dev); +#endif /* CONFIG_SYSCTL */ + +/* + . Function: smc_reset( struct net_device* dev ) + . Purpose: + . This sets the SMC91111 chip to its normal state, hopefully from whatever + . mess that any other DOS driver has put it in. + . + . Maybe I should reset more registers to defaults in here? SOFTRST should + . do that for me. + . + . Method: + . 1. send a SOFT RESET + . 2. wait for it to finish + . 3. enable autorelease mode + . 4. reset the memory management unit + . 5. clear all interrupts + . +*/ +static void smc_reset( struct net_device* dev ) +{ + //struct smc_local *lp = (struct smc_local *)dev->priv; + int ioaddr = dev->base_addr; + + PRINTK2("%s:smc_reset\n", dev->name); + + /* This resets the registers mostly to defaults, but doesn't + affect EEPROM. That seems unnecessary */ + SMC_SELECT_BANK( 0 ); + SMC_outw( RCR_SOFTRST, RCR_REG ); + + /* Setup the Configuration Register */ + /* This is necessary because the CONFIG_REG is not affected */ + /* by a soft reset */ + + SMC_SELECT_BANK( 1 ); + SMC_outw( CONFIG_DEFAULT, CONFIG_REG); + + /* Setup for fast accesses if requested */ + /* If the card/system can't handle it then there will */ + /* be no recovery except for a hard reset or power cycle */ + + if (dev->dma) + SMC_outw( SMC_inw( CONFIG_REG ) | CONFIG_NO_WAIT, CONFIG_REG ); + +#ifdef POWER_DOWN + /* Release from possible power-down state */ + /* Configuration register is not affected by Soft Reset */ + SMC_SELECT_BANK( 1 ); + SMC_outw( SMC_inw( CONFIG_REG ) | CONFIG_EPH_POWER_EN, CONFIG_REG ); +#endif + + SMC_SELECT_BANK( 0 ); + + /* this should pause enough for the chip to be happy */ + mdelay(10); + + /* Disable transmit and receive functionality */ + SMC_outw( RCR_CLEAR, RCR_REG ); + SMC_outw( TCR_CLEAR, TCR_REG ); + + /* set the control register to automatically + release successfully transmitted packets, to make the best + use out of our limited memory */ + SMC_SELECT_BANK( 1 ); + SMC_outw( SMC_inw( CTL_REG ) | CTL_AUTO_RELEASE , CTL_REG ); + + /* Reset the MMU */ + SMC_SELECT_BANK( 2 ); + SMC_outw( MC_RESET, MMU_CMD_REG ); + + /* Note: It doesn't seem that waiting for the MMU busy is needed here, + but this is a place where future chipsets _COULD_ break. Be wary + of issuing another MMU command right after this */ + + /* Disable all interrupts */ + SMC_outb( 0, IM_REG ); +} + +/* + . Function: smc_enable + . Purpose: let the chip talk to the outside work + . Method: + . 1. Enable the transmitter + . 2. Enable the receiver + . 3. Enable interrupts +*/ +static void smc_enable( struct net_device *dev ) +{ + unsigned int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + + PRINTK2("%s:smc_enable\n", dev->name); + SMC_SELECT_BANK( 0 ); + /* see the header file for options in TCR/RCR DEFAULT*/ + SMC_outw( lp->tcr_cur_mode, TCR_REG ); + SMC_outw( lp->rcr_cur_mode, RCR_REG ); + + /* now, enable interrupts */ + SMC_SELECT_BANK( 2 ); + SMC_outb( SMC_INTERRUPT_MASK, IM_REG ); +} + +/* + . Function: smc_shutdown + . Purpose: closes down the SMC91xxx chip. + . Method: + . 1. zero the interrupt mask + . 2. clear the enable receive flag + . 3. clear the enable xmit flags + . + . TODO: + . (1) maybe utilize power down mode. + . Why not yet? Because while the chip will go into power down mode, + . the manual says that it will wake up in response to any I/O requests + . in the register space. Empirical results do not show this working. +*/ +static void smc_shutdown( int ioaddr ) +{ + PRINTK2(CARDNAME ":smc_shutdown\n"); + + /* no more interrupts for me */ + SMC_SELECT_BANK( 2 ); + SMC_outb( 0, IM_REG ); + + /* and tell the card to stay away from that nasty outside world */ + SMC_SELECT_BANK( 0 ); + SMC_outb( RCR_CLEAR, RCR_REG ); + SMC_outb( TCR_CLEAR, TCR_REG ); + +#ifdef POWER_DOWN + /* finally, shut the chip down */ + SMC_SELECT_BANK( 1 ); + SMC_outw( SMC_inw( CONFIG_REG ) & ~CONFIG_EPH_POWER_EN, CONFIG_REG ); +#endif +} + + +/* + . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) + . Purpose: + . This sets the internal hardware table to filter out unwanted multicast + . packets before they take up memory. + . + . The SMC chip uses a hash table where the high 6 bits of the CRC of + . address are the offset into the table. If that bit is 1, then the + . multicast packet is accepted. Otherwise, it's dropped silently. + . + . To use the 6 bits as an offset into the table, the high 3 bits are the + . number of the 8 bit register, while the low 3 bits are the bit within + . that register. + . + . This routine is based very heavily on the one provided by Peter Cammaert. +*/ + + +static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { + int i; + unsigned char multicast_table[ 8 ]; + struct dev_mc_list * cur_addr; + /* table for flipping the order of 3 bits */ + unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + + PRINTK2(CARDNAME ":smc_setmulticast\n"); + + /* start with a table of all zeros: reject all */ + memset( multicast_table, 0, sizeof( multicast_table ) ); + + cur_addr = addrs; + for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { + int position; + + /* do we have a pointer here? */ + if ( !cur_addr ) + break; + /* make sure this is a multicast address - shouldn't this + be a given if we have it here ? */ + if ( !( *cur_addr->dmi_addr & 1 ) ) + continue; + + /* only use the low order bits */ + position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; + + /* do some messy swapping to put the bit in the right spot */ + multicast_table[invert3[position&7]] |= + (1<>3)&7]); + + } + /* now, the table can be loaded into the chipset */ + SMC_SELECT_BANK( 3 ); + + for ( i = 0; i < 8 ; i++ ) { + SMC_outb( multicast_table[i], MCAST_REG1 + i ); + } +} + +/* + Finds the CRC32 of a set of bytes. + Again, from Peter Cammaert's code. +*/ +static int crc32( char * s, int length ) { + /* indices */ + int perByte; + int perBit; + /* crc polynomial for Ethernet */ + const unsigned long poly = 0xedb88320; + /* crc value - preinitialized to all 1's */ + unsigned long crc_value = 0xffffffff; + + for ( perByte = 0; perByte < length; perByte ++ ) { + unsigned char c; + + c = *(s++); + for ( perBit = 0; perBit < 8; perBit++ ) { + crc_value = (crc_value>>1)^ + (((crc_value^c)&0x01)?poly:0); + c >>= 1; + } + } + return crc_value; +} + + +/* + . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) + . Purpose: + . Attempt to allocate memory for a packet, if chip-memory is not + . available, then tell the card to generate an interrupt when it + . is available. + . + . Algorithm: + . + . o if the saved_skb is not currently null, then drop this packet + . on the floor. This should never happen, because of TBUSY. + . o if the saved_skb is null, then replace it with the current packet, + . o See if I can sending it now. + . o (NO): Enable interrupts and let the interrupt handler deal with it. + . o (YES):Send it now. +*/ +static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + unsigned long ioaddr = dev->base_addr; + word length; + unsigned short numPages; + word time_out; + word status; + + PRINTK3("%s:smc_wait_to_send_packet\n", dev->name); + + netif_stop_queue(dev); + + if ( lp->saved_skb) { + /* THIS SHOULD NEVER HAPPEN. */ + lp->stats.tx_aborted_errors++; + printk("%s: Bad Craziness - sent packet while busy.\n", + dev->name); + return 1; + } + lp->saved_skb = skb; + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + + + /* + ** The MMU wants the number of pages to be the number of 256 bytes + ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) + ** + ** The 91C111 ignores the size bits, but the code is left intact + ** for backwards and future compatibility. + ** + ** Pkt size for allocating is data length +6 (for additional status + ** words, length and ctl!) + ** + ** If odd size then last byte is included in this header. + */ + numPages = ((length & 0xfffe) + 6); + numPages >>= 8; // Divide by 256 + + if (numPages > 7 ) { + printk("%s: Far too big packet error. \n", dev->name); + /* freeing the packet is a good thing here... but should + . any packets of this size get down here? */ + dev_kfree_skb (skb); + lp->saved_skb = NULL; + /* this IS an error, but, i don't want the skb saved */ + netif_wake_queue(dev); + return 0; + } + /* either way, a packet is waiting now */ + lp->packets_waiting++; + + /* now, try to allocate the memory */ + SMC_SELECT_BANK( 2 ); + SMC_outw( MC_ALLOC | numPages, MMU_CMD_REG ); + /* + . Performance Hack + . + . wait a short amount of time.. if I can send a packet now, I send + . it now. Otherwise, I enable an interrupt and wait for one to be + . available. + . + . I could have handled this a slightly different way, by checking to + . see if any memory was available in the FREE MEMORY register. However, + . either way, I need to generate an allocation, and the allocation works + . no matter what, so I saw no point in checking free memory. + */ + time_out = MEMORY_WAIT_TIME; + do { + status = SMC_inb( INT_REG ); + if ( status & IM_ALLOC_INT ) { + /* acknowledge the interrupt */ + SMC_outb( IM_ALLOC_INT, INT_REG ); + break; + } + } while ( -- time_out ); + + if ( !time_out ) { + /* oh well, wait until the chip finds memory later */ + SMC_ENABLE_INT( IM_ALLOC_INT ); + + /* Check the status bit one more time just in case */ + /* it snuk in between the time we last checked it */ + /* and when we set the interrupt bit */ + status = SMC_inb( INT_REG ); + if ( !(status & IM_ALLOC_INT) ) { + PRINTK2("%s: memory allocation deferred. \n", + dev->name); + /* it's deferred, but I'll handle it later */ + return 0; + } + + /* Looks like it did sneak in, so disable */ + /* the interrupt */ + SMC_DISABLE_INT( IM_ALLOC_INT ); + } + /* or YES! I can send the packet now.. */ + smc_hardware_send_packet(dev); + netif_wake_queue(dev); + + return 0; +} + +/* + . Function: smc_hardware_send_packet(struct net_device * ) + . Purpose: + . This sends the actual packet to the SMC9xxx chip. + . + . Algorithm: + . First, see if a saved_skb is available. + . ( this should NOT be called if there is no 'saved_skb' + . Now, find the packet number that the chip allocated + . Point the data pointers at it in memory + . Set the length word in the chip's memory + . Dump the packet to chip memory + . Check if a last byte is needed ( odd length packet ) + . if so, set the control flag right + . Tell the card to send it + . Enable the transmit interrupt, so I know if it failed + . Free the kernel data if I actually sent it. +*/ +static void smc_hardware_send_packet( struct net_device * dev ) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + byte packet_no; + struct sk_buff * skb = lp->saved_skb; + word length; + unsigned long ioaddr; + byte * buf; + + PRINTK3("%s:smc_hardware_send_packet\n", dev->name); + + ioaddr = dev->base_addr; + + if ( !skb ) { + PRINTK("%s: In XMIT with no packet to send \n", dev->name); + return; + } + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + buf = skb->data; + + /* If I get here, I _know_ there is a packet slot waiting for me */ + packet_no = SMC_inb( AR_REG ); + if ( packet_no & AR_FAILED ) { + /* or isn't there? BAD CHIP! */ + printk(KERN_DEBUG "%s: Memory allocation failed. \n", + dev->name); + kfree(skb); + lp->saved_skb = NULL; + netif_wake_queue(dev); + return; + } + + /* we have a packet address, so tell the card to use it */ + SMC_outb( packet_no, PN_REG ); + + /* point to the beginning of the packet */ + SMC_outw( PTR_AUTOINC , PTR_REG ); + + PRINTK3("%s: Trying to xmit packet of length %x\n", + dev->name, length); + +#if SMC_DEBUG > 2 + printk("Transmitting Packet\n"); + print_packet( buf, length ); +#endif + + /* send the packet length ( +6 for status, length and ctl byte ) + and the status word ( set to zeros ) */ +#ifdef USE_32_BIT + SMC_outl( (length +6 ) << 16 , DATA_REG ); +#else + SMC_outw( 0, DATA_REG ); + /* send the packet length ( +6 for status words, length, and ctl*/ + SMC_outw( (length+6), DATA_REG ); +#endif + + /* send the actual data + . I _think_ it's faster to send the longs first, and then + . mop up by sending the last word. It depends heavily + . on alignment, at least on the 486. Maybe it would be + . a good idea to check which is optimal? But that could take + . almost as much time as is saved? + */ +#ifdef USE_32_BIT + outsl(ioaddr + DATA_REG, buf, length >> 2 ); + if ( length & 0x2 ) + SMC_outw(*((word *)(buf + (length & 0xFFFFFFFC))),DATA_REG); +#else + SMC_outsw(DATA_REG , buf, (length ) >> 1); +#endif // USE_32_BIT + + /* Send the last byte, if there is one. */ + if ( (length & 1) == 0 ) { + SMC_outw( 0, DATA_REG ); + } else { + SMC_outw( buf[length -1 ] | 0x2000, DATA_REG ); + } + + /* enable the interrupts */ + SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); + + /* and let the chipset deal with it */ + SMC_outw( MC_ENQUEUE , MMU_CMD_REG ); + + PRINTK2("%s: Sent packet of length %d \n", dev->name, length); + + lp->saved_skb = NULL; + dev_kfree_skb_any(skb); + + dev->trans_start = jiffies; + + /* we can send another packet */ + netif_wake_queue(dev); + + return; +} + +/*------------------------------------------------------------------------- + | + | smc_init( struct net_device * dev ) + | Input parameters: + | dev->base_addr == 0, try to find all possible locations + | dev->base_addr == 1, return failure code + | dev->base_addr == 2, always allocate space, and return success + | dev->base_addr == this is the address to check + | + | Output: + | 0 --> there is a device + | anything else, error + | + --------------------------------------------------------------------------- +*/ +int __init smc_init(struct net_device *dev) +{ +#ifdef CONFIG_ISA + int i; + int base_addr = dev ? dev->base_addr : 0; + + PRINTK2(CARDNAME ":smc_init\n"); + + /* try a specific location */ + if (base_addr > 0x1ff) { + int error; + error = smc_probe(dev, base_addr); + if ( 0 == error ) { + return smc_probe( dev, base_addr ); + } + return error; + } else { + if ( 0 != base_addr ) { + return -ENXIO; + } + } + + /* check every ethernet address */ + for (i = 0; smc_portlist[i]; i++) { + int ioaddr = smc_portlist[i]; + + /* check if the area is available */ + if (check_region( ioaddr , SMC_IO_EXTENT)) + continue; + + /* check this specific address */ + if ( smc_probe( dev, ioaddr ) == 0) { + return smc_probe( dev, ioaddr ); + } + } + + /* couldn't find anything */ + return -ENODEV; +#endif + +#ifdef CONFIG_SA1100_ADSBITSY + int base_addr = 0xF0000300; + int ret; + + PRINTK2(CARDNAME ":smc_init\n"); + + MECR &= ~0xFFFF0000; + MECR |= 0x89430000; + + // Enable Power 3.3V only + PA_DDR &= ~(GPIO_GPIO2 | GPIO_GPIO3); + PA_DWR &= ~(GPIO_GPIO2 | GPIO_GPIO3); + + PCCR |= PCCR_S1_RST | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN; + mdelay(10); + PCCR &= ~PCCR_S1_RST; + + ret = smc_probe( dev, base_addr); + if (ret < 0) { + printk("smsc 91C1111 is not found\n"); + } + + return ret; +#endif + +#ifdef CONFIG_SA1100_DNP1110 + int base_addr = 0xF6000300; /* LAN @ PCMCIA Socket 0 */ + int ret; + + PRINTK2(CARDNAME ":smc_init\n"); + + MECR &= ~0x0000FFFF; /* PCMCIA Socket 0 Timing */ + MECR |= 0x00000421; /* 3*(1+1)*9,7ns = 68ns */ + + ret = smc_probe( dev, base_addr); + if (ret < 0) { + printk("smsc 91C1111 is not found\n"); + } + + return ret; +#endif +} + + +/*------------------------------------------------------------------------- + | + | smc_destructor( struct net_device * dev ) + | Input parameters: + | dev, pointer to the device structure + | + | Output: + | None. + | + --------------------------------------------------------------------------- +*/ +void smc_destructor(struct net_device *dev) +{ + PRINTK2(CARDNAME ":smc_destructor\n"); +} + + +#ifndef NO_AUTOPROBE +/*---------------------------------------------------------------------- + . smc_findirq + . + . This routine has a simple purpose -- make the SMC chip generate an + . interrupt, so an auto-detect routine can detect it, and find the IRQ, + ------------------------------------------------------------------------ +*/ +int __init smc_findirq( int ioaddr ) +{ + int timeout = 20; + unsigned long cookie; + + PRINTK2(CARDNAME ":smc_findirq\n"); + + /* I have to do a STI() here, because this is called from + a routine that does an CLI during this process, making it + rather difficult to get interrupts for auto detection */ + sti(); + + cookie = probe_irq_on(); + + /* + * What I try to do here is trigger an ALLOC_INT. This is done + * by allocating a small chunk of memory, which will give an interrupt + * when done. + */ + + + SMC_SELECT_BANK(2); + /* enable ALLOCation interrupts ONLY */ + SMC_outb( IM_ALLOC_INT, IM_REG ); + + /* + . Allocate 512 bytes of memory. Note that the chip was just + . reset so all the memory is available + */ + SMC_outw( MC_ALLOC | 1, MMU_CMD_REG ); + + /* + . Wait until positive that the interrupt has been generated + */ + while ( timeout ) { + byte int_status; + + int_status = SMC_inb( INT_REG ); + + if ( int_status & IM_ALLOC_INT ) + break; /* got the interrupt */ + timeout--; + } + + /* there is really nothing that I can do here if timeout fails, + as autoirq_report will return a 0 anyway, which is what I + want in this case. Plus, the clean up is needed in both + cases. */ + + /* DELAY HERE! + On a fast machine, the status might change before the interrupt + is given to the processor. This means that the interrupt was + never detected, and autoirq_report fails to report anything. + This should fix autoirq_* problems. + */ + mdelay(10); + + /* and disable all interrupts again */ + SMC_outb( 0, IM_REG ); + + /* clear hardware interrupts again, because that's how it + was when I was called... */ + cli(); + + /* and return what I found */ + return probe_irq_off(cookie); +} +#endif + +/*---------------------------------------------------------------------- + . Function: smc_probe( struct net_device *, int ioaddr ) + . + . Purpose: + . Tests to see if a given ioaddr points to an SMC91111 chip. + . Returns a 0 on success + . + . Algorithm: + . (1) see if the high byte of BANK_SELECT is 0x33 + . (2) compare the ioaddr with the base register's address + . (3) see if I recognize the chip ID in the appropriate register + . + .--------------------------------------------------------------------- + */ + +static int __init smc_probe( struct net_device *dev, int ioaddr ) +{ +#ifdef CONFIG_SA1100_DNP1110 + /* MAC ADDRESS AT FLASHBLOCK 1 / OFFSET 0x10 */ + unsigned char *dnp1110_mac = (unsigned char *) (0xE8000000 + 0x20010); +#endif + int i, memory, retval; + static unsigned version_printed; + unsigned int bank; + + const char *version_string; + + word revision_register; + word memory_info_register; + + PRINTK2(CARDNAME ":smc_probe\n"); + + if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) + return -EBUSY; + + /* First, see if the high byte is 0x33 */ + bank = SMC_inw( BANK_SELECT ); + if ( (bank & 0xFF00) != 0x3300 ) { + retval = -ENODEV; + goto err_out; + } + /* The above MIGHT indicate a device, but I need to write to further + test this. */ + SMC_outw( 0x0, BANK_SELECT ); + bank = SMC_inw( BANK_SELECT ); + if ( (bank & 0xFF00 ) != 0x3300 ) { + retval = -ENODEV; + goto err_out; + } + +#ifdef CONFIG_ISA + /* well, we've already written once, so hopefully another time won't + hurt. This time, I need to switch the bank register to bank 1, + so I can access the base address register */ + SMC_SELECT_BANK(1); + base_address_register = SMC_inw( BASE_REG ); + if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { + printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)." + "Probably not a SMC chip\n", + ioaddr, base_address_register >> 3 & 0x3E0 ); + /* well, the base address register didn't match. Must not have + been a SMC chip after all. */ + return -ENODEV; + } +#endif + + /* check if the revision register is something that I recognize. + These might need to be added to later, as future revisions + could be added. */ + SMC_SELECT_BANK(3); + revision_register = SMC_inw(REV_REG); + if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { + /* I don't recognize this chip, so... */ + printk(CARDNAME ": IO %x: Unrecognized revision register:" + " %x, Contact author. \n", + ioaddr, revision_register ); + + retval = -ENODEV; + goto err_out; + } + + if (version_printed++ == 0) + printk("%s", version); + + /* Fill in some of the fields */ + dev->base_addr = ioaddr; + + /* Get MAC Address */ + SMC_SELECT_BANK( 1 ); + for ( i = 0; i < 6; i ++) { + dev->dev_addr[ i ] = (SMC_inb( ADDR0_REG + i)) & 0xFF; + } + +#ifdef CONFIG_SA1100_ADSBITSY + for ( i = 0;i < 6; i++) + if (dev->dev_addr[i] != 0 && dev->dev_addr[i] != 0xff) + break; + if (i == 6) { + printk(CARDNAME": uninitialized MAC address detected -- using a dummy one\n"); + for (i=0;i<6;i++) + dev->dev_addr[i] = i; + } +#endif + +#ifdef CONFIG_SA1100_DNP1110 + for (i=0; i<6; i++) + if ((dev->dev_addr[i] != 0) && (dev->dev_addr[i] != 0xff)) + break; + if (i==6) { + dev->dev_addr[0] = *(dnp1110_mac+0); + dev->dev_addr[1] = *(dnp1110_mac+1); + dev->dev_addr[2] = *(dnp1110_mac+2); + dev->dev_addr[3] = *(dnp1110_mac+3); + dev->dev_addr[4] = *(dnp1110_mac+4); + dev->dev_addr[5] = *(dnp1110_mac+5); + } + + for (i=0; i<6; i++) + if ((dev->dev_addr[i] != 0) && (dev->dev_addr[i] != 0xff)) + break; + if (i==6) { + printk(CARDNAME": uninitialized MAC address detected -- using a dummy one\n"); + for (i=0;i<6;i++) + dev->dev_addr[i] = i; + } +#endif + /* get the memory information */ + + SMC_SELECT_BANK( 0 ); + memory_info_register = SMC_inw( MIR_REG ); + memory = memory_info_register & (word)0x00ff; + memory *= LAN91C111_MEMORY_MULTIPLIER; + + /* + Now, I want to find out more about the chip. This is sort of + redundant, but it's cleaner to have it in both, rather than having + one VERY long probe procedure. + */ + SMC_SELECT_BANK(3); + revision_register = SMC_inw( REV_REG ); + version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; + if ( !version_string ) { + /* I shouldn't get here because this call was done before.... */ + return -ENODEV; + } + + /* now, reset the chip, and put it into a known state */ + smc_reset( dev ); + + /* + . If dev->irq is 0, then the device has to be banged on to see + . what the IRQ is. + . + . This banging doesn't always detect the IRQ, for unknown reasons. + . a workaround is to reset the chip and try again. + . + . Interestingly, the DOS packet driver *SETS* the IRQ on the card to + . be what is requested on the command line. I don't do that, mostly + . because the card that I have uses a non-standard method of accessing + . the IRQs, and because this _should_ work in most configurations. + . + . Specifying an IRQ is done with the assumption that the user knows + . what (s)he is doing. No checking is done!!!! + . + */ +#ifndef NO_AUTOPROBE + if ( dev->irq < 2 ) { + int trials; + + trials = 3; + while ( trials-- ) { + dev->irq = smc_findirq( ioaddr ); + if ( dev->irq ) + break; + /* kick the card and try again */ + smc_reset( dev ); + } + } + if (dev->irq == 0 ) { + printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", + dev->name); + return -ENODEV; + } +#else +#ifdef CONFIG_SA1100_ADSBITSY + dev->irq = GPCIN6; +#endif +#ifdef CONFIG_SA1100_DNP1110 + dev->irq = 5; /* GPIO 5 */ +#endif + if (dev->irq == 0 ) { + printk( + "%s: Autoprobing IRQs is not supported for old kernels.\n", + dev->name); + return -ENODEV; + } +#endif + if (dev->irq == 2) { + /* Fixup for users that don't know that IRQ 2 is really IRQ 9, + * or don't know which one to set. + */ + dev->irq = 9; + } + + /* now, print out the card info, in a short format.. */ + + printk("%s: %s(rev:%d) at %#3x IRQ:%d MEMSIZE:%db NOWAIT:%d ", + dev->name, + version_string, revision_register & 0xF, ioaddr, dev->irq, + memory, dev->dma); + /* + . Print the Ethernet address + */ + printk("ADDR: "); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i] ); + printk("%2.2x \n", dev->dev_addr[5] ); + + + /* Initialize the private structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + } + /* set the private data to zero by default */ + memset(dev->priv, 0, sizeof(struct smc_local)); + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + /* Grab the IRQ */ + retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); + if (retval) { + printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); + kfree(dev->priv); + dev->priv = NULL; + goto err_out; + } + + dev->open = smc_open; + dev->stop = smc_close; + dev->hard_start_xmit = smc_wait_to_send_packet; + dev->get_stats = smc_query_statistics; + dev->watchdog_timeo = HZ/20; +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &smc_set_multicast_list; +#endif + + /* at this point I'll assume that the chip is an SMC9xxx. + It might be prudent to check a listing of MAC addresses + against the hardware address, or do some other tests. */ + return 0; + +err_out: + release_region(ioaddr, SMC_IO_EXTENT); + return retval; +} + +#if SMC_DEBUG > 2 +static void print_packet( byte * buf, int length ) +{ +#if 1 + int i; + int remainder; + int lines; + + printk("Packet of length %d \n", length ); + +#if SMC_DEBUG > 3 + lines = length / 16; + remainder = length % 16; + + for ( i = 0; i < lines ; i ++ ) { + int cur; + + for ( cur = 0; cur < 8; cur ++ ) { + byte a, b; + + a = *(buf ++ ); + b = *(buf ++ ); + printk("%02x%02x ", a, b ); + } + printk("\n"); + } + for ( i = 0; i < remainder/2 ; i++ ) { + byte a, b; + + a = *(buf ++ ); + b = *(buf ++ ); + printk("%02x%02x ", a, b ); + } + printk("\n"); +#endif +#endif +} +#endif + + +/* + * Open and Initialize the board + * + * Set up everything, reset the card, etc .. + * + */ +static int smc_open(struct net_device *dev) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + int ioaddr = dev->base_addr; + int i; /* used to set hw ethernet address */ + + PRINTK2("%s:smc_open\n", dev->name); + + /* clear out all the junk that was put here before... */ + memset(dev->priv, 0, sizeof(struct smc_local)); + + // Setup the default Register Modes + lp->tcr_cur_mode = TCR_DEFAULT; + lp->rcr_cur_mode = RCR_DEFAULT; + lp->rpc_cur_mode = RPC_DEFAULT; + + // Set default parameters (files) + lp->ctl_swfdup = 0; + lp->ctl_ephloop = 0; + lp->ctl_miiop = 0; + lp->ctl_autoneg = 1; + lp->ctl_rfduplx = 1; + lp->ctl_rspeed = 100; + lp->ctl_afduplx = 1; + lp->ctl_aspeed = 100; + lp->ctl_lnkfail = 1; + lp->ctl_forcol = 0; + lp->ctl_filtcar = 0; + + /* reset the hardware */ + + smc_reset( dev ); + smc_enable( dev ); + + /* Configure the PHY */ + smc_phy_configure(dev); + + /* + According to Becker, I have to set the hardware address + at this point, because the (l)user can set it with an + ioctl. Easily done... + */ + SMC_SELECT_BANK( 1 ); + for ( i = 0; i < 6; i ++ ) + SMC_outb( dev->dev_addr[i], ADDR0_REG + i ); + +#ifdef CONFIG_SYSCTL + smc_sysctl_register(dev); +#endif /* CONFIG_SYSCTL */ + + netif_start_queue(dev); + return 0; +} + +/*-------------------------------------------------------------------- + . + . This is the main routine of the driver, to handle the device when + . it needs some attention. + . + . So: + . first, save state of the chipset + . branch off into routines to handle each case, and acknowledge + . each to the interrupt register + . and finally restore state. + . + ---------------------------------------------------------------------*/ +static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + + byte status; + word card_stats; + byte mask; + int timeout; + /* state registers */ + word saved_bank; + word saved_pointer; + + + + PRINTK3("%s: SMC interrupt started \n", dev->name); + + if (dev == NULL) { + printk(KERN_WARNING "%s: irq %d for unknown device.\n", + dev->name, irq); + return; + } + + saved_bank = SMC_inw( BANK_SELECT ); + + SMC_SELECT_BANK(2); + saved_pointer = SMC_inw( PTR_REG ); + + /* read the interrupt status register */ + mask = SMC_inb( IM_REG ); + + /* disable all interrupts */ + SMC_outb( 0, IM_REG ); + + + /* set a timeout value, so I don't stay here forever */ + timeout = 4; + + PRINTK2(KERN_WARNING "%s: MASK IS %x \n", dev->name, mask); + do { + /* read the status flag, and mask it */ + status = SMC_inb( INT_REG ) & mask; + if (!status ) + break; + + PRINTK3(KERN_WARNING "%s: Handling interrupt status %x \n", + dev->name, status); + + if (status & IM_RCV_INT) { + /* Got a packet(s). */ + PRINTK2(KERN_WARNING + "%s: Receive Interrupt\n", dev->name); + smc_rcv(dev); + } else if (status & IM_TX_INT ) { + PRINTK2(KERN_WARNING "%s: TX ERROR handled\n", + dev->name); + smc_tx(dev); + // Acknowledge the interrupt + SMC_outb(IM_TX_INT, INT_REG ); + } else if (status & IM_TX_EMPTY_INT ) { + /* update stats */ + SMC_SELECT_BANK( 0 ); + card_stats = SMC_inw( COUNTER_REG ); + /* single collisions */ + lp->stats.collisions += card_stats & 0xF; + card_stats >>= 4; + /* multiple collisions */ + lp->stats.collisions += card_stats & 0xF; + + /* these are for when linux supports these statistics */ +#if 0 + card_stats >>= 4; + /* deferred */ + card_stats >>= 4; + /* excess deferred */ +#endif + SMC_SELECT_BANK( 2 ); + PRINTK2(KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n", + dev->name); + // Acknowledge the interrupt + SMC_outb( IM_TX_EMPTY_INT, INT_REG ); + mask &= ~IM_TX_EMPTY_INT; + lp->stats.tx_packets += lp->packets_waiting; + lp->packets_waiting = 0; + + } else if (status & IM_ALLOC_INT ) { + PRINTK2(KERN_DEBUG "%s: Allocation interrupt \n", dev->name); + /* clear this interrupt so it doesn't happen again */ + mask &= ~IM_ALLOC_INT; + + smc_hardware_send_packet( dev ); + + /* enable xmit interrupts based on this */ + mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); + + /* and let the card send more packets to me */ + netif_wake_queue(dev); + + PRINTK2("%s: Handoff done successfully.\n", dev->name); + } else if (status & IM_RX_OVRN_INT ) { + lp->stats.rx_errors++; + lp->stats.rx_fifo_errors++; + // Acknowledge the interrupt + SMC_outb( IM_RX_OVRN_INT, INT_REG ); + } else if (status & IM_EPH_INT ) { + PRINTK("%s: UNSUPPORTED: EPH INTERRUPT \n", + dev->name); + } else if (status & IM_MDINT ) { + smc_phy_interrupt(dev); + // Acknowledge the interrupt + SMC_outb(IM_MDINT, INT_REG ); + } else if (status & IM_ERCV_INT ) { + PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", + dev->name); + // Acknowledge the interrupt + SMC_outb( IM_ERCV_INT, INT_REG ); + } + } while ( timeout -- ); + + + /* restore register states */ + + SMC_SELECT_BANK( 2 ); + + SMC_outb( mask, IM_REG ); + + PRINTK3( KERN_WARNING "%s: MASK is now %x \n", dev->name, mask); + SMC_outw( saved_pointer, PTR_REG ); + + SMC_SELECT_BANK( saved_bank ); + + PRINTK3("%s: Interrupt done\n", dev->name); + return; +} + +/*------------------------------------------------------------- + . + . smc_rcv - receive a packet from the card + . + . There is ( at least ) a packet waiting to be read from + . chip-memory. + . + . o Read the status + . o If an error, record it + . o otherwise, read in the packet + -------------------------------------------------------------- +*/ +static void smc_rcv(struct net_device *dev) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + int ioaddr = dev->base_addr; + int packet_number; + word status; + word packet_length; + + PRINTK3("%s:smc_rcv\n", dev->name); + + /* assume bank 2 */ + + packet_number = SMC_inw( RXFIFO_REG ); + + if ( packet_number & RXFIFO_REMPTY ) { + + /* we got called , but nothing was on the FIFO */ + PRINTK("%s: WARNING: smc_rcv with nothing on FIFO. \n", + dev->name); + /* don't need to restore anything */ + return; + } + + /* start reading from the start of the packet */ + SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG ); + + /* First two words are status and packet_length */ + status = SMC_inw( DATA_REG ); + packet_length = SMC_inw( DATA_REG ); + + packet_length &= 0x07ff; /* mask off top bits */ + + PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ); + + if ( !(status & RS_ERRORS ) ){ + /* do stuff to make a new packet */ + struct sk_buff * skb; + byte * data; + + /* set multicast stats */ + if ( status & RS_MULTICAST ) + lp->stats.multicast++; + + // Allocate enough memory for entire receive frame, to be safe + skb = dev_alloc_skb( packet_length ); + + /* Adjust for having already read the first two words */ + packet_length -= 4; + + if ( skb == NULL ) { + printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", + dev->name); + lp->stats.rx_dropped++; + } + + /* + ! This should work without alignment, but it could be + ! in the worse case + */ + /* TODO: Should I use 32bit alignment here ? */ + skb_reserve( skb, 2 ); /* 16 bit alignment */ + + skb->dev = dev; + + // set odd length for bug in LAN91C111, + // which never sets RS_ODDFRAME + data = skb_put( skb, packet_length + 1 ); + +#ifdef USE_32_BIT + PRINTK3(" Reading %d dwords (and %d bytes) \n", + packet_length >> 2, packet_length & 3 ); + /* QUESTION: Like in the TX routine, do I want + to send the DWORDs or the bytes first, or some + mixture. A mixture might improve already slow PIO + performance */ + insl(ioaddr + DATA_REG , data, packet_length >> 2 ); + /* read the left over bytes */ + insb( ioaddr + DATA_REG, data + (packet_length & 0xFFFFFC), + packet_length & 0x3 ); +#else + PRINTK3(" Reading %d words and %d byte(s) \n", + (packet_length >> 1 ), packet_length & 1 ); + SMC_insw(DATA_REG , data, packet_length >> 1); + +#endif // USE_32_BIT + +#if SMC_DEBUG > 2 + printk("Receiving Packet\n"); + print_packet( data, packet_length ); +#endif + + skb->protocol = eth_type_trans(skb, dev ); + netif_rx(skb); + lp->stats.rx_packets++; + } else { + /* error ... */ + lp->stats.rx_errors++; + + if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; + if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) + lp->stats.rx_length_errors++; + if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; + } + + while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) + udelay(1); // Wait until not busy + + /* error or good, tell the card to get rid of this packet */ + SMC_outw( MC_RELEASE, MMU_CMD_REG ); + + + return; +} + + +/************************************************************************* + . smc_tx + . + . Purpose: Handle a transmit error message. This will only be called + . when an error, because of the AUTO_RELEASE mode. + . + . Algorithm: + . Save pointer and packet no + . Get the packet no from the top of the queue + . check if it's valid ( if not, is this an error??? ) + . read the status word + . record the error + . ( resend? Not really, since we don't want old packets around ) + . Restore saved values + ************************************************************************/ +static void smc_tx( struct net_device * dev ) +{ + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + byte saved_packet; + byte packet_no; + word tx_status; + + + PRINTK3("%s:smc_tx\n", dev->name); + + /* assume bank 2 */ + + saved_packet = SMC_inb( PN_REG ); + packet_no = SMC_inw( RXFIFO_REG ); + packet_no &= 0x7F; + + /* If the TX FIFO is empty then nothing to do */ + if ( packet_no & TXFIFO_TEMPTY ) + return; + + /* select this as the packet to read from */ + SMC_outb( packet_no, PN_REG ); + + /* read the first word (status word) from this packet */ + SMC_outw( PTR_AUTOINC | PTR_READ, PTR_REG ); + + tx_status = SMC_inw( DATA_REG ); + PRINTK3("%s: TX DONE STATUS: %4x \n", dev->name, tx_status); + + lp->stats.tx_errors++; + if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; + if ( tx_status & TS_LATCOL ) { + printk(KERN_DEBUG + "%s: Late collision occurred on last xmit.\n", + dev->name); + lp->stats.tx_window_errors++; + lp->ctl_forcol = 0; // Reset forced collsion + } +#if 0 + if ( tx_status & TS_16COL ) { ... } +#endif + + if ( tx_status & TS_SUCCESS ) { + printk("%s: Successful packet caused interrupt \n", dev->name); + } + /* re-enable transmit */ + SMC_SELECT_BANK( 0 ); + SMC_outw( SMC_inw( TCR_REG ) | TCR_ENABLE, TCR_REG ); + + /* kill the packet */ + SMC_SELECT_BANK( 2 ); + SMC_outw( MC_FREEPKT, MMU_CMD_REG ); + + /* one less packet waiting for me */ + lp->packets_waiting--; + + /* Don't change Packet Number Reg until busy bit is cleared */ + /* Per LAN91C111 Spec, Page 50 */ + while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ); + + SMC_outb( saved_packet, PN_REG ); + return; +} + + +/*---------------------------------------------------- + . smc_close + . + . this makes the board clean up everything that it can + . and not talk to the outside world. Caused by + . an 'ifconfig ethX down' + . + -----------------------------------------------------*/ +static int smc_close(struct net_device *dev) +{ + PRINTK2("%s:smc_close\n", dev->name); + + netif_stop_queue(dev); + +#ifdef CONFIG_SYSCTL + smc_sysctl_unregister(dev); +#endif /* CONFIG_SYSCTL */ + + /* clear everything */ + smc_shutdown( dev->base_addr ); + + return 0; +} + +/*------------------------------------------------------------ + . Get the current statistics. + . This may be called with the card open or closed. + .-------------------------------------------------------------*/ +static struct net_device_stats* smc_query_statistics(struct net_device *dev) { + struct smc_local *lp = (struct smc_local *)dev->priv; + + PRINTK2("%s:smc_query_statistics\n", dev->name); + + return &lp->stats; +} + +/*----------------------------------------------------------- + . smc_set_multicast_list + . + . This routine will, depending on the values passed to it, + . either make it accept multicast packets, go into + . promiscuous mode ( for TCPDUMP and cousins ) or accept + . a select set of multicast packets +*/ +static void smc_set_multicast_list(struct net_device *dev) +{ + unsigned long ioaddr = dev->base_addr; + + PRINTK2("%s:smc_set_multicast_list\n", dev->name); + + SMC_SELECT_BANK(0); + if ( dev->flags & IFF_PROMISC ) + { + PRINTK2("%s:smc_set_multicast_list:RCR_PRMS\n", dev->name); + SMC_outw( SMC_inw( RCR_REG ) | RCR_PRMS, RCR_REG ); + } + +/* BUG? I never disable promiscuous mode if multicasting was turned on. + Now, I turn off promiscuous mode, but I don't do anything to multicasting + when promiscuous mode is turned on. +*/ + + /* Here, I am setting this to accept all multicast packets. + I don't need to zero the multicast table, because the flag is + checked before the table is + */ + else if (dev->flags & IFF_ALLMULTI) + { + SMC_outw( SMC_inw(RCR_REG ) | RCR_ALMUL, RCR_REG ); + PRINTK2("%s:smc_set_multicast_list:RCR_ALMUL\n", dev->name); + } + + /* We just get all multicast packets even if we only want them + . from one source. This will be changed at some future + . point. */ + else if (dev->mc_count ) { + /* support hardware multicasting */ + + /* be sure I get rid of flags I might have set */ + SMC_outw( SMC_inw( RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL), RCR_REG ); + /* NOTE: this has to set the bank, so make sure it is the + last thing called. The bank is set to zero at the top */ + smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); + } else { + PRINTK2("%s:smc_set_multicast_list:~(RCR_PRMS|RCR_ALMUL)\n", + dev->name); + SMC_outw( SMC_inw( RCR_REG ) & ~(RCR_PRMS | RCR_ALMUL), RCR_REG ); + + /* + since I'm disabling all multicast entirely, I need to + clear the multicast list + */ + SMC_SELECT_BANK( 3 ); + SMC_outw( 0, MCAST_REG1 ); + SMC_outw( 0, MCAST_REG2 ); + SMC_outw( 0, MCAST_REG3 ); + SMC_outw( 0, MCAST_REG4 ); + } +} + +#ifdef MODULE + +static struct net_device devSMC91111; +static int io; +static int irq; +static int ifport; + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(ifport, "i"); + +/*------------------------------------------------------------ + . Module initialization function + .-------------------------------------------------------------*/ +int init_module(void) +{ + int result; + + PRINTK2(CARDNAME ":init_module\n"); + + if (io == 0) + printk(KERN_WARNING + CARDNAME": You shouldn't use auto-probing with insmod!\n" ); + + /* copy the parameters from insmod into the device structure */ + devSMC91111.base_addr = io; + devSMC91111.irq = irq; + devSMC91111.if_port = ifport; + devSMC91111.init = smc_init; + if ((result = register_netdev(&devSMC91111)) != 0) + return result; + + return 0; +} + +/*------------------------------------------------------------ + . Cleanup when module is removed with rmmod + .-------------------------------------------------------------*/ +void cleanup_module(void) +{ + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + unregister_netdev(&devSMC91111); + + free_irq(devSMC91111.irq, &devSMC91111); + release_region(devSMC91111.base_addr, SMC_IO_EXTENT); + + if (devSMC91111.priv) + kfree(devSMC91111.priv); +} + +#endif /* MODULE */ + + +#ifdef CONFIG_SYSCTL + + +/*------------------------------------------------------------ + . Modify a bit in the LAN91C111 register set + .-------------------------------------------------------------*/ +static word smc_modify_regbit(int bank, int ioaddr, int reg, + unsigned int bit, int val) +{ + word regval; + + SMC_SELECT_BANK( bank ); + + regval = SMC_inw( reg ); + if (val) + regval |= bit; + else + regval &= ~bit; + + SMC_outw( regval, 0 ); + return(regval); +} + + +/*------------------------------------------------------------ + . Retrieve a bit in the LAN91C111 register set + .-------------------------------------------------------------*/ +static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit) +{ + SMC_SELECT_BANK( bank ); + if ( SMC_inw( reg ) & bit) + return(1); + else + return(0); +} + + +/*------------------------------------------------------------ + . Modify a LAN91C111 register (word access only) + .-------------------------------------------------------------*/ +static void smc_modify_reg(int bank, int ioaddr, int reg, word val) +{ + SMC_SELECT_BANK( bank ); + SMC_outw( val, reg ); +} + + +/*------------------------------------------------------------ + . Retrieve a LAN91C111 register (word access only) + .-------------------------------------------------------------*/ +static int smc_get_reg(int bank, int ioaddr, int reg) +{ + SMC_SELECT_BANK( bank ); + return(SMC_inw( reg )); +} + + +static const char smc_info_string[] = +"\n" +"info Provides this information blurb\n" +"swver Prints the software version information of this driver\n" +"autoneg Auto-negotiate Mode = 1\n" +"rspeed Requested Speed, 100=100Mbps, 10=10Mpbs\n" +"rfduplx Requested Full Duplex Operation\n" +"aspeed Actual Speed, 100=100Mbps, 10=10Mpbs\n" +"afduplx Actual Full Duplex Operation\n" +"lnkfail PHY Link Failure when 1\n" +"miiop External MII when 1, Internal PHY when 0\n" +"swfdup Switched Full Duplex Mode (allowed only in MII operation)\n" +"ephloop EPH Block Loopback\n" +"forcol Force a collision\n" +"filtcar Filter leading edge of carrier sense for 12 bit times\n" +"freemem Free buffer memory in bytes\n" +"totmem Total buffer memory in bytes\n" +"leda Output of LED-A (green)\n" +"ledb Output of LED-B (yellow)\n" +"chiprev Revision ID of the LAN91C111 chip\n" +""; + +/*------------------------------------------------------------ + . Sysctl handler for all integer parameters + .-------------------------------------------------------------*/ +static int smc_sysctl_handler(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + struct net_device *dev = (struct net_device*)ctl->extra1; + struct smc_local *lp = (struct smc_local *)ctl->extra2; + int ioaddr = dev->base_addr; + int *valp = ctl->data; + int val; + int ret; + + // Update parameters from the real registers + switch (ctl->ctl_name) + { + case CTL_SMC_FORCOL: + *valp = smc_get_regbit(0, ioaddr, TCR_REG, TCR_FORCOL); + break; + + case CTL_SMC_FREEMEM: + *valp = ( (word)smc_get_reg(0, ioaddr, MIR_REG) >> 8 ) + * LAN91C111_MEMORY_MULTIPLIER; + break; + + + case CTL_SMC_TOTMEM: + *valp = ( smc_get_reg(0, ioaddr, MIR_REG) & (word)0x00ff ) + * LAN91C111_MEMORY_MULTIPLIER; + break; + + case CTL_SMC_CHIPREV: + *valp = smc_get_reg(3, ioaddr, REV_REG); + break; + + case CTL_SMC_AFDUPLX: + *valp = (lp->lastPhy18 & PHY_INT_DPLXDET) ? 1 : 0; + break; + + case CTL_SMC_ASPEED: + *valp = (lp->lastPhy18 & PHY_INT_SPDDET) ? 100 : 10; + break; + + case CTL_SMC_LNKFAIL: + *valp = (lp->lastPhy18 & PHY_INT_LNKFAIL) ? 1 : 0; + break; + + case CTL_SMC_LEDA: + *valp = (lp->rpc_cur_mode >> RPC_LSXA_SHFT) & (word)0x0007; + break; + + case CTL_SMC_LEDB: + *valp = (lp->rpc_cur_mode >> RPC_LSXB_SHFT) & (word)0x0007; + break; + + case CTL_SMC_MIIOP: + *valp = smc_get_regbit(1, ioaddr, CONFIG_REG, CONFIG_EXT_PHY); + break; + +#ifdef SMC_DEBUG + case CTL_SMC_REG_BSR: // Bank Select + *valp = smc_get_reg(0, ioaddr, BSR_REG); + break; + + case CTL_SMC_REG_TCR: // Transmit Control + *valp = smc_get_reg(0, ioaddr, TCR_REG); + break; + + case CTL_SMC_REG_ESR: // EPH Status + *valp = smc_get_reg(0, ioaddr, EPH_STATUS_REG); + break; + + case CTL_SMC_REG_RCR: // Receive Control + *valp = smc_get_reg(0, ioaddr, RCR_REG); + break; + + case CTL_SMC_REG_CTRR: // Counter + *valp = smc_get_reg(0, ioaddr, COUNTER_REG); + break; + + case CTL_SMC_REG_MIR: // Memory Information + *valp = smc_get_reg(0, ioaddr, MIR_REG); + break; + + case CTL_SMC_REG_RPCR: // Receive/Phy Control + *valp = smc_get_reg(0, ioaddr, RPC_REG); + break; + + case CTL_SMC_REG_CFGR: // Configuration + *valp = smc_get_reg(1, ioaddr, CONFIG_REG); + break; + + case CTL_SMC_REG_BAR: // Base Address + *valp = smc_get_reg(1, ioaddr, BASE_REG); + break; + + case CTL_SMC_REG_IAR0: // Individual Address + *valp = smc_get_reg(1, ioaddr, ADDR0_REG); + break; + + case CTL_SMC_REG_IAR1: // Individual Address + *valp = smc_get_reg(1, ioaddr, ADDR1_REG); + break; + + case CTL_SMC_REG_IAR2: // Individual Address + *valp = smc_get_reg(1, ioaddr, ADDR2_REG); + break; + + case CTL_SMC_REG_GPR: // General Purpose + *valp = smc_get_reg(1, ioaddr, GP_REG); + break; + + case CTL_SMC_REG_CTLR: // Control + *valp = smc_get_reg(1, ioaddr, CTL_REG); + break; + + case CTL_SMC_REG_MCR: // MMU Command + *valp = smc_get_reg(2, ioaddr, MMU_CMD_REG); + break; + + case CTL_SMC_REG_PNR: // Packet Number + *valp = smc_get_reg(2, ioaddr, PN_REG); + break; + + case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports + *valp = smc_get_reg(2, ioaddr, RXFIFO_REG); + break; + + case CTL_SMC_REG_PTR: // Pointer + *valp = smc_get_reg(2, ioaddr, PTR_REG); + break; + + case CTL_SMC_REG_DR: // Data + *valp = smc_get_reg(2, ioaddr, DATA_REG); + break; + + case CTL_SMC_REG_ISR: // Interrupt Status/Mask + *valp = smc_get_reg(2, ioaddr, INT_REG); + break; + + case CTL_SMC_REG_MTR1: // Multicast Table Entry 1 + *valp = smc_get_reg(3, ioaddr, MCAST_REG1); + break; + + case CTL_SMC_REG_MTR2: // Multicast Table Entry 2 + *valp = smc_get_reg(3, ioaddr, MCAST_REG2); + break; + + case CTL_SMC_REG_MTR3: // Multicast Table Entry 3 + *valp = smc_get_reg(3, ioaddr, MCAST_REG3); + break; + + case CTL_SMC_REG_MTR4: // Multicast Table Entry 4 + *valp = smc_get_reg(3, ioaddr, MCAST_REG4); + break; + + case CTL_SMC_REG_MIIR: // Management Interface + *valp = smc_get_reg(3, ioaddr, MII_REG); + break; + + case CTL_SMC_REG_REVR: // Revision + *valp = smc_get_reg(3, ioaddr, REV_REG); + break; + + case CTL_SMC_REG_ERCVR: // Early RCV + *valp = smc_get_reg(3, ioaddr, ERCV_REG); + break; + + case CTL_SMC_REG_EXTR: // External + *valp = smc_get_reg(7, ioaddr, EXT_REG); + break; + + case CTL_SMC_PHY_CTRL: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_CNTL_REG); + break; + + case CTL_SMC_PHY_STAT: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_STAT_REG); + break; + + case CTL_SMC_PHY_ID1: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_ID1_REG); + break; + + case CTL_SMC_PHY_ID2: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_ID2_REG); + break; + + case CTL_SMC_PHY_ADC: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_AD_REG); + break; + + case CTL_SMC_PHY_REMC: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_RMT_REG); + break; + + case CTL_SMC_PHY_CFG1: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_CFG1_REG); + break; + + case CTL_SMC_PHY_CFG2: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_CFG2_REG); + break; + + case CTL_SMC_PHY_INT: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_INT_REG); + break; + + case CTL_SMC_PHY_MASK: + *valp = smc_read_phy_register(ioaddr, lp->phyaddr, + PHY_MASK_REG); + break; + +#endif // SMC_DEBUG + + default: + // Just ignore unsupported parameters + break; + } + + // Save old state + val = *valp; + + // Perform the generic integer operation + if ((ret = proc_dointvec(ctl, write, filp, buffer, lenp)) != 0) + return(ret); + + // Write changes out to the registers + if (write && *valp != val) { + + val = *valp; + switch (ctl->ctl_name) { + + case CTL_SMC_SWFDUP: + if (val) + lp->tcr_cur_mode |= TCR_SWFDUP; + else + lp->tcr_cur_mode &= ~TCR_SWFDUP; + + smc_modify_regbit(0, ioaddr, TCR_REG, TCR_SWFDUP, val); + break; + + case CTL_SMC_EPHLOOP: + if (val) + lp->tcr_cur_mode |= TCR_EPH_LOOP; + else + lp->tcr_cur_mode &= ~TCR_EPH_LOOP; + + smc_modify_regbit(0, ioaddr, TCR_REG, TCR_EPH_LOOP, val); + break; + + case CTL_SMC_FORCOL: + if (val) + lp->tcr_cur_mode |= TCR_FORCOL; + else + lp->tcr_cur_mode &= ~TCR_FORCOL; + + // Update the EPH block + smc_modify_regbit(0, ioaddr, TCR_REG, TCR_FORCOL, val); + break; + + case CTL_SMC_FILTCAR: + if (val) + lp->rcr_cur_mode |= RCR_FILT_CAR; + else + lp->rcr_cur_mode &= ~RCR_FILT_CAR; + + // Update the EPH block + smc_modify_regbit(0, ioaddr, RCR_REG, RCR_FILT_CAR, val); + break; + + case CTL_SMC_RFDUPLX: + // Disallow changes if in auto-negotiation mode + if (lp->ctl_autoneg) + break; + + if (val) + { + lp->rpc_cur_mode |= RPC_DPLX; + } + else + { + lp->rpc_cur_mode &= ~RPC_DPLX; + } + + // Reconfigure the PHY + smc_phy_configure(dev); + + break; + + case CTL_SMC_RSPEED: + // Disallow changes if in auto-negotiation mode + if (lp->ctl_autoneg) + break; + + if (val > 10) + lp->rpc_cur_mode |= RPC_SPEED; + else + lp->rpc_cur_mode &= ~RPC_SPEED; + + // Reconfigure the PHY + smc_phy_configure(dev); + + break; + + case CTL_SMC_AUTONEG: + if (val) + lp->rpc_cur_mode |= RPC_ANEG; + else + lp->rpc_cur_mode &= ~RPC_ANEG; + + // Reconfigure the PHY + smc_phy_configure(dev); + + break; + + case CTL_SMC_LEDA: + val &= 0x07; // Restrict to 3 ls bits + lp->rpc_cur_mode &= ~(word)(0x07<rpc_cur_mode |= (word)(val<rpc_cur_mode); + break; + + case CTL_SMC_LEDB: + val &= 0x07; // Restrict to 3 ls bits + lp->rpc_cur_mode &= ~(word)(0x07<rpc_cur_mode |= (word)(val<rpc_cur_mode); + break; + + case CTL_SMC_MIIOP: + // Update the Internal PHY block + smc_modify_regbit(1, ioaddr, CONFIG_REG, + CONFIG_EXT_PHY, val); + break; + +#ifdef SMC_DEBUG + case CTL_SMC_REG_BSR: // Bank Select + smc_modify_reg(0, ioaddr, BSR_REG, val); + break; + + case CTL_SMC_REG_TCR: // Transmit Control + smc_modify_reg(0, ioaddr, TCR_REG, val); + break; + + case CTL_SMC_REG_ESR: // EPH Status + smc_modify_reg(0, ioaddr, EPH_STATUS_REG, val); + break; + + case CTL_SMC_REG_RCR: // Receive Control + smc_modify_reg(0, ioaddr, RCR_REG, val); + break; + + case CTL_SMC_REG_CTRR: // Counter + smc_modify_reg(0, ioaddr, COUNTER_REG, val); + break; + + case CTL_SMC_REG_MIR: // Memory Information + smc_modify_reg(0, ioaddr, MIR_REG, val); + break; + + case CTL_SMC_REG_RPCR: // Receive/Phy Control + smc_modify_reg(0, ioaddr, RPC_REG, val); + break; + + case CTL_SMC_REG_CFGR: // Configuration + smc_modify_reg(1, ioaddr, CONFIG_REG, val); + break; + + case CTL_SMC_REG_BAR: // Base Address + smc_modify_reg(1, ioaddr, BASE_REG, val); + break; + + case CTL_SMC_REG_IAR0: // Individual Address + smc_modify_reg(1, ioaddr, ADDR0_REG, val); + break; + + case CTL_SMC_REG_IAR1: // Individual Address + smc_modify_reg(1, ioaddr, ADDR1_REG, val); + break; + + case CTL_SMC_REG_IAR2: // Individual Address + smc_modify_reg(1, ioaddr, ADDR2_REG, val); + break; + + case CTL_SMC_REG_GPR: // General Purpose + smc_modify_reg(1, ioaddr, GP_REG, val); + break; + + case CTL_SMC_REG_CTLR: // Control + smc_modify_reg(1, ioaddr, CTL_REG, val); + break; + + case CTL_SMC_REG_MCR: // MMU Command + smc_modify_reg(2, ioaddr, MMU_CMD_REG, val); + break; + + case CTL_SMC_REG_PNR: // Packet Number + smc_modify_reg(2, ioaddr, PN_REG, val); + break; + + case CTL_SMC_REG_FPR: // Allocation Result/FIFO Ports + smc_modify_reg(2, ioaddr, RXFIFO_REG, val); + break; + + case CTL_SMC_REG_PTR: // Pointer + smc_modify_reg(2, ioaddr, PTR_REG, val); + break; + + case CTL_SMC_REG_DR: // Data + smc_modify_reg(2, ioaddr, DATA_REG, val); + break; + + case CTL_SMC_REG_ISR: // Interrupt Status/Mask + smc_modify_reg(2, ioaddr, INT_REG, val); + break; + + case CTL_SMC_REG_MTR1: // Multicast Table Entry 1 + smc_modify_reg(3, ioaddr, MCAST_REG1, val); + break; + + case CTL_SMC_REG_MTR2: // Multicast Table Entry 2 + smc_modify_reg(3, ioaddr, MCAST_REG2, val); + break; + + case CTL_SMC_REG_MTR3: // Multicast Table Entry 3 + smc_modify_reg(3, ioaddr, MCAST_REG3, val); + break; + + case CTL_SMC_REG_MTR4: // Multicast Table Entry 4 + smc_modify_reg(3, ioaddr, MCAST_REG4, val); + break; + + case CTL_SMC_REG_MIIR: // Management Interface + smc_modify_reg(3, ioaddr, MII_REG, val); + break; + + case CTL_SMC_REG_REVR: // Revision + smc_modify_reg(3, ioaddr, REV_REG, val); + break; + + case CTL_SMC_REG_ERCVR: // Early RCV + smc_modify_reg(3, ioaddr, ERCV_REG, val); + break; + + case CTL_SMC_REG_EXTR: // External + smc_modify_reg(7, ioaddr, EXT_REG, val); + break; + + case CTL_SMC_PHY_CTRL: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_CNTL_REG, val); + break; + + case CTL_SMC_PHY_STAT: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_STAT_REG, val); + break; + + case CTL_SMC_PHY_ID1: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_ID1_REG, val); + break; + + case CTL_SMC_PHY_ID2: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_ID2_REG, val); + break; + + case CTL_SMC_PHY_ADC: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_AD_REG, val); + break; + + case CTL_SMC_PHY_REMC: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_RMT_REG, val); + break; + + case CTL_SMC_PHY_CFG1: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_CFG1_REG, val); + break; + + case CTL_SMC_PHY_CFG2: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_CFG2_REG, val); + break; + + case CTL_SMC_PHY_INT: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_INT_REG, val); + break; + + case CTL_SMC_PHY_MASK: + smc_write_phy_register(ioaddr, lp->phyaddr, + PHY_MASK_REG, val); + break; + +#endif // SMC_DEBUG + + default: + // Just ignore unsupported parameters + break; + } // end switch + + } // end if + + return ret; +} + +#if 0 //;my +#ifdef MODULE +/* + * This is called as the fill_inode function when an inode + * is going into (fill = 1) or out of service (fill = 0). + * We use it here to manage the module use counts. + * + * Note: only the top-level directory needs to do this; if + * a lower level is referenced, the parent will be as well. + */ +static void smc_procfs_modcount(struct inode *inode, int fill) +{ + if (fill) { + MOD_INC_USE_COUNT; + } else { + MOD_DEC_USE_COUNT; + } +} +#endif // MODULE +#endif //;my + +/*------------------------------------------------------------ + . Sysctl registration function for all parameters (files) + .-------------------------------------------------------------*/ +static void smc_sysctl_register(struct net_device *dev) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + static int ctl_name = CTL_SMC; + ctl_table* ct; + int i; + + // Make sure the ctl_tables start out as all zeros + memset(lp->root_table, 0, sizeof lp->root_table); + memset(lp->eth_table, 0, sizeof lp->eth_table); + memset(lp->param_table, 0, sizeof lp->param_table); + + // Initialize the root table + ct = lp->root_table; + ct->ctl_name = CTL_DEV; + ct->procname = "dev"; + ct->maxlen = 0; + ct->mode = 0555; + ct->child = lp->eth_table; + // remaining fields are zero + + // Initialize the ethX table (this device's table) + ct = lp->eth_table; + ct->ctl_name = ctl_name++; // Must be unique + ct->procname = dev->name; + ct->maxlen = 0; + ct->mode = 0555; + ct->child = lp->param_table; + // remaining fields are zero + + // Initialize the parameter (files) table + // Make sure the last entry remains null + ct = lp->param_table; + for (i = 0; i < (CTL_SMC_LAST_ENTRY-1); ++i) + { + // Initialize fields common to all table entries + ct[i].proc_handler = smc_sysctl_handler; + ct[i].extra1 = (void*)dev; // Save our device pointer + ct[i].extra2 = (void*)lp; // Save our smc_local data pointer + } + + // INFO - this is our only string parameter + i = 0; + ct[i].proc_handler = proc_dostring; // use default handler + ct[i].ctl_name = CTL_SMC_INFO; + ct[i].procname = "info"; + ct[i].data = (void*)smc_info_string; + ct[i].maxlen = sizeof smc_info_string; + ct[i].mode = 0444; // Read only + + // SWVER + ++i; + ct[i].proc_handler = proc_dostring; // use default handler + ct[i].ctl_name = CTL_SMC_SWVER; + ct[i].procname = "swver"; + ct[i].data = (void*)version; + ct[i].maxlen = sizeof version; + ct[i].mode = 0444; // Read only + + // SWFDUP + ++i; + ct[i].ctl_name = CTL_SMC_SWFDUP; + ct[i].procname = "swfdup"; + ct[i].data = (void*)&(lp->ctl_swfdup); + ct[i].maxlen = sizeof lp->ctl_swfdup; + ct[i].mode = 0644; // Read by all, write by root + + // EPHLOOP + ++i; + ct[i].ctl_name = CTL_SMC_EPHLOOP; + ct[i].procname = "ephloop"; + ct[i].data = (void*)&(lp->ctl_ephloop); + ct[i].maxlen = sizeof lp->ctl_ephloop; + ct[i].mode = 0644; // Read by all, write by root + + // MIIOP + ++i; + ct[i].ctl_name = CTL_SMC_MIIOP; + ct[i].procname = "miiop"; + ct[i].data = (void*)&(lp->ctl_miiop); + ct[i].maxlen = sizeof lp->ctl_miiop; + ct[i].mode = 0644; // Read by all, write by root + + // AUTONEG + ++i; + ct[i].ctl_name = CTL_SMC_AUTONEG; + ct[i].procname = "autoneg"; + ct[i].data = (void*)&(lp->ctl_autoneg); + ct[i].maxlen = sizeof lp->ctl_autoneg; + ct[i].mode = 0644; // Read by all, write by root + + // RFDUPLX + ++i; + ct[i].ctl_name = CTL_SMC_RFDUPLX; + ct[i].procname = "rfduplx"; + ct[i].data = (void*)&(lp->ctl_rfduplx); + ct[i].maxlen = sizeof lp->ctl_rfduplx; + ct[i].mode = 0644; // Read by all, write by root + + // RSPEED + ++i; + ct[i].ctl_name = CTL_SMC_RSPEED; + ct[i].procname = "rspeed"; + ct[i].data = (void*)&(lp->ctl_rspeed); + ct[i].maxlen = sizeof lp->ctl_rspeed; + ct[i].mode = 0644; // Read by all, write by root + + // AFDUPLX + ++i; + ct[i].ctl_name = CTL_SMC_AFDUPLX; + ct[i].procname = "afduplx"; + ct[i].data = (void*)&(lp->ctl_afduplx); + ct[i].maxlen = sizeof lp->ctl_afduplx; + ct[i].mode = 0444; // Read only + + // ASPEED + ++i; + ct[i].ctl_name = CTL_SMC_ASPEED; + ct[i].procname = "aspeed"; + ct[i].data = (void*)&(lp->ctl_aspeed); + ct[i].maxlen = sizeof lp->ctl_aspeed; + ct[i].mode = 0444; // Read only + + // LNKFAIL + ++i; + ct[i].ctl_name = CTL_SMC_LNKFAIL; + ct[i].procname = "lnkfail"; + ct[i].data = (void*)&(lp->ctl_lnkfail); + ct[i].maxlen = sizeof lp->ctl_lnkfail; + ct[i].mode = 0444; // Read only + + // FORCOL + ++i; + ct[i].ctl_name = CTL_SMC_FORCOL; + ct[i].procname = "forcol"; + ct[i].data = (void*)&(lp->ctl_forcol); + ct[i].maxlen = sizeof lp->ctl_forcol; + ct[i].mode = 0644; // Read by all, write by root + + // FILTCAR + ++i; + ct[i].ctl_name = CTL_SMC_FILTCAR; + ct[i].procname = "filtcar"; + ct[i].data = (void*)&(lp->ctl_filtcar); + ct[i].maxlen = sizeof lp->ctl_filtcar; + ct[i].mode = 0644; // Read by all, write by root + + // FREEMEM + ++i; + ct[i].ctl_name = CTL_SMC_FREEMEM; + ct[i].procname = "freemem"; + ct[i].data = (void*)&(lp->ctl_freemem); + ct[i].maxlen = sizeof lp->ctl_freemem; + ct[i].mode = 0444; // Read only + + // TOTMEM + ++i; + ct[i].ctl_name = CTL_SMC_TOTMEM; + ct[i].procname = "totmem"; + ct[i].data = (void*)&(lp->ctl_totmem); + ct[i].maxlen = sizeof lp->ctl_totmem; + ct[i].mode = 0444; // Read only + + // LEDA + ++i; + ct[i].ctl_name = CTL_SMC_LEDA; + ct[i].procname = "leda"; + ct[i].data = (void*)&(lp->ctl_leda); + ct[i].maxlen = sizeof lp->ctl_leda; + ct[i].mode = 0644; // Read by all, write by root + + // LEDB + ++i; + ct[i].ctl_name = CTL_SMC_LEDB; + ct[i].procname = "ledb"; + ct[i].data = (void*)&(lp->ctl_ledb); + ct[i].maxlen = sizeof lp->ctl_ledb; + ct[i].mode = 0644; // Read by all, write by root + + // CHIPREV + ++i; + ct[i].ctl_name = CTL_SMC_CHIPREV; + ct[i].procname = "chiprev"; + ct[i].data = (void*)&(lp->ctl_chiprev); + ct[i].maxlen = sizeof lp->ctl_chiprev; + ct[i].mode = 0444; // Read only + +#ifdef SMC_DEBUG + // REG_BSR + ++i; + ct[i].ctl_name = CTL_SMC_REG_BSR; + ct[i].procname = "reg_bsr"; + ct[i].data = (void*)&(lp->ctl_reg_bsr); + ct[i].maxlen = sizeof lp->ctl_reg_bsr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_TCR + ++i; + ct[i].ctl_name = CTL_SMC_REG_TCR; + ct[i].procname = "reg_tcr"; + ct[i].data = (void*)&(lp->ctl_reg_tcr); + ct[i].maxlen = sizeof lp->ctl_reg_tcr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_ESR + ++i; + ct[i].ctl_name = CTL_SMC_REG_ESR; + ct[i].procname = "reg_esr"; + ct[i].data = (void*)&(lp->ctl_reg_esr); + ct[i].maxlen = sizeof lp->ctl_reg_esr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_RCR + ++i; + ct[i].ctl_name = CTL_SMC_REG_RCR; + ct[i].procname = "reg_rcr"; + ct[i].data = (void*)&(lp->ctl_reg_rcr); + ct[i].maxlen = sizeof lp->ctl_reg_rcr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_CTRR + ++i; + ct[i].ctl_name = CTL_SMC_REG_CTRR; + ct[i].procname = "reg_ctrr"; + ct[i].data = (void*)&(lp->ctl_reg_ctrr); + ct[i].maxlen = sizeof lp->ctl_reg_ctrr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MIR + ++i; + ct[i].ctl_name = CTL_SMC_REG_MIR; + ct[i].procname = "reg_mir"; + ct[i].data = (void*)&(lp->ctl_reg_mir); + ct[i].maxlen = sizeof lp->ctl_reg_mir; + ct[i].mode = 0644; // Read by all, write by root + + // REG_RPCR + ++i; + ct[i].ctl_name = CTL_SMC_REG_RPCR; + ct[i].procname = "reg_rpcr"; + ct[i].data = (void*)&(lp->ctl_reg_rpcr); + ct[i].maxlen = sizeof lp->ctl_reg_rpcr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_CFGR + ++i; + ct[i].ctl_name = CTL_SMC_REG_CFGR; + ct[i].procname = "reg_cfgr"; + ct[i].data = (void*)&(lp->ctl_reg_cfgr); + ct[i].maxlen = sizeof lp->ctl_reg_cfgr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_BAR + ++i; + ct[i].ctl_name = CTL_SMC_REG_BAR; + ct[i].procname = "reg_bar"; + ct[i].data = (void*)&(lp->ctl_reg_bar); + ct[i].maxlen = sizeof lp->ctl_reg_bar; + ct[i].mode = 0644; // Read by all, write by root + + // REG_IAR0 + ++i; + ct[i].ctl_name = CTL_SMC_REG_IAR0; + ct[i].procname = "reg_iar0"; + ct[i].data = (void*)&(lp->ctl_reg_iar0); + ct[i].maxlen = sizeof lp->ctl_reg_iar0; + ct[i].mode = 0644; // Read by all, write by root + + // REG_IAR1 + ++i; + ct[i].ctl_name = CTL_SMC_REG_IAR1; + ct[i].procname = "reg_iar1"; + ct[i].data = (void*)&(lp->ctl_reg_iar1); + ct[i].maxlen = sizeof lp->ctl_reg_iar1; + ct[i].mode = 0644; // Read by all, write by root + + // REG_IAR2 + ++i; + ct[i].ctl_name = CTL_SMC_REG_IAR2; + ct[i].procname = "reg_iar2"; + ct[i].data = (void*)&(lp->ctl_reg_iar2); + ct[i].maxlen = sizeof lp->ctl_reg_iar2; + ct[i].mode = 0644; // Read by all, write by root + + // REG_GPR + ++i; + ct[i].ctl_name = CTL_SMC_REG_GPR; + ct[i].procname = "reg_gpr"; + ct[i].data = (void*)&(lp->ctl_reg_gpr); + ct[i].maxlen = sizeof lp->ctl_reg_gpr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_CTLR + ++i; + ct[i].ctl_name = CTL_SMC_REG_CTLR; + ct[i].procname = "reg_ctlr"; + ct[i].data = (void*)&(lp->ctl_reg_ctlr); + ct[i].maxlen = sizeof lp->ctl_reg_ctlr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MCR + ++i; + ct[i].ctl_name = CTL_SMC_REG_MCR; + ct[i].procname = "reg_mcr"; + ct[i].data = (void*)&(lp->ctl_reg_mcr); + ct[i].maxlen = sizeof lp->ctl_reg_mcr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_PNR + ++i; + ct[i].ctl_name = CTL_SMC_REG_PNR; + ct[i].procname = "reg_pnr"; + ct[i].data = (void*)&(lp->ctl_reg_pnr); + ct[i].maxlen = sizeof lp->ctl_reg_pnr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_FPR + ++i; + ct[i].ctl_name = CTL_SMC_REG_FPR; + ct[i].procname = "reg_fpr"; + ct[i].data = (void*)&(lp->ctl_reg_fpr); + ct[i].maxlen = sizeof lp->ctl_reg_fpr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_PTR + ++i; + ct[i].ctl_name = CTL_SMC_REG_PTR; + ct[i].procname = "reg_ptr"; + ct[i].data = (void*)&(lp->ctl_reg_ptr); + ct[i].maxlen = sizeof lp->ctl_reg_ptr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_DR + ++i; + ct[i].ctl_name = CTL_SMC_REG_DR; + ct[i].procname = "reg_dr"; + ct[i].data = (void*)&(lp->ctl_reg_dr); + ct[i].maxlen = sizeof lp->ctl_reg_dr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_ISR + ++i; + ct[i].ctl_name = CTL_SMC_REG_ISR; + ct[i].procname = "reg_isr"; + ct[i].data = (void*)&(lp->ctl_reg_isr); + ct[i].maxlen = sizeof lp->ctl_reg_isr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MTR1 + ++i; + ct[i].ctl_name = CTL_SMC_REG_MTR1; + ct[i].procname = "reg_mtr1"; + ct[i].data = (void*)&(lp->ctl_reg_mtr1); + ct[i].maxlen = sizeof lp->ctl_reg_mtr1; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MTR2 + ++i; + ct[i].ctl_name = CTL_SMC_REG_MTR2; + ct[i].procname = "reg_mtr2"; + ct[i].data = (void*)&(lp->ctl_reg_mtr2); + ct[i].maxlen = sizeof lp->ctl_reg_mtr2; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MTR3 + ++i; + ct[i].ctl_name = CTL_SMC_REG_MTR3; + ct[i].procname = "reg_mtr3"; + ct[i].data = (void*)&(lp->ctl_reg_mtr3); + ct[i].maxlen = sizeof lp->ctl_reg_mtr3; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MTR4 + ++i; + ct[i].ctl_name = CTL_SMC_REG_MTR4; + ct[i].procname = "reg_mtr4"; + ct[i].data = (void*)&(lp->ctl_reg_mtr4); + ct[i].maxlen = sizeof lp->ctl_reg_mtr4; + ct[i].mode = 0644; // Read by all, write by root + + // REG_MIIR + ++i; + ct[i].ctl_name = CTL_SMC_REG_MIIR; + ct[i].procname = "reg_miir"; + ct[i].data = (void*)&(lp->ctl_reg_miir); + ct[i].maxlen = sizeof lp->ctl_reg_miir; + ct[i].mode = 0644; // Read by all, write by root + + // REG_REVR + ++i; + ct[i].ctl_name = CTL_SMC_REG_REVR; + ct[i].procname = "reg_revr"; + ct[i].data = (void*)&(lp->ctl_reg_revr); + ct[i].maxlen = sizeof lp->ctl_reg_revr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_ERCVR + ++i; + ct[i].ctl_name = CTL_SMC_REG_ERCVR; + ct[i].procname = "reg_ercvr"; + ct[i].data = (void*)&(lp->ctl_reg_ercvr); + ct[i].maxlen = sizeof lp->ctl_reg_ercvr; + ct[i].mode = 0644; // Read by all, write by root + + // REG_EXTR + ++i; + ct[i].ctl_name = CTL_SMC_REG_EXTR; + ct[i].procname = "reg_extr"; + ct[i].data = (void*)&(lp->ctl_reg_extr); + ct[i].maxlen = sizeof lp->ctl_reg_extr; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Control + ++i; + ct[i].ctl_name = CTL_SMC_PHY_CTRL; + ct[i].procname = "phy_ctrl"; + ct[i].data = (void*)&(lp->ctl_phy_ctrl); + ct[i].maxlen = sizeof lp->ctl_phy_ctrl; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Status + ++i; + ct[i].ctl_name = CTL_SMC_PHY_STAT; + ct[i].procname = "phy_stat"; + ct[i].data = (void*)&(lp->ctl_phy_stat); + ct[i].maxlen = sizeof lp->ctl_phy_stat; + ct[i].mode = 0644; // Read by all, write by root + + // PHY ID1 + ++i; + ct[i].ctl_name = CTL_SMC_PHY_ID1; + ct[i].procname = "phy_id1"; + ct[i].data = (void*)&(lp->ctl_phy_id1); + ct[i].maxlen = sizeof lp->ctl_phy_id1; + ct[i].mode = 0644; // Read by all, write by root + + // PHY ID2 + ++i; + ct[i].ctl_name = CTL_SMC_PHY_ID2; + ct[i].procname = "phy_id2"; + ct[i].data = (void*)&(lp->ctl_phy_id2); + ct[i].maxlen = sizeof lp->ctl_phy_id2; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Advertise Capabilities + ++i; + ct[i].ctl_name = CTL_SMC_PHY_ADC; + ct[i].procname = "phy_adc"; + ct[i].data = (void*)&(lp->ctl_phy_adc); + ct[i].maxlen = sizeof lp->ctl_phy_adc; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Remote Capabilities + ++i; + ct[i].ctl_name = CTL_SMC_PHY_REMC; + ct[i].procname = "phy_remc"; + ct[i].data = (void*)&(lp->ctl_phy_remc); + ct[i].maxlen = sizeof lp->ctl_phy_remc; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Configuration 1 + ++i; + ct[i].ctl_name = CTL_SMC_PHY_CFG1; + ct[i].procname = "phy_cfg1"; + ct[i].data = (void*)&(lp->ctl_phy_cfg1); + ct[i].maxlen = sizeof lp->ctl_phy_cfg1; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Configuration 2 + ++i; + ct[i].ctl_name = CTL_SMC_PHY_CFG2; + ct[i].procname = "phy_cfg2"; + ct[i].data = (void*)&(lp->ctl_phy_cfg2); + ct[i].maxlen = sizeof lp->ctl_phy_cfg2; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Interrupt/Status Output + ++i; + ct[i].ctl_name = CTL_SMC_PHY_INT; + ct[i].procname = "phy_int"; + ct[i].data = (void*)&(lp->ctl_phy_int); + ct[i].maxlen = sizeof lp->ctl_phy_int; + ct[i].mode = 0644; // Read by all, write by root + + // PHY Interrupt/Status Mask + ++i; + ct[i].ctl_name = CTL_SMC_PHY_MASK; + ct[i].procname = "phy_mask"; + ct[i].data = (void*)&(lp->ctl_phy_mask); + ct[i].maxlen = sizeof lp->ctl_phy_mask; + ct[i].mode = 0644; // Read by all, write by root + +#endif // SMC_DEBUG + + // Register /proc/sys/dev/ethX + lp->sysctl_header = register_sysctl_table(lp->root_table, 1); + +} + + +/*------------------------------------------------------------ + . Sysctl unregistration when driver is closed + .-------------------------------------------------------------*/ +static void smc_sysctl_unregister(struct net_device *dev) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + + unregister_sysctl_table(lp->sysctl_header); +} + +#endif /* endif CONFIG_SYSCTL */ + + +//---PHY CONTROL AND CONFIGURATION----------------------------------------- + +#if (SMC_DEBUG > 2 ) + +/*------------------------------------------------------------ + . Debugging function for viewing MII Management serial bitstream + .-------------------------------------------------------------*/ +static void smc_dump_mii_stream(byte* bits, int size) +{ + int i; + + printk("BIT#:"); + for (i = 0; i < size; ++i) + { + printk("%d", i%10); + } + + printk("\nMDOE:"); + for (i = 0; i < size; ++i) + { + if (bits[i] & MII_MDOE) + printk("1"); + else + printk("0"); + } + + printk("\nMDO :"); + for (i = 0; i < size; ++i) + { + if (bits[i] & MII_MDO) + printk("1"); + else + printk("0"); + } + + printk("\nMDI :"); + for (i = 0; i < size; ++i) + { + if (bits[i] & MII_MDI) + printk("1"); + else + printk("0"); + } + + printk("\n"); +} +#endif + +/*------------------------------------------------------------ + . Reads a register from the MII Management serial interface + .-------------------------------------------------------------*/ +static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg) +{ + int oldBank; + int i; + byte mask; + word mii_reg; + byte bits[64]; + int clk_idx = 0; + int input_idx; + word phydata; + + // 32 consecutive ones on MDO to establish sync + for (i = 0; i < 32; ++i) + bits[clk_idx++] = MII_MDOE | MII_MDO; + + // Start code <01> + bits[clk_idx++] = MII_MDOE; + bits[clk_idx++] = MII_MDOE | MII_MDO; + + // Read command <10> + bits[clk_idx++] = MII_MDOE | MII_MDO; + bits[clk_idx++] = MII_MDOE; + + // Output the PHY address, msb first + mask = (byte)0x10; + for (i = 0; i < 5; ++i) + { + if (phyaddr & mask) + bits[clk_idx++] = MII_MDOE | MII_MDO; + else + bits[clk_idx++] = MII_MDOE; + + // Shift to next lowest bit + mask >>= 1; + } + + // Output the phy register number, msb first + mask = (byte)0x10; + for (i = 0; i < 5; ++i) + { + if (phyreg & mask) + bits[clk_idx++] = MII_MDOE | MII_MDO; + else + bits[clk_idx++] = MII_MDOE; + + // Shift to next lowest bit + mask >>= 1; + } + + // Tristate and turnaround (2 bit times) + bits[clk_idx++] = 0; + //bits[clk_idx++] = 0; + + // Input starts at this bit time + input_idx = clk_idx; + + // Will input 16 bits + for (i = 0; i < 16; ++i) + bits[clk_idx++] = 0; + + // Final clock bit + bits[clk_idx++] = 0; + + // Save the current bank + oldBank = SMC_inw( BANK_SELECT ); + + // Select bank 3 + SMC_SELECT_BANK( 3 ); + + // Get the current MII register value + mii_reg = SMC_inw( MII_REG ); + + // Turn off all MII Interface bits + mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); + + // Clock all 64 cycles + for (i = 0; i < sizeof bits; ++i) + { + // Clock Low - output data + SMC_outw( mii_reg | bits[i], MII_REG ); + udelay(50); + + + // Clock Hi - input data + SMC_outw( mii_reg | bits[i] | MII_MCLK, MII_REG ); + udelay(50); + bits[i] |= SMC_inw( MII_REG ) & MII_MDI; + } + + // Return to idle state + // Set clock to low, data to low, and output tristated + SMC_outw( mii_reg, MII_REG ); + udelay(50); + + // Restore original bank select + SMC_SELECT_BANK( oldBank ); + + // Recover input data + phydata = 0; + for (i = 0; i < 16; ++i) + { + phydata <<= 1; + + if (bits[input_idx++] & MII_MDI) + phydata |= 0x0001; + } + +#if (SMC_DEBUG > 2 ) + printk("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", + phyaddr, phyreg, phydata); + smc_dump_mii_stream(bits, sizeof bits); +#endif + + return(phydata); +} + + +/*------------------------------------------------------------ + . Writes a register to the MII Management serial interface + .-------------------------------------------------------------*/ +static void smc_write_phy_register(int ioaddr, + byte phyaddr, byte phyreg, word phydata) +{ + int oldBank; + int i; + word mask; + word mii_reg; + byte bits[65]; + int clk_idx = 0; + + // 32 consecutive ones on MDO to establish sync + for (i = 0; i < 32; ++i) + bits[clk_idx++] = MII_MDOE | MII_MDO; + + // Start code <01> + bits[clk_idx++] = MII_MDOE; + bits[clk_idx++] = MII_MDOE | MII_MDO; + + // Write command <01> + bits[clk_idx++] = MII_MDOE; + bits[clk_idx++] = MII_MDOE | MII_MDO; + + // Output the PHY address, msb first + mask = (byte)0x10; + for (i = 0; i < 5; ++i) + { + if (phyaddr & mask) + bits[clk_idx++] = MII_MDOE | MII_MDO; + else + bits[clk_idx++] = MII_MDOE; + + // Shift to next lowest bit + mask >>= 1; + } + + // Output the phy register number, msb first + mask = (byte)0x10; + for (i = 0; i < 5; ++i) + { + if (phyreg & mask) + bits[clk_idx++] = MII_MDOE | MII_MDO; + else + bits[clk_idx++] = MII_MDOE; + + // Shift to next lowest bit + mask >>= 1; + } + + // Tristate and turnaround (2 bit times) + bits[clk_idx++] = 0; + bits[clk_idx++] = 0; + + // Write out 16 bits of data, msb first + mask = 0x8000; + for (i = 0; i < 16; ++i) + { + if (phydata & mask) + bits[clk_idx++] = MII_MDOE | MII_MDO; + else + bits[clk_idx++] = MII_MDOE; + + // Shift to next lowest bit + mask >>= 1; + } + + // Final clock bit (tristate) + bits[clk_idx++] = 0; + + // Save the current bank + oldBank = SMC_inw( BANK_SELECT ); + + // Select bank 3 + SMC_SELECT_BANK( 3 ); + + // Get the current MII register value + mii_reg = SMC_inw( MII_REG ); + + // Turn off all MII Interface bits + mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO); + + // Clock all cycles + for (i = 0; i < sizeof bits; ++i) + { + // Clock Low - output data + SMC_outw( mii_reg | bits[i], MII_REG ); + udelay(50); + + + // Clock Hi - input data + SMC_outw( mii_reg | bits[i] | MII_MCLK, MII_REG ); + udelay(50); + bits[i] |= SMC_inw( MII_REG ) & MII_MDI; + } + + // Return to idle state + // Set clock to low, data to low, and output tristated + SMC_outw( mii_reg, MII_REG ); + udelay(50); + + // Restore original bank select + SMC_SELECT_BANK( oldBank ); + +#if (SMC_DEBUG > 2 ) + printk("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n", + phyaddr, phyreg, phydata); + smc_dump_mii_stream(bits, sizeof bits); +#endif +} + + +/*------------------------------------------------------------ + . Finds and reports the PHY address + .-------------------------------------------------------------*/ +static int smc_detect_phy(struct net_device* dev) +{ + struct smc_local *lp = (struct smc_local *)dev->priv; + int ioaddr = dev->base_addr; + word phy_id1; + word phy_id2; + int phyaddr; + int found = 0; + + PRINTK3("%s:smc_detect_phy()\n", dev->name); + + // Scan all 32 PHY addresses if necessary + for (phyaddr = 0; phyaddr < 32; ++phyaddr) + { + // Read the PHY identifiers + phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG); + phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG); + + PRINTK3("%s: phy_id1=%x, phy_id2=%x\n", dev->name, phy_id1, phy_id2); + + // Make sure it is a valid identifier + if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) && + (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) + { + if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) + { + // Save the PHY's address + lp->phyaddr = phyaddr; + found = 1; + break; + } + } + } + + if (!found) + { + PRINTK("%s: No PHY found\n", dev->name); + return(0); + } + + // Set the PHY type + if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) + { + lp->phytype = PHY_LAN83C183; + PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name); + } + + if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) + { + lp->phytype = PHY_LAN83C180; + PRINTK("%s: PHY=LAN83C180\n", dev->name); + } + + return(1); +} + +/*------------------------------------------------------------ + . Waits the specified number of milliseconds - kernel friendly + .-------------------------------------------------------------*/ +static void smc_wait_ms(unsigned int ms) +{ + + if (!in_interrupt()) + { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); + } + else + { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1 + ms * HZ / 1000); + current->state = TASK_RUNNING; + } +} + +/*------------------------------------------------------------ + . Sets the PHY to a configuration as determined by the user + .-------------------------------------------------------------*/ +static int smc_phy_fixed(struct net_device* dev) +{ + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + byte phyaddr = lp->phyaddr; + word my_fixed_caps; + word cfg1; + + PRINTK3("%s:smc_phy_fixed()\n", dev->name); + + // Enter Link Disable state + cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG); + cfg1 |= PHY_CFG1_LNKDIS; + smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1); + + // Set our fixed capabilities + // Disable auto-negotiation + my_fixed_caps = 0; + + if (lp->ctl_rfduplx) + my_fixed_caps |= PHY_CNTL_DPLX; + + if (lp->ctl_rspeed == 100) + my_fixed_caps |= PHY_CNTL_SPEED; + + // Write our capabilities to the phy control register + smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps); + + // Re-Configure the Receive/Phy Control register + SMC_outw( lp->rpc_cur_mode, RPC_REG ); + + // Success + return(1); +} + + +/*------------------------------------------------------------ + . Configures the specified PHY using Autonegotiation. Calls + . smc_phy_fixed() if the user has requested a certain config. + .-------------------------------------------------------------*/ +static void smc_phy_configure(struct net_device *dev) +{ + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + int timeout; + byte phyaddr; + word my_phy_caps; // My PHY capabilities + word my_ad_caps; // My Advertised capabilities + word status = 0; //;my status = 0 + int failed = 0; + + PRINTK3("%s:smc_program_phy()\n", dev->name); + + // Set the blocking flag + lp->autoneg_active = 1; + + // Find the address and type of our phy + if (!smc_detect_phy(dev)) + { + goto smc_phy_configure_exit; + } + + // Get the detected phy address + phyaddr = lp->phyaddr; + + // Reset the PHY, setting all other bits to zero + smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST); + + // Wait for the reset to complete, or time out + timeout = 6; // Wait up to 3 seconds + while (timeout--) + { + if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG) + & PHY_CNTL_RST)) + { + // reset complete + break; + } + + smc_wait_ms(500); // wait 500 millisecs + if (signal_pending(current)) // Exit anyway if signaled + { + PRINTK2("%s:PHY reset interrupted by signal\n", + dev->name); + timeout = 0; + break; + } + } + + if (timeout < 1) + { + PRINTK2("%s:PHY reset timed out\n", dev->name); + goto smc_phy_configure_exit; + } + + // Read PHY Register 18, Status Output + lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); + + // Enable PHY Interrupts (for register 18) + // Interrupts listed here are disabled + smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG, + PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD | + PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB | + PHY_INT_SPDDET | PHY_INT_DPLXDET); + + /* Configure the Receive/Phy Control register */ + SMC_SELECT_BANK( 0 ); + SMC_outw( lp->rpc_cur_mode, RPC_REG ); + + // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG + my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); + my_ad_caps = PHY_AD_CSMA; // I am CSMA capable + + if (my_phy_caps & PHY_STAT_CAP_T4) + my_ad_caps |= PHY_AD_T4; + + if (my_phy_caps & PHY_STAT_CAP_TXF) + my_ad_caps |= PHY_AD_TX_FDX; + + if (my_phy_caps & PHY_STAT_CAP_TXH) + my_ad_caps |= PHY_AD_TX_HDX; + + if (my_phy_caps & PHY_STAT_CAP_TF) + my_ad_caps |= PHY_AD_10_FDX; + + if (my_phy_caps & PHY_STAT_CAP_TH) + my_ad_caps |= PHY_AD_10_HDX; + + // Disable capabilities not selected by our user + if (lp->ctl_rspeed != 100) + { + my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX); + } + + if (!lp->ctl_rfduplx) + { + my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX); + } + + // Update our Auto-Neg Advertisement Register + smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps); + + PRINTK2("%s:phy caps=%x\n", dev->name, my_phy_caps); + PRINTK2("%s:phy advertised caps=%x\n", dev->name, my_ad_caps); + + // If the user requested no auto neg, then go set his request + if (!(lp->ctl_autoneg)) + { + smc_phy_fixed(dev); + goto smc_phy_configure_exit; + } + + // Restart auto-negotiation process in order to advertise my caps + smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, + PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST ); + + // Wait for the auto-negotiation to complete. This may take from + // 2 to 3 seconds. + // Wait for the reset to complete, or time out + timeout = 20; // Wait up to 10 seconds + while (timeout--) + { + status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG); + if (status & PHY_STAT_ANEG_ACK) + { + // auto-negotiate complete + break; + } + + smc_wait_ms(500); // wait 500 millisecs + if (signal_pending(current)) // Exit anyway if signaled + { + printk(KERN_DEBUG + "%s:PHY auto-negotiate interrupted by signal\n", + dev->name); + timeout = 0; + break; + } + + // Restart auto-negotiation if remote fault + if (status & PHY_STAT_REM_FLT) + { + PRINTK2("%s:PHY remote fault detected\n", dev->name); + + // Restart auto-negotiation + PRINTK2("%s:PHY restarting auto-negotiation\n", + dev->name); + smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG, + PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST | + PHY_CNTL_SPEED | PHY_CNTL_DPLX); + } + } + + if (timeout < 1) + { + printk(KERN_DEBUG "%s:PHY auto-negotiate timed out\n", + dev->name); + PRINTK2("%s:PHY auto-negotiate timed out\n", dev->name); + failed = 1; + } + + // Fail if we detected an auto-negotiate remote fault + if (status & PHY_STAT_REM_FLT) + { + printk(KERN_DEBUG "%s:PHY remote fault detected\n", dev->name); + PRINTK2("%s:PHY remote fault detected\n", dev->name); + failed = 1; + } + + // The smc_phy_interrupt() routine will be called to update lastPhy18 + + // Set our sysctl parameters to match auto-negotiation results + if ( lp->lastPhy18 & PHY_INT_SPDDET ) + { + PRINTK2("%s:PHY 100BaseT\n", dev->name); + lp->rpc_cur_mode |= RPC_SPEED; + } + else + { + PRINTK2("%s:PHY 10BaseT\n", dev->name); + lp->rpc_cur_mode &= ~RPC_SPEED; + } + + if ( lp->lastPhy18 & PHY_INT_DPLXDET ) + { + PRINTK2("%s:PHY Full Duplex\n", dev->name); + lp->rpc_cur_mode |= RPC_DPLX; + } + else + { + PRINTK2("%s:PHY Half Duplex\n", dev->name); + lp->rpc_cur_mode &= ~RPC_DPLX; + } + + // Re-Configure the Receive/Phy Control register + SMC_outw( lp->rpc_cur_mode, RPC_REG ); + + smc_phy_configure_exit: + + // Exit auto-negotiation + lp->autoneg_active = 0; +} + + + +/************************************************************************* + . smc_phy_interrupt + . + . Purpose: Handle interrupts relating to PHY register 18. This is + . called from the "hard" interrupt handler. + . + ************************************************************************/ +static void smc_phy_interrupt(struct net_device* dev) +{ + int ioaddr = dev->base_addr; + struct smc_local *lp = (struct smc_local *)dev->priv; + byte phyaddr = lp->phyaddr; + word phy18; + + PRINTK2("%s: smc_phy_interrupt\n", dev->name); + + while (1) + { + // Read PHY Register 18, Status Output + phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG); + + // Exit if not more changes + if (phy18 == lp->lastPhy18) + break; + +#if (SMC_DEBUG > 1 ) + + PRINTK2("%s: phy18=0x%x\n", dev->name, phy18); + PRINTK2("%s: lastPhy18=0x%x\n", dev->name, lp->lastPhy18); + + // Handle events + if ((phy18 & PHY_INT_LNKFAIL) != (lp->lastPhy18 & PHY_INT_LNKFAIL)) + { + PRINTK2("%s: PHY Link Fail=%x\n", dev->name, + phy18 & PHY_INT_LNKFAIL); + } + + if ((phy18 & PHY_INT_LOSSSYNC) != (lp->lastPhy18 & PHY_INT_LOSSSYNC)) + { + PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name, + phy18 & PHY_INT_LOSSSYNC); + } + + if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD)) + { + PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name, + phy18 & PHY_INT_CWRD); + } + + if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD)) + { + PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name, + phy18 & PHY_INT_SSD); + } + + if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD)) + { + PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name, + phy18 & PHY_INT_ESD); + } + + if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL)) + { + PRINTK2("%s: PHY Reverse Polarity Detected=%x\n", dev->name, + phy18 & PHY_INT_RPOL); + } + + if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB)) + { + PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name, + phy18 & PHY_INT_JAB); + } + + if ((phy18 & PHY_INT_SPDDET) != (lp->lastPhy18 & PHY_INT_SPDDET)) + { + PRINTK2("%s: PHY Speed Detect=%x\n", dev->name, + phy18 & PHY_INT_SPDDET); + } + + if ((phy18 & PHY_INT_DPLXDET) != (lp->lastPhy18 & PHY_INT_DPLXDET)) + { + PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name, + phy18 & PHY_INT_DPLXDET); + } +#endif + + // Update the last phy 18 variable + lp->lastPhy18 = phy18; + + } // end while +} + + diff -urN linux-2.4.5-rmk7-np2/drivers/net/smc91111.h linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc91111.h --- linux-2.4.5-rmk7-np2/drivers/net/smc91111.h Thu Jan 1 01:00:00 1970 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc91111.h Fri Dec 7 11:41:53 2001 @@ -0,0 +1,631 @@ +/*------------------------------------------------------------------------ + . smc91111.h - macros for the LAN91C111 Ethernet Driver + . + . Copyright (C) 2001 Standard Microsystems Corporation (SMSC) + . Developed by Simple Network Magic Corporation (SNMC) + . Copyright (C) 1996 by Erik Stahlman (ES) + . + . 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. + . + . 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + . + . This file contains register information and access macros for + . the LAN91C111 single chip ethernet controller. It is a modified + . version of the smc9194.h file. + . + . Information contained in this file was obtained from the LAN91C111 + . manual from SMC. To get a copy, if you really want one, you can find + . information under www.smsc.com. + . + . Authors + . Erik Stahlman ( erik@vt.edu ) + . Daris A Nevil ( dnevil@snmc.com ) + . + . History + . 03/16/01 Daris A Nevil Modified for use with LAN91C111 device + . + ---------------------------------------------------------------------------*/ +#ifndef _SMC91111_H_ +#define _SMC91111_H_ + +/* I want some simple types */ + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long int dword; + +/* + . DEBUGGING LEVELS + . + . 0 for normal operation + . 1 for slightly more details + . >2 for various levels of increasingly useless information + . 2 for interrupt tracking, status flags + . 3 for packet info + . 4 for complete packet dumps +*/ +//#define SMC_DEBUG 0 + +/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */ + +#ifdef CONFIG_ISA +#define SMC_IO_EXTENT 16 +#endif + +#ifdef CONFIG_SA1100_ADSBITSY +#define SMC_IO_EXTENT 16 + +#define SMC_inw(r) (*((volatile word *)(ioaddr+(r)))) +#define SMC_inb(r) (*((volatile byte *)(ioaddr+(r)))) +// (((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF) + +#define SMC_outw(d,r) (*((volatile word *)(ioaddr+(r))) = d) +#define SMC_outb(d,r) (*((volatile byte *)(ioaddr+(r))) = d) +/* ({ word __d = (byte)(d); \ + word __w = SMC_inw((r)&~1); \ + __w &= ((r)&1) ? 0x00FF : 0xFF00; \ + __w |= ((r)&1) ? __d<<8 : __d; \ + SMC_outw(__w,(r)&~1); }) */ + +#define SMC_insw(r,b,l) insw(ioaddr+(r), (b), (l)) +#define SMC_outsw(r,b,l) outsw(ioaddr+(r), (b), (l)) + +#endif + +#ifdef CONFIG_SA1100_DNP1110 +/* + * We have only 16 Bit PCMCIA access on Socket 0 + */ +#define SMC_IO_EXTENT 16 + +#define SMC_inw(r) (*((volatile word *)(ioaddr+(r)))) +#define SMC_inb(r) (((r)&1) ? SMC_inw((r)&~1)>>8 : SMC_inw(r)&0xFF) + +#define SMC_outw(d,r) (*((volatile word *)(ioaddr+(r))) = d) +#define SMC_outb(d,r) ({ word __d = (byte)(d); \ + word __w = SMC_inw((r)&~1); \ + __w &= ((r)&1) ? 0x00FF : 0xFF00; \ + __w |= ((r)&1) ? __d<<8 : __d; \ + SMC_outw(__w,(r)&~1); \ + }) + +#define SMC_outsw(r,b,l) outsw(ioaddr+(r), (b), (l)) + +#if 1 +#define SMC_insw(r,b,l) insw(ioaddr+(r), (b), (l)) +#else +#define SMC_insw(r,b,l) ({ int __i ; \ + word *__b2; \ + __b2 = (word *) b; \ + for (__i = 0; __i < l; __i++) { \ + *(__b2 + __i) = SMC_inw(r); \ + SMC_inw(0); \ + }; \ + }) +#endif +#endif + +/*--------------------------------------------------------------- + . + . A description of the SMSC registers is probably in order here, + . although for details, the SMC datasheet is invaluable. + . + . Basically, the chip has 4 banks of registers ( 0 to 3 ), which + . are accessed by writing a number into the BANK_SELECT register + . ( I also use a SMC_SELECT_BANK macro for this ). + . + . The banks are configured so that for most purposes, bank 2 is all + . that is needed for simple run time tasks. + -----------------------------------------------------------------------*/ + +/* + . Bank Select Register: + . + . yyyy yyyy 0000 00xx + . xx = bank number + . yyyy yyyy = 0x33, for identification purposes. +*/ +#define BANK_SELECT 14 + +// Transmit Control Register +/* BANK 0 */ +#define TCR_REG 0x0000 // transmit control register +#define TCR_ENABLE 0x0001 // When 1 we can transmit +#define TCR_LOOP 0x0002 // Controls output pin LBK +#define TCR_FORCOL 0x0004 // When 1 will force a collision +#define TCR_PAD_EN 0x0080 // When 1 will pad tx frames < 64 bytes w/0 +#define TCR_NOCRC 0x0100 // When 1 will not append CRC to tx frames +#define TCR_MON_CSN 0x0400 // When 1 tx monitors carrier +#define TCR_FDUPLX 0x0800 // When 1 enables full duplex operation +#define TCR_STP_SQET 0x1000 // When 1 stops tx if Signal Quality Error +#define TCR_EPH_LOOP 0x2000 // When 1 enables EPH block loopback +#define TCR_SWFDUP 0x8000 // When 1 enables Switched Full Duplex mode + +#define TCR_CLEAR 0 /* do NOTHING */ +/* the default settings for the TCR register : */ +/* QUESTION: do I want to enable padding of short packets ? */ +#define TCR_DEFAULT TCR_ENABLE + + +// EPH Status Register +/* BANK 0 */ +#define EPH_STATUS_REG 0x0002 +#define ES_TX_SUC 0x0001 // Last TX was successful +#define ES_SNGL_COL 0x0002 // Single collision detected for last tx +#define ES_MUL_COL 0x0004 // Multiple collisions detected for last tx +#define ES_LTX_MULT 0x0008 // Last tx was a multicast +#define ES_16COL 0x0010 // 16 Collisions Reached +#define ES_SQET 0x0020 // Signal Quality Error Test +#define ES_LTXBRD 0x0040 // Last tx was a broadcast +#define ES_TXDEFR 0x0080 // Transmit Deferred +#define ES_LATCOL 0x0200 // Late collision detected on last tx +#define ES_LOSTCARR 0x0400 // Lost Carrier Sense +#define ES_EXC_DEF 0x0800 // Excessive Deferral +#define ES_CTR_ROL 0x1000 // Counter Roll Over indication +#define ES_LINK_OK 0x4000 // Driven by inverted value of nLNK pin +#define ES_TXUNRN 0x8000 // Tx Underrun + + +// Receive Control Register +/* BANK 0 */ +#define RCR_REG 0x0004 +#define RCR_RX_ABORT 0x0001 // Set if a rx frame was aborted +#define RCR_PRMS 0x0002 // Enable promiscuous mode +#define RCR_ALMUL 0x0004 // When set accepts all multicast frames +#define RCR_RXEN 0x0100 // IFF this is set, we can receive packets +#define RCR_STRIP_CRC 0x0200 // When set strips CRC from rx packets +#define RCR_ABORT_ENB 0x0200 // When set will abort rx on collision +#define RCR_FILT_CAR 0x0400 // When set filters leading 12 bit s of carrier +#define RCR_SOFTRST 0x8000 // resets the chip + +/* the normal settings for the RCR register : */ +#define RCR_DEFAULT (RCR_STRIP_CRC | RCR_RXEN) +#define RCR_CLEAR 0x0 // set it to a base state + +// Counter Register +/* BANK 0 */ +#define COUNTER_REG 0x0006 + +// Memory Information Register +/* BANK 0 */ +#define MIR_REG 0x0008 + +// Receive/Phy Control Register +/* BANK 0 */ +#define RPC_REG 0x000A +#define RPC_SPEED 0x2000 // When 1 PHY is in 100Mbps mode. +#define RPC_DPLX 0x1000 // When 1 PHY is in Full-Duplex Mode +#define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode +#define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb +#define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb +#define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect +#define RPC_LED_RES (0x01) // LED = Reserved +#define RPC_LED_10 (0x02) // LED = 10Mbps link detect +#define RPC_LED_FD (0x03) // LED = Full Duplex Mode +#define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred +#define RPC_LED_100 (0x05) // LED = 100Mbps link dectect +#define RPC_LED_TX (0x06) // LED = TX packet occurred +#define RPC_LED_RX (0x07) // LED = RX packet occurred +#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX) + +/* Bank 0 0x000C is reserved */ + +// Bank Select Register +/* All Banks */ +#define BSR_REG 0x000E + + +// Configuration Reg +/* BANK 1 */ +#define CONFIG_REG 0x0000 +#define CONFIG_EXT_PHY 0x0200 // 1=external MII, 0=internal Phy +#define CONFIG_GPCNTRL 0x0400 // Inverse value drives pin nCNTRL +#define CONFIG_NO_WAIT 0x1000 // When 1 no extra wait states on ISA bus +#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode. + +// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low +#define CONFIG_DEFAULT (CONFIG_EPH_POWER_EN) + + +// Base Address Register +/* BANK 1 */ +#define BASE_REG 0x0002 + + +// Individual Address Registers +/* BANK 1 */ +#define ADDR0_REG 0x0004 +#define ADDR1_REG 0x0006 +#define ADDR2_REG 0x0008 + + +// General Purpose Register +/* BANK 1 */ +#define GP_REG 0x000A + + +// Control Register +/* BANK 1 */ +#define CTL_REG 0x000C +#define CTL_RCV_BAD 0x4000 // When 1 bad CRC packets are received +#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically +#define CTL_LE_ENABLE 0x0080 // When 1 enables Link Error interrupt +#define CTL_CR_ENABLE 0x0040 // When 1 enables Counter Rollover interrupt +#define CTL_TE_ENABLE 0x0020 // When 1 enables Transmit Error interrupt +#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store +#define CTL_RELOAD 0x0002 // When set reads EEPROM into registers +#define CTL_STORE 0x0001 // When set stores registers into EEPROM + + +// MMU Command Register +/* BANK 2 */ +#define MMU_CMD_REG 0x0000 +#define MC_BUSY 1 // When 1 the last release has not completed +#define MC_NOP (0<<5) // No Op +#define MC_ALLOC (1<<5) // OR with number of 256 byte packets +#define MC_RESET (2<<5) // Reset MMU to initial state +#define MC_REMOVE (3<<5) // Remove the current rx packet +#define MC_RELEASE (4<<5) // Remove and release the current rx packet +#define MC_FREEPKT (5<<5) // Release packet in PNR register +#define MC_ENQUEUE (6<<5) // Enqueue the packet for transmit +#define MC_RSTTXFIFO (7<<5) // Reset the TX FIFOs + + +// Packet Number Register +/* BANK 2 */ +#define PN_REG 0x0002 + + +// Allocation Result Register +/* BANK 2 */ +#define AR_REG 0x0003 +#define AR_FAILED 0x80 // Alocation Failed + + +// RX FIFO Ports Register +/* BANK 2 */ +#define RXFIFO_REG 0x0004 // Must be read as a word +#define RXFIFO_REMPTY 0x8000 // RX FIFO Empty + + +// TX FIFO Ports Register +/* BANK 2 */ +#define TXFIFO_REG RXFIFO_REG // Must be read as a word +#define TXFIFO_TEMPTY 0x80 // TX FIFO Empty + + +// Pointer Register +/* BANK 2 */ +#define PTR_REG 0x0006 +#define PTR_RCV 0x8000 // 1=Receive area, 0=Transmit area +#define PTR_AUTOINC 0x4000 // Auto increment the pointer on each access +#define PTR_READ 0x2000 // When 1 the operation is a read + + +// Data Register +/* BANK 2 */ +#define DATA_REG 0x0008 + + +// Interrupt Status/Acknowledge Register +/* BANK 2 */ +#define INT_REG 0x000C + + +// Interrupt Mask Register +/* BANK 2 */ +#define IM_REG 0x000D +#define IM_MDINT 0x80 // PHY MI Register 18 Interrupt +#define IM_ERCV_INT 0x40 // Early Receive Interrupt +#define IM_EPH_INT 0x20 // Set by Etheret Protocol Handler section +#define IM_RX_OVRN_INT 0x10 // Set by Receiver Overruns +#define IM_ALLOC_INT 0x08 // Set when allocation request is completed +#define IM_TX_EMPTY_INT 0x04 // Set if the TX FIFO goes empty +#define IM_TX_INT 0x02 // Transmit Interrrupt +#define IM_RCV_INT 0x01 // Receive Interrupt + + +// Multicast Table Registers +/* BANK 3 */ +#define MCAST_REG1 0x0000 +#define MCAST_REG2 0x0002 +#define MCAST_REG3 0x0004 +#define MCAST_REG4 0x0006 + + +// Management Interface Register (MII) +/* BANK 3 */ +#define MII_REG 0x0008 +#define MII_MSK_CRS100 0x4000 // Disables CRS100 detection during tx half dup +#define MII_MDOE 0x0008 // MII Output Enable +#define MII_MCLK 0x0004 // MII Clock, pin MDCLK +#define MII_MDI 0x0002 // MII Input, pin MDI +#define MII_MDO 0x0001 // MII Output, pin MDO + + +// Revision Register +/* BANK 3 */ +#define REV_REG 0x000A /* ( hi: chip id low: rev # ) */ + + +// Early RCV Register +/* BANK 3 */ +/* this is NOT on SMC9192 */ +#define ERCV_REG 0x000C +#define ERCV_RCV_DISCRD 0x0080 // When 1 discards a packet being received +#define ERCV_THRESHOLD 0x001F // ERCV Threshold Mask + +// External Register +/* BANK 7 */ +#define EXT_REG 0x0000 + + +#define CHIP_9192 3 +#define CHIP_9194 4 +#define CHIP_9195 5 +#define CHIP_9196 6 +#define CHIP_91100 7 +#define CHIP_91100FD 8 +#define CHIP_91111FD 9 + +static const char * chip_ids[ 15 ] = { + NULL, NULL, NULL, + /* 3 */ "SMC91C90/91C92", + /* 4 */ "SMC91C94", + /* 5 */ "SMC91C95", + /* 6 */ "SMC91C96", + /* 7 */ "SMC91C100", + /* 8 */ "SMC91C100FD", + /* 9 */ "SMC91C111", + NULL, NULL, + NULL, NULL, NULL}; + +/* + . Transmit status bits +*/ +#define TS_SUCCESS 0x0001 +#define TS_LOSTCAR 0x0400 +#define TS_LATCOL 0x0200 +#define TS_16COL 0x0010 + +/* + . Receive status bits +*/ +#define RS_ALGNERR 0x8000 +#define RS_BRODCAST 0x4000 +#define RS_BADCRC 0x2000 +#define RS_ODDFRAME 0x1000 // bug: the LAN91C111 never sets this on receive +#define RS_TOOLONG 0x0800 +#define RS_TOOSHORT 0x0400 +#define RS_MULTICAST 0x0001 +#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) + + +// PHY Types +enum { + PHY_LAN83C183 = 1, // LAN91C111 Internal PHY + PHY_LAN83C180 +}; + + +// PHY Register Addresses (LAN91C111 Internal PHY) + +// PHY Control Register +#define PHY_CNTL_REG 0x00 +#define PHY_CNTL_RST 0x8000 // 1=PHY Reset +#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback +#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs +#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation +#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode +#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled +#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate +#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex +#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test + +// PHY Status Register +#define PHY_STAT_REG 0x01 +#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable +#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable +#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable +#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable +#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable +#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble +#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed +#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected +#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable +#define PHY_STAT_LINK 0x0004 // 1=valid link +#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition +#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented + +// PHY Identifier Registers +#define PHY_ID1_REG 0x02 // PHY Identifier 1 +#define PHY_ID2_REG 0x03 // PHY Identifier 2 + +// PHY Auto-Negotiation Advertisement Register +#define PHY_AD_REG 0x04 +#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page +#define PHY_AD_ACK 0x4000 // 1=got link code word from remote +#define PHY_AD_RF 0x2000 // 1=advertise remote fault +#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4 +#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX +#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX +#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX +#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX +#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA + +// PHY Auto-negotiation Remote End Capability Register +#define PHY_RMT_REG 0x05 +// Uses same bit definitions as PHY_AD_REG + +// PHY Configuration Register 1 +#define PHY_CFG1_REG 0x10 +#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled +#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled +#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down +#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler +#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable +#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled +#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm) +#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db +#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust +#define PHY_CFG1_TLVL_MASK 0x003C +#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time + + +// PHY Configuration Register 2 +#define PHY_CFG2_REG 0x11 +#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled +#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled +#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt) +#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo + +// PHY Status Output (and Interrupt status) Register +#define PHY_INT_REG 0x12 // Status Output (Interrupt Status) +#define PHY_INT_INT 0x8000 // 1=bits have changed since last read +#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected +#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync +#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx +#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx +#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx +#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected +#define PHY_INT_JAB 0x0100 // 1=Jabber detected +#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode +#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex + +// PHY Interrupt/Status Mask Register +#define PHY_MASK_REG 0x13 // Interrupt Mask +// Uses the same bit definitions as PHY_INT_REG + + + +/*------------------------------------------------------------------------- + . I define some macros to make it easier to do somewhat common + . or slightly complicated, repeated tasks. + --------------------------------------------------------------------------*/ + +/* select a register bank, 0 to 3 */ + +#define SMC_SELECT_BANK(x) { SMC_outw( x, BANK_SELECT ); } + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) {\ + unsigned char mask;\ + SMC_SELECT_BANK(2);\ + mask = SMC_inb( IM_REG );\ + mask |= (x);\ + SMC_outb( mask, IM_REG ); \ +} + +/* this disables an interrupt from the interrupt mask register */ + +#define SMC_DISABLE_INT(x) {\ + unsigned char mask;\ + SMC_SELECT_BANK(2);\ + mask = SMC_inb( IM_REG );\ + mask &= ~(x);\ + SMC_outb( mask, IM_REG ); \ +} + +/*---------------------------------------------------------------------- + . Define the interrupts that I want to receive from the card + . + . I want: + . IM_EPH_INT, for nasty errors + . IM_RCV_INT, for happy received packets + . IM_RX_OVRN_INT, because I have to kick the receiver + . IM_MDINT, for PHY Register 18 Status Changes + --------------------------------------------------------------------------*/ +#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | \ + IM_MDINT) + + +#ifdef CONFIG_SYSCTL + + +/* + * Declarations for the sysctl interface, which allows users the ability to + * control the finer aspects of the LAN91C111 chip. Since the smc + * module currently registers its sysctl table dynamically, the sysctl path + * for module FOO is /proc/sys/dev/ethX/FOO + */ +#define CTL_SMC (CTL_BUS+1389) // arbitrary and hopefully unused + +enum { + CTL_SMC_INFO = 1, // Sysctl files information + CTL_SMC_SWVER, // Driver Software Version Info + CTL_SMC_SWFDUP, // Switched Full Duplex Mode + CTL_SMC_EPHLOOP, // EPH Block Internal Loopback + CTL_SMC_MIIOP, // MII Operation + CTL_SMC_AUTONEG, // Auto-negotiate Mode + CTL_SMC_RFDUPLX, // Request Full Duplex Mode + CTL_SMC_RSPEED, // Request Speed Selection + CTL_SMC_AFDUPLX, // Actual Full Duplex Mode + CTL_SMC_ASPEED, // Actual Speed Selection + CTL_SMC_LNKFAIL, // Link Failed + CTL_SMC_FORCOL, // Force a Collision + CTL_SMC_FILTCAR, // Filter Carrier + CTL_SMC_FREEMEM, // Free Buffer Memory + CTL_SMC_TOTMEM, // Total Buffer Memory + CTL_SMC_LEDA, // Output of LED-A + CTL_SMC_LEDB, // Output of LED-B + CTL_SMC_CHIPREV, // LAN91C111 Chip Revision ID +#ifdef SMC_DEBUG + // Register access for debugging + CTL_SMC_REG_BSR, // Bank Select + CTL_SMC_REG_TCR, // Transmit Control + CTL_SMC_REG_ESR, // EPH Status + CTL_SMC_REG_RCR, // Receive Control + CTL_SMC_REG_CTRR, // Counter + CTL_SMC_REG_MIR, // Memory Information + CTL_SMC_REG_RPCR, // Receive/Phy Control + CTL_SMC_REG_CFGR, // Configuration + CTL_SMC_REG_BAR, // Base Address + CTL_SMC_REG_IAR0, // Individual Address 0 + CTL_SMC_REG_IAR1, // Individual Address 1 + CTL_SMC_REG_IAR2, // Individual Address 2 + CTL_SMC_REG_GPR, // General Purpose + CTL_SMC_REG_CTLR, // Control + CTL_SMC_REG_MCR, // MMU Command + CTL_SMC_REG_PNR, // Packet Number + CTL_SMC_REG_FPR, // FIFO Ports + CTL_SMC_REG_PTR, // Pointer + CTL_SMC_REG_DR, // Data + CTL_SMC_REG_ISR, // Interrupt Status + CTL_SMC_REG_MTR1, // Multicast Table Entry 1 + CTL_SMC_REG_MTR2, // Multicast Table Entry 2 + CTL_SMC_REG_MTR3, // Multicast Table Entry 3 + CTL_SMC_REG_MTR4, // Multicast Table Entry 4 + CTL_SMC_REG_MIIR, // Management Interface + CTL_SMC_REG_REVR, // Revision + CTL_SMC_REG_ERCVR, // Early RCV + CTL_SMC_REG_EXTR, // External + CTL_SMC_PHY_CTRL, // PHY Control + CTL_SMC_PHY_STAT, // PHY Status + CTL_SMC_PHY_ID1, // PHY ID1 + CTL_SMC_PHY_ID2, // PHY ID2 + CTL_SMC_PHY_ADC, // PHY Advertise Capability + CTL_SMC_PHY_REMC, // PHY Advertise Capability + CTL_SMC_PHY_CFG1, // PHY Configuration 1 + CTL_SMC_PHY_CFG2, // PHY Configuration 2 + CTL_SMC_PHY_INT, // PHY Interrupt/Status Output + CTL_SMC_PHY_MASK, // PHY Interrupt/Status Mask +#endif + // --------------------------------------------------- + CTL_SMC_LAST_ENTRY // Add new entries above the line +}; + +#endif // CONFIG_SYSCTL + +#endif /* _SMC_91111_H_ */ + + diff -urN linux-2.4.5-rmk7-np2/drivers/net/smc9194.c linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc9194.c --- linux-2.4.5-rmk7-np2/drivers/net/smc9194.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc9194.c Wed Oct 10 21:06:04 2001 @@ -790,6 +790,15 @@ return smc_probe(dev, base_addr); #endif +#ifdef CONFIG_SA1100_DNP1110 + int base_addr = 0xF6000300; + + // Max recovery timing + MSC1 &= ~0xFFFF; + MSC1 |= 0x8649; + return smc_probe(dev, base_addr); +#endif + #ifdef CONFIG_ISA int i; int base_addr = dev->base_addr; @@ -1034,7 +1043,7 @@ } #if defined(CONFIG_ASSABET_NEPONSET) || defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ - (defined CONFIG_SA1100_PFS168) || defined(CONFIG_SA1100_FLEXANET) + (defined CONFIG_SA1100_PFS168) || defined(CONFIG_SA1100_FLEXANET) || defined(CONFIG_SA1100_DNP1110) /* * Check if MAC address is all zeroes or all ones * (many boards got out uninitialized) diff -urN linux-2.4.5-rmk7-np2/drivers/net/smc9194.h linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc9194.h --- linux-2.4.5-rmk7-np2/drivers/net/smc9194.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/net/smc9194.h Wed Oct 10 21:06:16 2001 @@ -53,7 +53,7 @@ #endif -#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_PFS168) || defined(CONFIG_SA1100_FLEXANET) +#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_PFS168) || defined(CONFIG_SA1100_DNP1110) || defined(CONFIG_SA1100_FLEXANET) #define SMC_USES_16BIT_MEM /* * We can only do 16-bit reads and writes in the static memory space. # # Sound # diff -urN linux-2.4.5-rmk7-np2/drivers/sound/Config.in linux-2.4.5-rmk7-np2-ssv1/drivers/sound/Config.in --- linux-2.4.5-rmk7-np2/drivers/sound/Config.in Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/Config.in Wed Oct 10 18:56:03 2001 @@ -6,16 +6,12 @@ # Prompt user for primary drivers. -dep_tristate ' Assabet audio (UDA1341) support' CONFIG_SOUND_ASSABET_UDA1341 $CONFIG_SA1100_ASSABET $CONFIG_SOUND -dep_tristate ' Compaq iPAQ audio support' CONFIG_SOUND_BITSY_UDA1341 $CONFIG_SA1100_BITSY $CONFIG_SOUND -dep_tristate ' Audio support for SA1111/UDA1341' CONFIG_SOUND_SA1111_UDA1341 $CONFIG_SA1111 $CONFIG_SOUND -dep_tristate ' Generic DAC on the SA11x0 SSP port' CONFIG_SOUND_SA1100SSP $CONFIG_ARCH_SA1100 $CONFIG_SOUND - if [ "$CONFIG_SA1100_ASSABET" = "y" -o "$CONFIG_SA1100_BITSY" = "y" -o \ "$CONFIG_SA1100_PANGOLIN" = "y" -o "$CONFIG_SA1100_FREEBIRD" = "y" -o \ "$CONFIG_SA1100_YOPY" = "y" -o "$CONFIG_SA1100_JORNADA720" = "y" ]; then - dep_tristate ' Old Assabet/Bitsy/Pangolin/Yopy/Freebird/Jornada720 audio support (UDA1341)' CONFIG_SOUND_UDA1341 $CONFIG_SOUND + dep_tristate ' Assabet/Bitsy/Pangolin/Yopy/Freebird/Jornada720 audio support (UDA1341)' CONFIG_SOUND_UDA1341 $CONFIG_SOUND fi +dep_tristate ' SA-1100 SSP sound' CONFIG_SOUND_SA1100_SSP $CONFIG_SOUND dep_tristate ' C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND $CONFIG_PCI if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then diff -urN linux-2.4.5-rmk7-np2/drivers/sound/Makefile linux-2.4.5-rmk7-np2-ssv1/drivers/sound/Makefile --- linux-2.4.5-rmk7-np2/drivers/sound/Makefile Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/Makefile Wed Oct 10 18:56:03 2001 @@ -66,10 +66,7 @@ obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_UDA1341) += sa1100-uda1341.o -obj-$(CONFIG_SOUND_ASSABET_UDA1341) += assabet-uda1341.o uda1341.o sa1100-audio.o -obj-$(CONFIG_SOUND_BITSY_UDA1341) += bitsy-uda1341.o uda1341.o sa1100-audio.o -obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o uda1341.o sa1100-audio.o -obj-$(CONFIG_SOUND_SA1100SSP) += sa1100ssp.o sa1100-audio.o +obj-$(CONFIG_SOUND_SA1100_SSP) += sa1100_ssp.o subdir-$(CONFIG_SOUND_EMU10K1) += emu10k1 subdir-$(CONFIG_SOUND_CS4281) += cs4281 diff -urN linux-2.4.5-rmk7-np2/drivers/sound/assabet-uda1341.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/assabet-uda1341.c --- linux-2.4.5-rmk7-np2/drivers/sound/assabet-uda1341.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/assabet-uda1341.c Thu Jan 1 01:00:00 1970 @@ -1,466 +0,0 @@ -/* - * Glue audio driver for the SA1110 Assabet board & Philips UDA1341 codec. - * - * Copyright (c) 2000 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * This is the machine specific part of the Assabet/UDA1341 support. - * This driver makes use of the UDA1341 and the sa1100-audio modules. - * - * History: - * - * 2000-05-21 Nicolas Pitre Initial release. - * - * 2001-06-03 Nicolas Pitre Made this file a separate module, based on - * the former sa1100-uda1341.c driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sa1100-audio.h" -#include "uda1341.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -#define AUDIO_NAME "Assabet_UDA1341" - -#define AUDIO_FMT_MASK (AFMT_S16_LE) -#define AUDIO_FMT_DEFAULT (AFMT_S16_LE) -#define AUDIO_CHANNELS_DEFAULT 2 -#define AUDIO_RATE_DEFAULT 44100 - - -/* - * GPIO based L3 bus support. - * - * This provides control of Philips L3 type devices. - * GPIO lines are used for clock, data and mode pins. - * - * Note: On Assabet the L3 pins are shared with I2C devices. This should not - * present any problems as long as an I2C start sequence is not generated. - * This is defined as a 1->0 transition on the data lines when the clock is - * high. It is critical this code only allow data transitions when the clock - * is low. This is always legal in L3. - * - * The IIC interface requires the clock and data pin to be LOW when idle. We - * must make sure we leave them in this state. - * - * It appears the read data is generated on the falling edge of the clock - * and should be held stable during the clock high time. - */ - -/* - * L3 bus GPIO pin definitions - */ - -#define L3_DataPin GPIO_GPIO(15) -#define L3_ClockPin GPIO_GPIO(18) -#define L3_ModePin GPIO_GPIO(17) - -/* - * L3 setup and hold times (expressed in us) - */ -#define L3_DataSetupTime 1 /* 190 ns */ -#define L3_DataHoldTime 1 /* 30 ns */ -#define L3_ModeSetupTime 1 /* 190 ns */ -#define L3_ModeHoldTime 1 /* 190 ns */ -#define L3_ClockHighTime 1 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ -#define L3_ClockLowTime 1 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ -#define L3_HaltTime 1 /* 190 ns */ - -/* - * Grab control of the IIC/L3 shared pins - */ -static inline void L3_acquirepins(void) -{ - GPSR = (L3_ModePin | L3_ClockPin | L3_DataPin); - GPDR |= (L3_ModePin | L3_ClockPin | L3_DataPin); -} - -/* - * Release control of the IIC/L3 shared pins - */ -static inline void L3_releasepins(void) -{ - GPDR &= ~(L3_ModePin | L3_ClockPin | L3_DataPin); -} - -/* - * Initialize the interface - */ -static void L3_init(void) -{ - GAFR &= ~(L3_DataPin | L3_ClockPin | L3_ModePin); - L3_releasepins(); -} - -/* - * Get a bit. The clock is high on entry and on exit. Data is read after - * the clock low time has expired. - */ -static inline int L3_getbit(void) -{ - int data; - - GPCR = L3_ClockPin; - udelay(L3_ClockLowTime); - - data = (GPLR & L3_DataPin) ? 1 : 0; - - GPSR = L3_ClockPin; - udelay(L3_ClockHighTime); - - return data; -} - -/* - * Send a bit. The clock is high on entry and on exit. Data is sent only - * when the clock is low (I2C compatibility). - */ -static inline void L3_sendbit(int bit) -{ - GPCR = L3_ClockPin; - - if (bit & 1) - GPSR = L3_DataPin; - else - GPCR = L3_DataPin; - - /* Assumes L3_DataSetupTime < L3_ClockLowTime */ - udelay(L3_ClockLowTime); - - GPSR = L3_ClockPin; - udelay(L3_ClockHighTime); -} - -/* - * Send a byte. The mode line is set or pulsed based on the mode sequence - * count. The mode line is high on entry and exit. The mod line is pulsed - * before the second data byte and before ech byte thereafter. - */ -static void L3_sendbyte(char data, int mode) -{ - int i; - - switch (mode) { - case 0: /* Address mode */ - GPCR = L3_ModePin; - break; - case 1: /* First data byte */ - break; - default: /* Subsequent bytes */ - GPCR = L3_ModePin; - udelay(L3_HaltTime); - GPSR = L3_ModePin; - break; - } - - udelay(L3_ModeSetupTime); - - for (i = 0; i < 8; i++) - L3_sendbit(data >> i); - - if (mode == 0) /* Address mode */ - GPSR = L3_ModePin; - - udelay(L3_ModeHoldTime); -} - -/* - * Get a byte. The mode line is set or pulsed based on the mode sequence - * count. The mode line is high on entry and exit. The mod line is pulsed - * before the second data byte and before each byte thereafter. This - * function is never valid with mode == 0 (address cycle) as the address - * is always sent on the bus, not read. - * L3_DataPin must be set to an input before calling this function! - */ -static char L3_getbyte(int mode) -{ - char data = 0; - int i; - - switch (mode) { - case 0: /* Address mode - never valid */ - break; - case 1: /* First data byte */ - break; - default: /* Subsequent bytes */ - GPCR = L3_ModePin; - udelay(L3_HaltTime); - GPSR = L3_ModePin; - break; - } - - udelay(L3_ModeSetupTime); - - for (i = 0; i < 8; i++) - data |= (L3_getbit() << i); - - udelay(L3_ModeHoldTime); - - return data; -} - -/* - * Write data to a device on the L3 bus. The address is passed as well as - * the data and length. The length written is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_write(char addr, char *data, int len) -{ - int bytes = len; - int mode = 0; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - L3_acquirepins(); - L3_sendbyte(addr, mode++); - while(len--) - L3_sendbyte(*data++, mode++); - L3_releasepins(); - - return bytes; -} - -/* - * Read data from a device on the L3 bus. The address is passed as well as - * the data and length. The length read is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_read(char addr, char *data, int len) -{ - int bytes = len; - int mode = 0; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - L3_acquirepins(); - L3_sendbyte(addr, mode++); - GPDR &= ~(L3_DataPin); - while(len--) - *data++ = L3_getbyte(mode++); - L3_releasepins(); - - return bytes; -} - - -/* - * Mixer (UDA1341) interface - */ - -static UDA1341_regs_t UDA1341_regs = UDA1341_REGS_DFLT; - -static UDA1341_state_t uda1341_state = { - regs: &UDA1341_regs, - L3_write: L3_write, - L3_read: L3_read, -}; - -static int mixer_ioctl (struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); -} - -static struct file_operations assabet_mixer_fops = { - ioctl: mixer_ioctl, - owner: THIS_MODULE -}; - - -/* - * Audio interface - */ - -static void assabet_audio_init(void) -{ - /* Setup the uarts */ - GAFR |= (GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | - GPIO_SSP_SFRM | GPIO_SSP_CLK); - GPDR |= (GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); - GPDR &= ~(GPIO_SSP_RXD | GPIO_SSP_CLK); - PPAR |= PPAR_SPR; - Ser4SSCR0 = SSCR0_SSE + SSCR0_DataSize(16) + SSCR0_TI; - Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; - - L3_init(); - - /* Enable the audio power */ - BCR_clear(BCR_STEREO_LB | BCR_QMUTE | BCR_SPK_OFF); - BCR_set(BCR_CODEC_RST | BCR_AUDIO_ON); - - /* - * The assabet board uses the SDRAM clock as the source clock for - * audio. This is supplied to the SA11x0 from the CPLD on pin 19. - * At 206Mhz we need to run the audio clock (SDRAM bank 2) - * at half speed. This clock will scale with core frequency so - * the audio sample rate will also scale. The CPLD on Assabet - * will need to be programmed to match the core frequency. - */ - MDREFR |= (MDREFR_K2DB2 | MDREFR_K2RUN); - /* Make sure EAPD and KAPD are clear to run the clocks at all times. */ - MDREFR &= ~(MDREFR_EAPD | MDREFR_KAPD); - - /* Wait for the UDA1341 to wake up */ - mdelay(1); - - /* initialize the UDA1341 internal state */ - uda1341_state.active = 1; - uda1341_reset(&uda1341_state); -} - -static void assabet_audio_shutdown(void) -{ - uda1341_state.active = 0; - /* disable the audio power */ - BCR_set(BCR_STEREO_LB | BCR_QMUTE | BCR_SPK_OFF); - BCR_clear(BCR_AUDIO_ON); - /* - * We can't clear BCR_CODEC_RST without knowing if - * the UCB1300 driver is still active... A global - * count would be required for this. - */ -} - -static int assabet_audio_ioctl( struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - long val; - int ret = 0; - - /* - * These are platform dependent ioctls which are not handled by the - * generic sa1100-audio module. - */ - switch (cmd) { - case SNDCTL_DSP_SETFMT: - ret = get_user(val, (long *) arg); - if (ret) break; - if (val & AUDIO_FMT_MASK) { - break; - } else - return -EINVAL; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - ret = get_user(val, (long *) arg); - if (ret) break; - if (cmd == SNDCTL_DSP_STEREO) - val = val ? 2 : 1; - /* the UDA1341 is stereo only */ - if (val != 2) - return -EINVAL; - break; - - case SOUND_PCM_READ_CHANNELS: - return put_user(2, (long *) arg); - - case SNDCTL_DSP_SPEED: - /* - * FIXME: we need to modify the clock rate for DRAM bank 2 - * (our clock source) accordingly. - */ - val = 44100; - return put_user(44100, (long *) arg); - - case SOUND_PCM_READ_RATE: - return put_user(44100, (long *) arg); - - case SNDCTL_DSP_GETFMTS: - return put_user(AUDIO_FMT_MASK, (long *) arg); - - default: - /* Maybe this is meant for the mixer (As per OSS Docs) */ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); - } - - return ret; -} - -static audio_stream_t output_stream, input_stream; - -static audio_state_t audio_state = { - output_stream: &output_stream, - input_stream: &input_stream, - need_tx_for_rx: 1, - hw_init: assabet_audio_init, - hw_shutdown: assabet_audio_shutdown, - client_ioctl: assabet_audio_ioctl, -}; - -static int assabet_audio_open(struct inode *inode, struct file *file) -{ - return sa1100_audio_instance(inode, file, &audio_state); -} - -/* - * Missing fields of this structure will be patched with the call - * to sa1100_audio_instance() - */ -static struct file_operations assabet_audio_fops = { - open: assabet_audio_open, - owner: THIS_MODULE -}; - - -static int audio_dev_id, mixer_dev_id; - -static int __init assabet_uda1341_init(void) -{ - if (!machine_is_assabet()) - return -ENODEV; - - /* Acquire and initialize DMA */ - if (sa1100_request_dma(&output_stream.dma_ch, "UDA1341 out") < 0 || - sa1100_request_dma(&input_stream.dma_ch, "UDA1341 in") < 0) { - sa1100_free_dma(output_stream.dma_ch); - printk( KERN_ERR AUDIO_NAME ": unable to get DMA channels\n" ); - return -EBUSY; - } - sa1100_dma_set_device(output_stream.dma_ch, DMA_Ser4SSPWr); - sa1100_dma_set_device(input_stream.dma_ch, DMA_Ser4SSPRd); - - /* register devices */ - audio_dev_id = register_sound_dsp(&assabet_audio_fops, -1); - mixer_dev_id = register_sound_mixer(&assabet_mixer_fops, -1); - - printk( KERN_INFO AUDIO_NAME " initialized\n" ); - return 0; -} - -module_init(assabet_uda1341_init); - - -static void __exit assabet_uda1341_exit(void) -{ - unregister_sound_dsp(audio_dev_id); - unregister_sound_mixer(mixer_dev_id); - sa1100_free_dma(output_stream.dma_ch); - sa1100_free_dma(input_stream.dma_ch); -} - -module_exit(assabet_uda1341_exit); diff -urN linux-2.4.5-rmk7-np2/drivers/sound/bitsy-uda1341.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/bitsy-uda1341.c --- linux-2.4.5-rmk7-np2/drivers/sound/bitsy-uda1341.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/bitsy-uda1341.c Thu Jan 1 01:00:00 1970 @@ -1,511 +0,0 @@ -/* - * Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec. - * - * Copyright (c) 2000 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * This is the machine specific part of the Compaq iPAQ (aka Bitsy) support. - * This driver makes use of the UDA1341 and the sa1100-audio modules. - * - * History: - * - * 2000-05-21 Nicolas Pitre Initial UDA1341 driver release. - * - * 2000-07-?? George France Bitsy support. - * - * 2000-12-13 Deborah Wallach Fixed power handling for iPAQ/bitsy - * - * 2001-06-03 Nicolas Pitre Made this file a separate module, based on - * the former sa1100-uda1341.c driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sa1100-audio.h" -#include "uda1341.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -#define AUDIO_NAME "Bitsy_UDA1341" - -#define AUDIO_FMT_MASK (AFMT_S16_LE) -#define AUDIO_FMT_DEFAULT (AFMT_S16_LE) -#define AUDIO_CHANNELS_DEFAULT 2 -#define AUDIO_RATE_DEFAULT 44100 - - -/* - * GPIO based L3 bus support. - * - * This provides control of Philips L3 type devices. - * GPIO lines are used for clock, data and mode pins. - * It appears the read data is generated on the falling edge of the clock - * and should be held stable during the clock high time. - */ - -/* - * L3 bus GPIO pin definitions - */ - -#define L3_DataPin GPIO_BITSY_L3_DATA -#define L3_ClockPin GPIO_BITSY_L3_CLOCK -#define L3_ModePin GPIO_BITSY_L3_MODE - -/* - * L3 setup and hold times (expressed in us) - */ -#define L3_DataSetupTime 1 /* 190 ns */ -#define L3_DataHoldTime 1 /* 30 ns */ -#define L3_ModeSetupTime 1 /* 190 ns */ -#define L3_ModeHoldTime 1 /* 190 ns */ -#define L3_ClockHighTime 1 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ -#define L3_ClockLowTime 1 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ -#define L3_HaltTime 1 /* 190 ns */ - -/* - * Grab control of the IIC/L3 shared pins - */ -static inline void L3_acquirepins(void) -{ - GPSR = (L3_ModePin | L3_ClockPin | L3_DataPin); - GPDR |= (L3_ModePin | L3_ClockPin | L3_DataPin); -} - -/* - * Release control of the IIC/L3 shared pins - */ -static inline void L3_releasepins(void) -{ - GPDR &= ~(L3_ModePin | L3_ClockPin | L3_DataPin); -} - -/* - * Initialize the interface - */ -static void L3_init(void) -{ - GAFR &= ~(L3_DataPin | L3_ClockPin | L3_ModePin); - L3_releasepins(); -} - -/* - * Get a bit. The clock is high on entry and on exit. Data is read after - * the clock low time has expired. - */ -static inline int L3_getbit(void) -{ - int data; - - GPCR = L3_ClockPin; - udelay(L3_ClockLowTime); - - data = (GPLR & L3_DataPin) ? 1 : 0; - - GPSR = L3_ClockPin; - udelay(L3_ClockHighTime); - - return data; -} - -/* - * Send a bit. The clock is high on entry and on exit. Data is sent only - * when the clock is low (I2C compatibility). - */ -static inline void L3_sendbit(int bit) -{ - GPCR = L3_ClockPin; - - if (bit & 1) - GPSR = L3_DataPin; - else - GPCR = L3_DataPin; - - /* Assumes L3_DataSetupTime < L3_ClockLowTime */ - udelay(L3_ClockLowTime); - - GPSR = L3_ClockPin; - udelay(L3_ClockHighTime); -} - -/* - * Send a byte. The mode line is set or pulsed based on the mode sequence - * count. The mode line is high on entry and exit. The mod line is pulsed - * before the second data byte and before ech byte thereafter. - */ -static void L3_sendbyte(char data, int mode) -{ - int i; - - switch (mode) { - case 0: /* Address mode */ - GPCR = L3_ModePin; - break; - case 1: /* First data byte */ - break; - default: /* Subsequent bytes */ - GPCR = L3_ModePin; - udelay(L3_HaltTime); - GPSR = L3_ModePin; - break; - } - - udelay(L3_ModeSetupTime); - - for (i = 0; i < 8; i++) - L3_sendbit(data >> i); - - if (mode == 0) /* Address mode */ - GPSR = L3_ModePin; - - udelay(L3_ModeHoldTime); -} - -/* - * Get a byte. The mode line is set or pulsed based on the mode sequence - * count. The mode line is high on entry and exit. The mod line is pulsed - * before the second data byte and before each byte thereafter. This - * function is never valid with mode == 0 (address cycle) as the address - * is always sent on the bus, not read. - * L3_DataPin must be set to an input before calling this function! - */ -static char L3_getbyte(int mode) -{ - char data = 0; - int i; - - switch (mode) { - case 0: /* Address mode - never valid */ - break; - case 1: /* First data byte */ - break; - default: /* Subsequent bytes */ - GPCR = L3_ModePin; - udelay(L3_HaltTime); - GPSR = L3_ModePin; - break; - } - - udelay(L3_ModeSetupTime); - - for (i = 0; i < 8; i++) - data |= (L3_getbit() << i); - - udelay(L3_ModeHoldTime); - - return data; -} - -/* - * Write data to a device on the L3 bus. The address is passed as well as - * the data and length. The length written is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_write(char addr, char *data, int len) -{ - int bytes = len; - int mode = 0; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - L3_acquirepins(); - L3_sendbyte(addr, mode++); - while(len--) - L3_sendbyte(*data++, mode++); - L3_releasepins(); - - return bytes; -} - -/* - * Read data from a device on the L3 bus. The address is passed as well as - * the data and length. The length read is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_read(char addr, char *data, int len) -{ - int bytes = len; - int mode = 0; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - L3_acquirepins(); - L3_sendbyte(addr, mode++); - GPDR &= ~(L3_DataPin); - while(len--) - *data++ = L3_getbyte(mode++); - L3_releasepins(); - - return bytes; -} - - -/* - * Mixer (UDA1341) interface - */ - -static UDA1341_regs_t UDA1341_regs = UDA1341_REGS_DFLT; - -static UDA1341_state_t uda1341_state = { - regs: &UDA1341_regs, - L3_write: L3_write, - L3_read: L3_read, -}; - -static int mixer_ioctl (struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); -} - -static struct file_operations bitsy_mixer_fops = { - ioctl: mixer_ioctl, - owner: THIS_MODULE -}; - - -/* - * Audio interface - */ - -static long audio_samplerate = AUDIO_RATE_DEFAULT; - -static void bitsy_set_samplerate(long val) -{ - if (val >= 48000) - val = 48000; - else if (val >= 44100) - val = 44100; - else if (val >= 32000) - val = 32000; - else if (val >= 22050) - val = 22050; - else if (val >= 16000) - val = 16000; - else if (val >= 11025) - val = 11025; - else - val = 8000; - - /* set the external clock generator */ - switch (val) { - case 32000: - case 48000: - /* 00: 12.288 MHz */ - GPCR = GPIO_BITSY_CLK_SET0 | GPIO_BITSY_CLK_SET1; - break; - case 44100: - case 22050: - /* 01: 11.2896 MHz */ - GPSR = GPIO_BITSY_CLK_SET0; - GPCR = GPIO_BITSY_CLK_SET1; - break; - case 8000: - case 16000: - /* 10: 4.096 MHz */ - GPCR = GPIO_BITSY_CLK_SET0; - GPSR = GPIO_BITSY_CLK_SET1; - break; - case 11025: - /* 11: 5.6245 MHz */ - GPSR = GPIO_BITSY_CLK_SET0 | GPIO_BITSY_CLK_SET1; - break; - } - switch (val) { - case 8000: - case 11025: - case 22050: - UDA1341_regs.status_0.system_clk = UDA_STATUS0_SC_512FS; - break; - case 16000: - case 44100: - case 48000: - UDA1341_regs.status_0.system_clk = UDA_STATUS0_SC_256FS; - break; - case 32000: - UDA1341_regs.status_0.system_clk = UDA_STATUS0_SC_384FS; - break; - } - L3_write((UDA1341_L3Addr << 2) | UDA1341_STATUS, - (char *)&UDA1341_regs.status_0, 1); - audio_samplerate = val; -} - -static void bitsy_audio_init(void) -{ - /* Setup the uarts */ - GAFR &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); - GAFR |= (GPIO_SSP_CLK); - GPDR &= ~(GPIO_SSP_CLK); - Ser4SSCR0 = 0; - Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI; - Ser4SSCR0 |= SSCR0_SerClkDiv(8); - Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk; - Ser4SSCR0 |= SSCR0_SSE; - - /* Setup L3 bus */ - L3_init(); - - /* Enable the audio power */ - set_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET | EGPIO_BITSY_AUD_AMP_ON | - EGPIO_BITSY_AUD_PWR_ON); - clr_bitsy_egpio(EGPIO_BITSY_QMUTE); - - /* external clock configuration */ - GPDR |= (GPIO_BITSY_CLK_SET0 | GPIO_BITSY_CLK_SET1); - bitsy_set_samplerate(audio_samplerate); - - /* Wait for the UDA1341 to wake up */ - mdelay(1); - - /* Initialize the UDA1341 internal state */ - uda1341_state.active = 1; - uda1341_reset(&uda1341_state); -} - -static void bitsy_audio_shutdown(void) -{ - uda1341_state.active = 0; - /* disable the audio power and all signals leading to the audio chip */ - clr_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET | EGPIO_BITSY_AUD_AMP_ON | - EGPIO_BITSY_AUD_PWR_ON | EGPIO_BITSY_QMUTE); -} - -static int bitsy_audio_ioctl(struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - long val; - int ret = 0; - - /* - * These are platform dependent ioctls which are not handled by the - * generic sa1100-audio module. - */ - switch (cmd) { - case SNDCTL_DSP_SETFMT: - ret = get_user(val, (long *) arg); - if (ret) break; - if (val & AUDIO_FMT_MASK) { - break; - } else - return -EINVAL; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - ret = get_user(val, (long *) arg); - if (ret) break; - if (cmd == SNDCTL_DSP_STEREO) - val = val ? 2 : 1; - /* the UDA1341 is stereo only */ - if (val != 2) - return -EINVAL; - break; - - case SOUND_PCM_READ_CHANNELS: - return put_user(2, (long *) arg); - - case SNDCTL_DSP_SPEED: - ret = get_user(val, (long *) arg); - if (ret) break; - bitsy_set_samplerate(val); - /* fall through */ - - case SOUND_PCM_READ_RATE: - return put_user(audio_samplerate, (long *) arg); - - case SNDCTL_DSP_GETFMTS: - return put_user(AUDIO_FMT_MASK, (long *) arg); - - default: - /* Maybe this is meant for the mixer (As per OSS Docs) */ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); - } - - return ret; -} - -static audio_stream_t output_stream, input_stream; - -static audio_state_t audio_state = { - output_stream: &output_stream, - input_stream: &input_stream, - need_tx_for_rx: 1, - hw_init: bitsy_audio_init, - hw_shutdown: bitsy_audio_shutdown, - client_ioctl: bitsy_audio_ioctl, -}; - -static int bitsy_audio_open(struct inode *inode, struct file *file) -{ - return sa1100_audio_instance(inode, file, &audio_state); -} - -/* - * Missing fields of this structure will be patched with the call - * to sa1100_audio_instance() - */ -static struct file_operations bitsy_audio_fops = { - open: bitsy_audio_open, - owner: THIS_MODULE -}; - - -static int audio_dev_id, mixer_dev_id; - -static int __init bitsy_uda1341_init(void) -{ - if (!machine_is_bitsy()) - return -ENODEV; - - /* Acquire and initialize DMA */ - if (sa1100_request_dma(&output_stream.dma_ch, "UDA1341 out") < 0 || - sa1100_request_dma(&input_stream.dma_ch, "UDA1341 in") < 0) { - sa1100_free_dma(output_stream.dma_ch); - printk( KERN_ERR AUDIO_NAME ": unable to get DMA channels\n" ); - return -EBUSY; - } - sa1100_dma_set_device(output_stream.dma_ch, DMA_Ser4SSPWr); - sa1100_dma_set_device(input_stream.dma_ch, DMA_Ser4SSPRd); - - /* register devices */ - audio_dev_id = register_sound_dsp(&bitsy_audio_fops, -1); - mixer_dev_id = register_sound_mixer(&bitsy_mixer_fops, -1); - - printk( KERN_INFO AUDIO_NAME " initialized\n" ); - return 0; -} - -module_init(bitsy_uda1341_init); - - -static void __exit bitsy_uda1341_exit(void) -{ - unregister_sound_dsp(audio_dev_id); - unregister_sound_mixer(mixer_dev_id); - sa1100_free_dma(output_stream.dma_ch); - sa1100_free_dma(input_stream.dma_ch); -} - -module_exit(bitsy_uda1341_exit); diff -urN linux-2.4.5-rmk7-np2/drivers/sound/sa1100-audio.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100-audio.c --- linux-2.4.5-rmk7-np2/drivers/sound/sa1100-audio.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100-audio.c Thu Jan 1 01:00:00 1970 @@ -1,729 +0,0 @@ -/* - * Common audio handling for the SA11x0 processor - * - * Copyright (c) 2000 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * - * This module handles the generic buffering/DMA/mmap audio interface for - * codecs connected to the SA1100 chip. All features depending on specific - * hardware implementations like supported audio formats or samplerates are - * relegated to separate specific modules. - * - * - * History: - * - * 2000-05-21 Nicolas Pitre Initial release. - * - * 2000-06-10 Erik Bunce Add initial poll support. - * - * 2000-08-22 Nicolas Pitre Removed all DMA stuff. Now using the - * generic SA1100 DMA interface. - * - * 2000-11-30 Nicolas Pitre - Validation of opened instances; - * - Power handling at open/release time instead - * of driver load/unload; - * - * 2001-06-03 Nicolas Pitre Made this file a separate module, based on - * the former sa1100-uda1341.c driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sa1100-audio.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -#define AUDIO_NAME "sa1100-audio" -#define AUDIO_NBFRAGS_DEFAULT 8 -#define AUDIO_FRAGSIZE_DEFAULT 8192 - -#define NEXT_BUF(_s_,_b_) { \ - (_s_)->_b_##_idx++; \ - (_s_)->_b_##_idx %= (_s_)->nbfrags; \ - (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; } - -#define AUDIO_ACTIVE(state) ((state)->rd_refcount || (state)->wr_refcount) - -/* - * This function frees all buffers - */ - -static void audio_clear_buf(audio_stream_t * s) -{ - DPRINTK("audio_clear_buf\n"); - - /* ensure DMA won't run anymore */ - sa1100_dma_flush_all(s->dma_ch); - - if (s->buffers) { - int frag; - for (frag = 0; frag < s->nbfrags; frag++) { - if (!s->buffers[frag].master) - continue; - consistent_free(s->buffers[frag].start, - s->buffers[frag].master, - s->buffers[frag].dma_addr); - } - kfree(s->buffers); - s->buffers = NULL; - } - - s->buf_idx = 0; - s->buf = NULL; -} - - -/* - * This function allocates the buffer structure array and buffer data space - * according to the current number of fragments and fragment size. - */ - -static int audio_setup_buf(audio_stream_t * s) -{ - int frag; - int dmasize = 0; - char *dmabuf = NULL; - dma_addr_t dmaphys = 0; - - if (s->buffers) - return -EBUSY; - - s->buffers = (audio_buf_t *) - kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); - if (!s->buffers) - goto err; - memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags); - - for (frag = 0; frag < s->nbfrags; frag++) { - audio_buf_t *b = &s->buffers[frag]; - - /* - * Let's allocate non-cached memory for DMA buffers. - * We try to allocate all memory at once. - * If this fails (a common reason is memory fragmentation), - * then we allocate more smaller buffers. - */ - if (!dmasize) { - dmasize = (s->nbfrags - frag) * s->fragsize; - do { - dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, - dmasize, - &dmaphys); - if (!dmabuf) - dmasize -= s->fragsize; - } while (!dmabuf && dmasize); - if (!dmabuf) - goto err; - b->master = dmasize; - } - - b->start = dmabuf; - b->dma_addr = dmaphys; - sema_init(&b->sem, 1); - DPRINTK("buf %d: start %p dma %p\n", frag, b->start, - b->dma_addr); - - dmabuf += s->fragsize; - dmaphys += s->fragsize; - dmasize -= s->fragsize; - } - - s->buf_idx = 0; - s->buf = &s->buffers[0]; - - return 0; - -err: - printk(AUDIO_NAME ": unable to allocate audio memory\n "); - audio_clear_buf(s); - return -ENOMEM; -} - - -/* - * DMA callback functions - */ - -static void audio_dmaout_done_callback(void *buf_id, int size) -{ - audio_buf_t *b = (audio_buf_t *) buf_id; - /* - * Current buffer is sent: wake up any process waiting for it. - */ - up(&b->sem); - /* And any process polling on write. */ - wake_up(&b->sem.wait); -} - -static void audio_dmain_done_callback(void *buf_id, int size) -{ - audio_buf_t *b = (audio_buf_t *) buf_id; - /* - * Current buffer is full: set its size and wake up any - * process waiting for it. - */ - b->size = size; - up(&b->sem); - /* And any process polling on read. */ - wake_up(&b->sem.wait); -} - - -static int audio_sync(struct file *file) -{ - audio_state_t *state = (audio_state_t *)file->private_data; - audio_stream_t *s = state->output_stream; - audio_buf_t *b = s->buf; - - DPRINTK("audio_sync\n"); - - if (!s->buffers) - return 0; - - /* Send half-full buffers */ - if (b->size != 0) { - down(&b->sem); - sa1100_dma_queue_buffer(s->dma_ch, (void *) b, - b->dma_addr, b->size); - b->size = 0; - NEXT_BUF(s, buf); - } - - /* - * Let's wait for the last buffer we sent i.e. the one before the - * current buf_idx. When we acquire the semaphore, this means either: - * - DMA on the buffer completed or - * - the buffer was already free thus nothing else to sync. - */ - b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags); - if (down_interruptible(&b->sem)) - return -EINTR; - up(&b->sem); - return 0; -} - - -static int audio_write(struct file *file, const char *buffer, - size_t count, loff_t * ppos) -{ - const char *buffer0 = buffer; - audio_state_t *state = (audio_state_t *)file->private_data; - audio_stream_t *s = state->output_stream; - int chunksize, ret = 0; - - DPRINTK("audio_write: count=%d\n", count); - - switch (file->f_flags & O_ACCMODE) { - case O_WRONLY: - case O_RDWR: - break; - default: - return -EPERM; - } - - if (!s->buffers && audio_setup_buf(s)) - return -ENOMEM; - - /* be sure to have a full sample byte count */ - count &= ~0x03; - - while (count > 0) { - audio_buf_t *b = s->buf; - - /* Wait for a buffer to become free */ - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - if (down_trylock(&b->sem)) - break; - } else { - ret = -ERESTARTSYS; - if (down_interruptible(&b->sem)) - break; - } - - /* Feed the current buffer */ - chunksize = s->fragsize - b->size; - if (chunksize > count) - chunksize = count; - DPRINTK("write %d to %d\n", chunksize, s->buf_idx); - if (copy_from_user(b->start + b->size, buffer, chunksize)) { - up(&b->sem); - return -EFAULT; - } - b->size += chunksize; - buffer += chunksize; - count -= chunksize; - if (b->size < s->fragsize) { - up(&b->sem); - break; - } - - /* Send current buffer to dma */ - sa1100_dma_queue_buffer(s->dma_ch, (void *) b, - b->dma_addr, b->size); - b->size = 0; /* indicate that the buffer has been sent */ - NEXT_BUF(s, buf); - } - - if ((buffer - buffer0)) - ret = buffer - buffer0; - DPRINTK("audio_write: return=%d\n", ret); - return ret; -} - - -static int audio_recording(audio_state_t *state) -{ - audio_stream_t *s = state->input_stream; - int i; - - if (!s->buffers) { - if (audio_setup_buf(s)) - return -ENOMEM; - - /* - * With some chips like the UDA1341 we must ensure there is - * an output stream at any time while recording since this is - * how the UDA1341 gets its clock from the SA1100. - * So while there is no playback data to send, the output DMA - * will spin with all zeroes. We use the cache flush special - * area for that. - */ - if (state->need_tx_for_rx) - sa1100_dma_set_spin(state->output_stream->dma_ch, - (dma_addr_t)FLUSH_BASE_PHYS, 2048); - - /* - * Since we just allocated all buffers, we must send them to - * the DMA code before receiving data. - */ - for (i = 0; i < s->nbfrags; i++) { - audio_buf_t *b = s->buf; - down(&b->sem); - sa1100_dma_queue_buffer(s->dma_ch, (void *) b, - b->dma_addr, s->fragsize); - NEXT_BUF(s, buf); - } - } - return 0; -} - - -static int audio_read(struct file *file, char *buffer, - size_t count, loff_t * ppos) -{ - char *buffer0 = buffer; - audio_state_t *state = (audio_state_t *)file->private_data; - audio_stream_t *s = state->input_stream; - int chunksize, ret = 0; - - DPRINTK("audio_read: count=%d\n", count); - - switch (file->f_flags & O_ACCMODE) { - case O_RDONLY: - case O_RDWR: - break; - default: - return -EPERM; - } - - ret = audio_recording(state); - if (ret) - return ret; - - /* be sure to have a full sample byte count */ - count &= ~0x03; - - while (count > 0) { - audio_buf_t *b = s->buf; - - /* Wait for a buffer to become full */ - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - if (down_trylock(&b->sem)) - break; - } else { - ret = -ERESTARTSYS; - if (down_interruptible(&b->sem)) - break; - } - - /* Grab data from the current buffer */ - chunksize = b->size; - if (chunksize > count) - chunksize = count; - DPRINTK("read %d from %d\n", chunksize, s->buf_idx); - if (copy_to_user(buffer, - b->start + s->fragsize - b->size, - chunksize)) { - up(&b->sem); - return -EFAULT; - } - b->size -= chunksize; - buffer += chunksize; - count -= chunksize; - if (b->size > 0) { - up(&b->sem); - break; - } - - /* Make current buffer available for DMA again */ - sa1100_dma_queue_buffer(s->dma_ch, (void *) b, - b->dma_addr, s->fragsize); - NEXT_BUF(s, buf); - } - - if ((buffer - buffer0)) - ret = buffer - buffer0; - DPRINTK("audio_read: return=%d\n", ret); - return ret; -} - - -static unsigned int audio_poll(struct file *file, - struct poll_table_struct *wait) -{ - audio_state_t *state = (audio_state_t *)file->private_data; - audio_stream_t *is = state->input_stream; - audio_stream_t *os = state->output_stream; - unsigned int mask = 0; - int i; - int ret; - - DPRINTK("audio_poll(): mode=%s%s\n", - (file->f_mode & FMODE_READ) ? "r" : "", - (file->f_mode & FMODE_WRITE) ? "w" : ""); - - if (file->f_mode & FMODE_READ) { - /* Start audio input if not already active */ - ret = audio_recording(state); - if (ret < 0) - return ret; - poll_wait(file, &is->buf->sem.wait, wait); - } - - if (file->f_mode & FMODE_WRITE) { - if (!os->buffers && audio_setup_buf(os)) - return -ENOMEM; - poll_wait(file, &os->buf->sem.wait, wait); - } - - if (file->f_mode & FMODE_READ) { - for (i = 0; i < is->nbfrags; i++) { - if (atomic_read(&is->buffers[i].sem.count) > 0) { - mask |= POLLIN | POLLRDNORM; - break; - } - } - } - if (file->f_mode & FMODE_WRITE) { - for (i = 0; i < os->nbfrags; i++) { - if (atomic_read(&os->buffers[i].sem.count) > 0) { - mask |= POLLOUT | POLLWRNORM; - break; - } - } - } - - DPRINTK("audio_poll() returned mask of %s%s\n", - (mask & POLLIN) ? "r" : "", - (mask & POLLOUT) ? "w" : ""); - - return mask; -} - - -static loff_t audio_llseek(struct file *file, loff_t offset, int origin) -{ - return -ESPIPE; -} - - -static int audio_set_fragments(audio_stream_t *s, int val) -{ - if (s->buffers) - return -EBUSY; - s->fragsize = 1 << (val & 0xFFFF); - if (s->fragsize < 16) - s->fragsize = 16; - if (s->fragsize > 16384) - s->fragsize = 16384; - s->nbfrags = (val >> 16) & 0x7FFF; - if (s->nbfrags < 2) - s->nbfrags = 2; - if (s->nbfrags * s->fragsize > 128 * 1024) - s->nbfrags = 128 * 1024 / s->fragsize; - return audio_setup_buf(s); -} - -static int audio_ioctl(struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - audio_state_t *state = (audio_state_t *)file->private_data; - audio_stream_t *os = state->output_stream; - audio_stream_t *is = state->input_stream; - long val; - - /* dispatch based on command */ - switch (cmd) { - case SNDCTL_DSP_GETBLKSIZE: - return put_user(os->fragsize, (long *) arg); - break; - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, (long *) arg)) - return -EFAULT; - return audio_set_fragments(os, val); - break; - - case SNDCTL_DSP_SYNC: - return audio_sync(file); - - case SNDCTL_DSP_GETOSPACE: - { - audio_buf_info *inf = (audio_buf_info *) arg; - int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf)); - int i; - int frags = 0, bytes = 0; - - if (err) - return err; - for (i = 0; i < os->nbfrags; i++) { - if (atomic_read(&os->buffers[i].sem.count) > 0) { - if (os->buffers[i].size == 0) frags++; - bytes += os->fragsize - os->buffers[i].size; - } - } - put_user(frags, &inf->fragments); - put_user(os->nbfrags, &inf->fragstotal); - put_user(os->fragsize, &inf->fragsize); - put_user(bytes, &inf->bytes); - break; - } - - case SNDCTL_DSP_GETISPACE: - { - audio_buf_info *inf = (audio_buf_info *) arg; - int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf)); - int i; - int frags = 0, bytes = 0; - - if (err) - return err; - for (i = 0; i < is->nbfrags; i++) { - if (atomic_read(&is->buffers[i].sem.count) > 0) { - if (is->buffers[i].size == is->fragsize) frags++; - bytes += is->buffers[i].size; - } - } - put_user(frags, &inf->fragments); - put_user(is->nbfrags, &inf->fragstotal); - put_user(is->fragsize, &inf->fragsize); - put_user(bytes, &inf->bytes); - break; - } - - case SNDCTL_DSP_RESET: - switch (file->f_flags & O_ACCMODE) { - case O_RDONLY: - case O_RDWR: - if (state->need_tx_for_rx) - sa1100_dma_set_spin(os->dma_ch, 0, 0); - audio_clear_buf(is); - } - switch (file->f_flags & O_ACCMODE) { - case O_WRONLY: - case O_RDWR: - audio_clear_buf(os); - } - return 0; - - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_NONBLOCK: - case SNDCTL_DSP_GETCAPS: - case SNDCTL_DSP_GETTRIGGER: - case SNDCTL_DSP_SETTRIGGER: - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - case SNDCTL_DSP_SETSYNCRO: - case SNDCTL_DSP_SETDUPLEX: - return -ENOSYS; - default: - /* - * Let the client of this module handle the - * non generic ioctls - */ - return state->client_ioctl(inode, file, cmd, arg); - } - - return 0; -} - - -static int audio_release(struct inode *inode, struct file *file) -{ - audio_state_t *state = (audio_state_t *)file->private_data; - DPRINTK("audio_release\n"); - - switch (file->f_flags & O_ACCMODE) { - case O_RDONLY: - case O_RDWR: - if (state->rd_refcount == 1) { - if (state->need_tx_for_rx) - sa1100_dma_set_spin(state->output_stream->dma_ch, 0, 0); - audio_clear_buf(state->input_stream); - state->rd_refcount = 0; - } - } - - switch (file->f_flags & O_ACCMODE) { - case O_WRONLY: - case O_RDWR: - if (state->wr_refcount == 1) { - audio_sync(file); - audio_clear_buf(state->output_stream); - state->wr_refcount = 0; - } - } - - if (!AUDIO_ACTIVE(state)) { - if (state->hw_shutdown) - state->hw_shutdown(); -#ifdef CONFIG_PM - pm_unregister(state->pm_dev); -#endif - } - - return 0; -} - - -#ifdef CONFIG_PM - -static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) -{ - audio_state_t *state = (audio_state_t *)pm_dev->data; - - switch (req) { - case PM_SUSPEND: /* enter D1-D3 */ - if (state->output_stream) - sa1100_dma_sleep(state->output_stream->dma_ch); - if (state->input_stream) - sa1100_dma_sleep(state->input_stream->dma_ch); - if (AUDIO_ACTIVE(state) && state->hw_shutdown) - state->hw_shutdown(); - break; - case PM_RESUME: /* enter D0 */ - if (AUDIO_ACTIVE(state) && state->hw_init) - state->hw_init(); - if (state->input_stream) - sa1100_dma_wakeup(state->input_stream->dma_ch); - if (state->output_stream) - sa1100_dma_wakeup(state->output_stream->dma_ch); - break; - } - return 0; -} - -#endif - - -int sa1100_audio_instance(struct inode *inode, struct file *file, - audio_state_t *state) -{ - int in = 0, out = 0; - - DPRINTK("audio_open\n"); - - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - if (!state->input_stream) - return -ENODEV; - if (state->rd_refcount) - return -EBUSY; - in = 1; - } else if ((file->f_flags & O_ACCMODE) == O_WRONLY) { - if (!state->input_stream) - return -ENODEV; - if (state->wr_refcount) - return -EBUSY; - out = 1; - } else if ((file->f_flags & O_ACCMODE) == O_RDWR) { - if (!state->input_stream || !state->output_stream) - return -EINVAL; - if (state->rd_refcount || state->wr_refcount) - return -EBUSY; - in = out = 1; - } else - return -EINVAL; - - if (!AUDIO_ACTIVE(state)) { - if (state->hw_init) - state->hw_init(); -#ifdef CONFIG_PM - state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback); - if (state->pm_dev) - state->pm_dev->data = state; -#endif - } - - if (in) { - audio_clear_buf(state->input_stream); - state->rd_refcount = 1; - state->input_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; - state->input_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; - sa1100_dma_set_callback(state->input_stream->dma_ch, - audio_dmain_done_callback); - } - - if (out) { - audio_clear_buf(state->output_stream); - state->wr_refcount = 1; - state->output_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; - state->output_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; - sa1100_dma_set_callback(state->output_stream->dma_ch, - audio_dmaout_done_callback); - } - - file->private_data = state; - file->f_op->release = audio_release; - file->f_op->write = audio_write; - file->f_op->read = audio_read; - file->f_op->poll = audio_poll; - file->f_op->ioctl = audio_ioctl; - file->f_op->llseek = audio_llseek; - - return 0; -} - -EXPORT_SYMBOL(sa1100_audio_instance); - diff -urN linux-2.4.5-rmk7-np2/drivers/sound/sa1100-audio.h linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100-audio.h --- linux-2.4.5-rmk7-np2/drivers/sound/sa1100-audio.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100-audio.h Thu Jan 1 01:00:00 1970 @@ -1,53 +0,0 @@ -/* - * Common audio handling for the SA11x0 - * - * Copyright (c) 2000 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - */ - - -/* - * Buffer Management - */ - -typedef struct { - int size; /* buffer size */ - char *start; /* points to actual buffer */ - dma_addr_t dma_addr; /* physical buffer address */ - struct semaphore sem; /* down before touching the buffer */ - int master; /* owner for buffer allocation, contain size when true */ -} audio_buf_t; - -typedef struct { - audio_buf_t *buffers; /* pointer to audio buffer structures */ - audio_buf_t *buf; /* current buffer used by read/write */ - u_int buf_idx; /* index for the pointer above... */ - u_int fragsize; /* fragment i.e. buffer size */ - u_int nbfrags; /* nbr of fragments i.e. buffers */ - dmach_t dma_ch; /* DMA channel ID */ -} audio_stream_t; - -/* - * State structure for one instance - */ - -typedef struct { - audio_stream_t *output_stream; - audio_stream_t *input_stream; - int rd_refcount; /* nbr of concurrent open() for recording */ - int wr_refcount; /* nbr of concurrent open() for playback */ - int need_tx_for_rx; /* true if data must be sent while receiving */ - void (*hw_init)(void); - void (*hw_shutdown)(void); - int (*client_ioctl)(struct inode *, struct file *, uint, ulong); - struct pm_dev *pm_dev; -} audio_state_t; - -/* - * Functions exported by this module - */ -extern int sa1100_audio_instance(struct inode *inode, struct file *file, - audio_state_t *state); - diff -urN linux-2.4.5-rmk7-np2/drivers/sound/sa1100ssp.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100ssp.c --- linux-2.4.5-rmk7-np2/drivers/sound/sa1100ssp.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1100ssp.c Thu Jan 1 01:00:00 1970 @@ -1,178 +0,0 @@ -/* - * Glue audio driver for a simple DAC on the SA1100's SSP port - * - * Copyright (c) 2001 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * History: - * - * 2001-06-04 Nicolas Pitre Initial release. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "sa1100-audio.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -#define AUDIO_NAME "SA1100 SSP audio" - -#define AUDIO_FMT_MASK (AFMT_S16_LE) -#define AUDIO_FMT_DEFAULT (AFMT_S16_LE) -#define AUDIO_CHANNELS_DEFAULT 2 -#define AUDIO_RATE_DEFAULT 44100 - - -/* - * Audio interface - */ - -static void ssp_audio_init(void) -{ - if (machine_is_lart()) { - /* LART has the SSP port rewired to GPIO 10-13, 19 */ - /* alternate functions for the GPIOs */ - GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | - GPIO_SSP_SFRM | GPIO_SSP_CLK ); - - /* Set the direction: 10, 12, 13 output; 11, 19 input */ - GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM ); - GPDR &= ~( GPIO_SSP_RXD | GPIO_SSP_CLK ); - - /* enable SSP pin swap */ - PPAR |= PPAR_SPR; - } - - /* turn on the SSP */ - Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2) | - SSCR0_SSE); - Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk); -} - -static int ssp_audio_ioctl( struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - long val; - int ret = 0; - - /* - * These are platform dependent ioctls which are not handled by the - * generic sa1100-audio module. - */ - switch (cmd) { - case SNDCTL_DSP_SETFMT: - ret = get_user(val, (long *) arg); - if (ret) break; - if (val & AUDIO_FMT_MASK) { - break; - } else - return -EINVAL; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - ret = get_user(val, (long *) arg); - if (ret) break; - if (cmd == SNDCTL_DSP_STEREO) - val = val ? 2 : 1; - /* Simple standard DACs are stereo only */ - if (val != 2) - return -EINVAL; - break; - - case SOUND_PCM_READ_CHANNELS: - return put_user(2, (long *) arg); - - case SNDCTL_DSP_SPEED: - case SOUND_PCM_READ_RATE: - /* We assume the clock doesn't change */ - return put_user(AUDIO_RATE_DEFAULT, (long *) arg); - - case SNDCTL_DSP_GETFMTS: - return put_user(AUDIO_FMT_MASK, (long *) arg); - - default: - return -EINVAL; - } - - return ret; -} - -static audio_stream_t output_stream; - -static audio_state_t audio_state = { - output_stream: &output_stream, - hw_init: ssp_audio_init, - client_ioctl: ssp_audio_ioctl, -}; - -static int ssp_audio_open(struct inode *inode, struct file *file) -{ - return sa1100_audio_instance(inode, file, &audio_state); -} - -/* - * Missing fields of this structure will be patched with the call - * to sa1100_audio_instance() - */ -static struct file_operations ssp_audio_fops = { - open: ssp_audio_open, - owner: THIS_MODULE -}; - - -static int audio_dev_id; - -static int __init sa1100ssp_audio_init(void) -{ - if (!machine_is_lart()) { - printk(KERN_ERR AUDIO_NAME ": no support for this SA-1100 design!\n"); - /* look at ssp_audio_init() for specific initialisations */ - return -ENODEV; - } - - /* Acquire and initialize DMA */ - if (sa1100_request_dma(&output_stream.dma_ch, "UDA1341 out") < 0) { - printk( KERN_ERR AUDIO_NAME ": unable to get DMA channels\n" ); - return -EBUSY; - } - sa1100_dma_set_device(output_stream.dma_ch, DMA_Ser4SSPWr); - - /* register devices */ - audio_dev_id = register_sound_dsp(&ssp_audio_fops, -1); - - printk( KERN_INFO AUDIO_NAME " initialized\n" ); - return 0; -} - -module_init(sa1100ssp_audio_init); - - -static void __exit sa1100ssp_audio_exit(void) -{ - unregister_sound_dsp(audio_dev_id); - sa1100_free_dma(output_stream.dma_ch); -} - -module_exit(sa1100ssp_audio_exit); diff -urN linux-2.4.5-rmk7-np2/drivers/sound/sa1111-uda1341.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1111-uda1341.c --- linux-2.4.5-rmk7-np2/drivers/sound/sa1111-uda1341.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/sa1111-uda1341.c Thu Jan 1 01:00:00 1970 @@ -1,323 +0,0 @@ -/* - * Glue audio driver for the SA1111 compagnon chip & Philips UDA1341 codec. - * - * Copyright (c) 2000 John Dorsey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * History: - * - * 2000-09-04 John Dorsey SA-1111 Serial Audio Controller support - * was initially added to the sa1100-uda1341.c - * driver. - * - * 2001-06-03 Nicolas Pitre Made this file a separate module, based on - * the former sa1100-uda1341.c driver. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "uda1341.h" -#include "sa1100-audio.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -/* - * Definitions - */ - -#define AUDIO_NAME "SA1111/UDA1341" - -#define AUDIO_FMT_MASK (AFMT_S16_LE) -#define AUDIO_FMT_DEFAULT (AFMT_S16_LE) -#define AUDIO_CHANNELS_DEFAULT 2 -#define AUDIO_RATE_DEFAULT 22050 - -#define AUDIO_CLK_BASE 561600 - - -/* - * Write data to a device on the L3 bus. The address is passed as well as - * the data and length. The length written is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_write(char addr, char *data, int len) -{ - int bytes = len; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - if( len > 1 ){ - SACR1 |= SACR1_L3MB; - while( (len--) > 1 ){ - L3_CAR = addr; - L3_CDR = *data++; - while((SASR0 & SASR0_L3WD) == 0) - mdelay(1); - SASCR = SASCR_DTS; - } - } - SACR1 &= ~SACR1_L3MB; - L3_CAR = addr; - L3_CDR = *data; - while((SASR0 & SASR0_L3WD) == 0) - mdelay(1); - SASCR = SASCR_DTS; - - return bytes; -} - -/* - * Read data from a device on the L3 bus. The address is passed as well as - * the data and length. The length read is returned. The register space - * is encoded in the address (low two bits are set and device address is - * in the upper 6 bits). - */ -static int L3_read(char addr, char *data, int len) -{ - int bytes = len; - - DPRINTK("%s(0x%x, %d)\n", __FUNCTION__, addr, len); - - if( len > 1 ){ - SACR1 |= SACR1_L3MB; - while( (len--) > 1 ){ - L3_CAR = addr; - while((SASR0 & SASR0_L3RD) == 0) - mdelay(1); - *data++ = L3_CDR; - SASCR = SASCR_RDD; - } - } - SACR1 &= ~SACR1_L3MB; - L3_CAR = addr; - while((SASR0 & SASR0_L3RD) == 0) - mdelay(1); - *data = L3_CDR; - SASCR = SASCR_RDD; - - return bytes; -} - - -/* - * Mixer (UDA1341) interface - */ - -static UDA1341_regs_t UDA1341_regs = UDA1341_REGS_DFLT; - -static UDA1341_state_t uda1341_state = { - regs: &UDA1341_regs, - L3_write: L3_write, - L3_read: L3_read, -}; - -static int mixer_ioctl (struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); -} - -static struct file_operations uda1341_mixer_fops = { - ioctl: mixer_ioctl, - owner: THIS_MODULE -}; - - -/* - * Audio interface - */ - -static int audio_clk_div = AUDIO_CLK_BASE/AUDIO_RATE_DEFAULT - 1; - -static void sa1111_audio_init(void) -{ -#ifdef CONFIG_ASSABET_NEPONSET - if (machine_is_assabet()) { - /* Select I2S audio (instead of AC-Link) */ - AUD_CTL = AUD_SEL_1341; - } -#endif -#ifdef CONFIG_SA1100_JORNADA720 - if (machine_is_jornada720()) { - /* LDD4 is speaker, LDD3 is microphone */ - PPSR &= ~(PPC_LDD3 | PPC_LDD4); - PPDR |= PPC_LDD3 | PPC_LDD4; - PPSR |= PPC_LDD4; /* enable speaker */ - PPSR |= PPC_LDD3; /* enable microphone */ - } -#endif - - SKCR &= ~SKCR_SELAC; - - /* Enable the I2S clock and L3 bus clock: */ - SKPCR |= (SKPCR_I2SCLKEN | SKPCR_L3CLKEN); - - /* Activate and reset the Serial Audio Controller */ - SACR0 |= (SACR0_ENB | SACR0_RST); - mdelay(5); - SACR0 &= ~SACR0_RST; - - /* For I2S, BIT_CLK is supplied internally. The "SA-1111 - * Specification Update" mentions that the BCKD bit should - * be interpreted as "0 = output". Default clock divider - * is 22.05kHz. - * - * Select I2S, L3 bus. "Recording" and "Replaying" - * (receive and transmit) are enabled. - */ - SACR1 = SACR1_L3EN; - SKAUD = audio_clk_div; - - /* Initialize the UDA1341 internal state */ - uda1341_state.active = 1; - uda1341_reset(&uda1341_state); -} - -static void sa1111_audio_shutdown(void) -{ - uda1341_state.active = 0; - SACR0 &= ~SACR0_ENB; -} - -static int sa1111_audio_ioctl( struct inode *inode, struct file *file, - uint cmd, ulong arg) -{ - long val; - int ret = 0; - - switch (cmd) { - case SNDCTL_DSP_SETFMT: - ret = get_user(val, (long *) arg); - if (ret) break; - if (val & AUDIO_FMT_MASK) { - break; - } else - return -EINVAL; - - case SNDCTL_DSP_CHANNELS: - case SNDCTL_DSP_STEREO: - ret = get_user(val, (long *) arg); - if (ret) break; - if (cmd == SNDCTL_DSP_STEREO) - val = val ? 2 : 1; - /* the UDA1341 is stereo only */ - if (val != 2) - return -EINVAL; - break; - - case SOUND_PCM_READ_CHANNELS: - return put_user(2, (long *) arg); - - case SNDCTL_DSP_SPEED: - ret = get_user(val, (long *) arg); - if (ret) break; - if (val < 8000) val = 8000; - if (val > 48000) val = 48000; - SKAUD = audio_clk_div = AUDIO_CLK_BASE/val - 1; - /* fall through */ - - case SOUND_PCM_READ_RATE: - return put_user(AUDIO_CLK_BASE/(audio_clk_div+1), (long *) arg); - - case SNDCTL_DSP_GETFMTS: - return put_user(AUDIO_FMT_MASK, (long *) arg); - - default: - /* Maybe this is meant for the mixer (as per OSS Docs) */ - return uda1341_mixer_ioctl(&uda1341_state, cmd, arg); - } - - return ret; -} - -static audio_stream_t output_stream, input_stream; - -static audio_state_t audio_state = { - output_stream: &output_stream, - input_stream: &input_stream, - hw_init: sa1111_audio_init, - hw_shutdown: sa1111_audio_shutdown, - client_ioctl: sa1111_audio_ioctl, -}; - -static int sa1111_audio_open(struct inode *inode, struct file *file) -{ - return sa1100_audio_instance(inode, file, &audio_state); -} - -/* - * Missing fields of this structure will be patched with the call - * to sa1100_audio_instance() - */ -static struct file_operations sa1111_audio_fops = { - open: sa1111_audio_open, - owner: THIS_MODULE -}; - - -static int audio_dev_id, mixer_dev_id; - -static int __init sa1111_uda1341_init(void) -{ - if ( !( (machine_is_assabet() && machine_has_neponset()) || - machine_is_jornada720() )) - return -ENODEV; - - /* Acquire and initialize DMA */ - if (sa1111_sac_request_dma(&output_stream.dma_ch, "UDA1341 out", SA1111_SAC_XMT_CHANNEL) < 0 || - sa1111_sac_request_dma(&input_stream.dma_ch, "UDA1341 in", SA1111_SAC_RCV_CHANNEL) < 0) { - sa1100_free_dma(output_stream.dma_ch); - printk( KERN_ERR AUDIO_NAME ": unable to get DMA channels\n" ); - return -EBUSY; - } - - /* Settings which differ from the default initialisation */ - UDA1341_regs.status_0.input_fmt = UDA_STATUS0_IF_I2S; - UDA1341_regs.status_0.system_clk = UDA_STATUS0_SC_256FS; - - /* register devices */ - audio_dev_id = register_sound_dsp(&sa1111_audio_fops, -1); - mixer_dev_id = register_sound_mixer(&uda1341_mixer_fops, -1); - - printk( KERN_INFO AUDIO_NAME " initialized\n" ); - return 0; -} - -module_init(sa1111_uda1341_init); - - -static void __exit sa1111_uda1341_exit(void) -{ - unregister_sound_dsp(audio_dev_id); - unregister_sound_mixer(mixer_dev_id); - sa1100_free_dma(output_stream.dma_ch); - sa1100_free_dma(input_stream.dma_ch); -} - -module_exit(sa1111_uda1341_exit); - diff -urN linux-2.4.5-rmk7-np2/drivers/sound/uda1341.c linux-2.4.5-rmk7-np2-ssv1/drivers/sound/uda1341.c --- linux-2.4.5-rmk7-np2/drivers/sound/uda1341.c Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/uda1341.c Thu Jan 1 01:00:00 1970 @@ -1,332 +0,0 @@ -/* - * Philips UDA1341 mixer device driver - * - * Copyright (c) 2000 Nicolas Pitre - * - * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - * - * History: - * - * 2000-05-21 Nicolas Pitre Initial release. - * - * 2000-08-19 Erik Bunce More inline w/ OSS API and UDA1341 docs - * including fixed AGC and audio source handling - * - * 2000-11-30 Nicolas Pitre - More mixer functionalities. - * - * 2001-06-03 Nicolas Pitre Made this file a separate module, based on - * the former sa1100-uda1341.c driver. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "uda1341.h" - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK( x... ) printk( ##x ) -#else -#define DPRINTK( x... ) -#endif - - -#define SET(adr, reg, len) \ - if (active) state->L3_write((UDA1341_L3Addr << 2)|(adr), (char*)®s->reg, (len)) - -int uda1341_mixer_ioctl (UDA1341_state_t *state, uint cmd, ulong arg) -{ - UDA1341_regs_t *regs = state->regs; - int active = state->active; - int ret; - long val = 0; - - /* - * Dispatch based on command. - * Exit with break if modifications occurred. - */ - switch (cmd) { - case SOUND_MIXER_INFO: - { - mixer_info info; - strncpy(info.id, "UDA1341", sizeof(info.id)); - strncpy(info.name, "Philips UDA1341", sizeof(info.name)); - info.modify_counter = state->mix_modcnt; - return copy_to_user((void *)arg, &info, sizeof(info)); - } - - case SOUND_OLD_MIXER_INFO: - { - _old_mixer_info info; - strncpy(info.id, "UDA1341", sizeof(info.id)); - strncpy(info.name, "Philips UDA1341", sizeof(info.name)); - return copy_to_user((void *)arg, &info, sizeof(info)); - } - - case SOUND_MIXER_READ_DEVMASK: - val = (SOUND_MASK_VOLUME | - SOUND_MASK_TREBLE | - SOUND_MASK_BASS | - SOUND_MASK_LINE1 | - SOUND_MASK_LINE2 | - SOUND_MASK_MIC); - return put_user(val, (long *) arg); - - case SOUND_MIXER_READ_RECMASK: - val = (SOUND_MASK_MIC | - SOUND_MASK_LINE1 | - SOUND_MASK_LINE2 | - SOUND_MASK_LINE3); - return put_user(val, (long *) arg); - - case SOUND_MIXER_READ_STEREODEVS: - return put_user(0, (long *) arg); - - case SOUND_MIXER_READ_CAPS: - val = SOUND_CAP_EXCL_INPUT; - return put_user(val, (long *) arg); - - case SOUND_MIXER_AGC: - /* - * (as found in sb_mixer.c) - * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1). - */ - regs->data0_ext4.AGC_ctrl = val ? 1 : 0; - SET (UDA1341_DATA0, data0_ext4, 2); - ret = put_user(regs->data0_ext4.AGC_ctrl, (long *) arg); - if (ret) - return ret; - break; - - case SOUND_MIXER_WRITE_RECSRC: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - /* Recording source is selected by mixer_mode */ - switch (val) { - case SOUND_MASK_LINE1: - /* input channel 1 select */ - regs->data0_ext2.mixer_mode = 1; - break; - case SOUND_MASK_LINE2: - /* Double differential mode */ - regs->data0_ext2.mixer_mode = 0; - break; - case SOUND_MASK_LINE3: - /* - * digital mixer mode - * (input 1 x MA + input2 x MB) - */ - regs->data0_ext2.mixer_mode = 3; - break; - case SOUND_MASK_MIC: - default: - /* Input channel 2 select */ - regs->data0_ext2.mixer_mode = 2; - break; - } - SET (UDA1341_DATA0, data0_ext2, 2); - break; - - case SOUND_MIXER_READ_RECSRC: - /* Recording source is specified by mixer_mode */ - switch (regs->data0_ext2.mixer_mode) { - case 0: - /* Double differential mode */ - val = SOUND_MASK_LINE2; - break; - case 1: - /* input channel 1 select */ - val = SOUND_MASK_LINE1; - break; - case 3: - /* - * digital mixer mode - * (input 1 x MA + input2 x MB) - */ - val = SOUND_MASK_LINE3; - break; - case 2: - default: - /* Input channel 2 select */ - val = SOUND_MASK_MIC; - break; - } - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_VOLUME: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_0.volume = 63 - (((val & 0xff) + 1) * 63) / 100; - SET (UDA1341_DATA0, data0_0, 1); - break; - - case SOUND_MIXER_READ_VOLUME: - val = ((63 - regs->data0_0.volume) * 100) / 63; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_TREBLE: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_1.treble = (((val & 0xff) + 1) * 3) / 100; - SET (UDA1341_DATA0, data0_1, 1); - break; - - case SOUND_MIXER_READ_TREBLE: - val = (regs->data0_1.treble * 100) / 3; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_BASS: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_1.bass = (((val & 0xff) + 1) * 15) / 100; - SET (UDA1341_DATA0, data0_1, 1); - break; - - case SOUND_MIXER_READ_BASS: - val = (regs->data0_1.bass * 100) / 15; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_LINE1: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_ext0.ch1_gain = (((val & 0xff) + 1) * 31) / 100; - SET (UDA1341_DATA0, data0_ext0, 2); - break; - - case SOUND_MIXER_READ_LINE1: - val = (regs->data0_ext0.ch1_gain * 100) / 31; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_LINE2: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_ext1.ch2_gain = (((val & 0xff) + 1) * 31) / 100; - SET (UDA1341_DATA0, data0_ext1, 2); - break; - - case SOUND_MIXER_READ_LINE2: - val = (regs->data0_ext1.ch2_gain * 100) / 31; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_MIC: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - /* Use different registers depending on AGC setting */ - if (regs->data0_ext4.AGC_ctrl == 1) { - /* AGC On, play with MIC sensitivity */ - /* even if 3 bits, value 7 is not used */ - regs->data0_ext2.mic_level = - (((val & 0xff) + 1) * 6) / 100; - SET (UDA1341_DATA0, data0_ext2, 2); - } else { - /* AGC Off, plain with Input channel 2 amplifier gain */ - val = ((val & 0xff) * 127) / 100; - regs->data0_ext4.ch2_igain_l = val & 3; - regs->data0_ext5.ch2_igain_h = val >> 2; - SET (UDA1341_DATA0, data0_ext4, 2); - SET (UDA1341_DATA0, data0_ext5, 2); - } - break; - - case SOUND_MIXER_READ_MIC: - /* Use different registers depending on AGC setting */ - if (regs->data0_ext4.AGC_ctrl == 1) { - val = (regs->data0_ext2.mic_level * 100) / 6; - val |= val << 8; - } else { - val = regs->data0_ext4.ch2_igain_l + - (regs->data0_ext5.ch2_igain_h << 2); - val = (val * 100) / 127; - val |= val << 8; - } - return put_user(val, (long *) arg); - -#if 0 /* Experimental. What those should produce is still not obvious to me. */ - case SOUND_MIXER_WRITE_OGAIN: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_ext6.AGC_level = (((val & 0xff) + 1) * 3) / 100; - SET (UDA1341_DATA0, data0_ext6, 2); - break; - - case SOUND_MIXER_READ_OGAIN: - val = (regs->data0_ext6.AGC_level * 100) / 3; - val |= val << 8; - return put_user(val, (long *) arg); - - case SOUND_MIXER_WRITE_IMIX: - ret = get_user(val, (long *) arg); - if (ret) - return ret; - regs->data0_ext2.mixer_mode = val; - SET (UDA1341_DATA0, data0_ext2, 2); - break; - - case SOUND_MIXER_READ_IMIX: - val = regs->data0_ext2.mixer_mode; - return put_user(val, (long *) arg); -#endif - - case SOUND_MIXER_WRITE_RECLEV: - case SOUND_MIXER_READ_RECLEV: - default: - return -ENOSYS; - } - - state->mix_modcnt++; - return 0; -} - -void uda1341_reset (UDA1341_state_t *state) -{ - UDA1341_regs_t *regs = state->regs; - int active = 1; - - DPRINTK("uda1341_reset\n"); - - /* Reset the chip */ - regs->status_0.reset = 1; - SET (UDA1341_STATUS, status_0, 1); - regs->status_0.reset = 0; - - /* Restore chip state, mixer values, etc... */ - SET (UDA1341_STATUS, status_0, 1); - SET (UDA1341_STATUS, status_1, 1); - SET (UDA1341_DATA0, data0_0, 1); - SET (UDA1341_DATA0, data0_1, 1); - SET (UDA1341_DATA0, data0_2, 1); - SET (UDA1341_DATA0, data0_ext0, 2); - SET (UDA1341_DATA0, data0_ext1, 2); - SET (UDA1341_DATA0, data0_ext2, 2); - SET (UDA1341_DATA0, data0_ext4, 2); - SET (UDA1341_DATA0, data0_ext5, 2); - SET (UDA1341_DATA0, data0_ext6, 2); -} - -EXPORT_SYMBOL(uda1341_mixer_ioctl); -EXPORT_SYMBOL(uda1341_reset); - diff -urN linux-2.4.5-rmk7-np2/drivers/sound/uda1341.h linux-2.4.5-rmk7-np2-ssv1/drivers/sound/uda1341.h --- linux-2.4.5-rmk7-np2/drivers/sound/uda1341.h Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/sound/uda1341.h Thu Jan 1 01:00:00 1970 @@ -1,205 +0,0 @@ -/* - * Philips UDA1341 mixer device driver - * - * Copyright (c) 2000 Nicolas Pitre - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License. - */ - -/* - * UDA1341 L3 address and command types - */ -#define UDA1341_L3Addr 5 -#define UDA1341_DATA0 0 -#define UDA1341_DATA1 1 -#define UDA1341_STATUS 2 - - -/* - * UDA1341 internal state variables. - * The default values are defined to sane initial operating values. - */ - -/* UDA1341 status settings */ - -#define UDA_STATUS0_IF_I2S 0 -#define UDA_STATUS0_IF_LSB16 1 -#define UDA_STATUS0_IF_LSB18 2 -#define UDA_STATUS0_IF_LSB20 3 -#define UDA_STATUS0_IF_MSB 4 -#define UDA_STATUS0_IF_MSB16 5 -#define UDA_STATUS0_IF_MSB18 6 -#define UDA_STATUS0_IF_MSB20 7 - -#define UDA_STATUS0_SC_512FS 0 -#define UDA_STATUS0_SC_384FS 1 -#define UDA_STATUS0_SC_256FS 2 - -typedef struct { - u_int DC_filter:1; /* DC filter */ - u_int input_fmt:3; /* data input format */ - u_int system_clk:2; /* system clock frequency */ - u_int reset:1; /* reset */ - const u_int select:1; /* must be set to 0 */ -} UDA_STATUS_0; - -#define UDA_STATUS_0_DFLT \ - (UDA_STATUS_0){0, UDA_STATUS0_IF_LSB16, UDA_STATUS0_SC_256FS, 0, 0} - -typedef struct { - u_int DAC_on:1; /* DAC powered */ - u_int ADC_on:1; /* ADC powered */ - u_int double_speed:1; /* double speed playback */ - u_int DAC_pol:1; /* polarity of DAC */ - u_int ADC_pol:1; /* polarity of ADC */ - u_int ADC_gain:1; /* gain of ADC */ - u_int DAC_gain:1; /* gain of DAC */ - const u_int select:1; /* must be set to 1 */ -} UDA_STATUS_1; - -#define UDA_STATUS_1_DFLT (UDA_STATUS_1){1, 1, 0, 0, 0, 1, 1, 1} - -/* UDA1341 direct control settings */ - -typedef struct { - u_int volume:6; /* volume control */ - const u_int select:2; /* must be set to 0 */ -} UDA_DATA0_0; - -#define UDA_DATA0_0_DFLT (UDA_DATA0_0){15, 0} - -typedef struct { - u_int treble:2; - u_int bass:4; - const u_int select:2; /* must be set to 1 */ -} UDA_DATA0_1; - -#define UDA_DATA0_1_DFLT (UDA_DATA0_1){0, 0, 1} - -typedef struct { - u_int mode:2; /* mode switch */ - u_int mute:1; - u_int deemphasis:2; - u_int peak_detect:1; - const u_int select:2; /* must be set to 2 */ -} UDA_DATA0_2; - -#define UDA_DATA0_2_DFLT (UDA_DATA0_2){3, 0, 0, 1, 2} - -/* DATA0 extended programming registers */ - -typedef struct { - const u_int ext_addr:3; /* must be set to 0 */ - const u_int select1:5; /* must be set to 24 */ - u_int ch1_gain:5; /* mixer gain channel 1 */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext0; - -#define UDA_DATA0_ext0_DFLT (UDA_DATA0_ext0){0, 24, 4, 7} - -typedef struct { - const u_int ext_addr:3; /* must be set to 1 */ - const u_int select1:5; /* must be set to 24 */ - u_int ch2_gain:5; /* mixer gain channel 2 */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext1; - -#define UDA_DATA0_ext1_DFLT (UDA_DATA0_ext1){1, 24, 4, 7} - -typedef struct { - const u_int ext_addr:3; /* must be set to 2 */ - const u_int select1:5; /* must be set to 24 */ - u_int mixer_mode:2; - u_int mic_level:3; /* MIC sensitivity level */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext2; - -#define UDA_DATA0_ext2_DFLT (UDA_DATA0_ext2){2, 24, 2, 4, 7} - -typedef struct { - const u_int ext_addr:3; /* must be set to 4 */ - const u_int select1:5; /* must be set to 24 */ - u_int ch2_igain_l:2; /* input amplifier gain channel 2 (bits 1-0) */ - const u_int reserved:2; /* must be set to 0 */ - u_int AGC_ctrl:1; /* AGC control */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext4; - -#define UDA_DATA0_ext4_DFLT (UDA_DATA0_ext4){4, 24, 0 & 3, 0, 1, 7} - -typedef struct { - const u_int ext_addr:3; /* must be set to 5 */ - const u_int select1:5; /* must be set to 24 */ - u_int ch2_igain_h:5; /* input amplifier gain channel 2 (bits 6-2) */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext5; - -#define UDA_DATA0_ext5_DFLT (UDA_DATA0_ext5){5, 24, 0 >> 2, 7} - -typedef struct { - const u_int ext_addr:3; /* must be set to 6 */ - const u_int select1:5; /* must be set to 24 */ - u_int AGC_level:2; /* AGC output level */ - u_int AGC_const:3; /* AGC time constant */ - const u_int select2:3; /* must be set to 7 */ -} UDA_DATA0_ext6; - -#define UDA_DATA0_ext6_DFLT (UDA_DATA0_ext6){6, 24, 3, 0, 7} - -typedef struct { - u_int peak:6; /* peak level value */ -} UDA_DATA1; - -#define UDA_DATA1_DFLT (UDA_DATA1){0} - -/* - * All registers - */ -typedef struct { - UDA_STATUS_0 status_0; - UDA_STATUS_1 status_1; - UDA_DATA0_0 data0_0; - UDA_DATA0_1 data0_1; - UDA_DATA0_2 data0_2; - UDA_DATA0_ext0 data0_ext0; - UDA_DATA0_ext1 data0_ext1; - UDA_DATA0_ext2 data0_ext2; - UDA_DATA0_ext4 data0_ext4; - UDA_DATA0_ext5 data0_ext5; - UDA_DATA0_ext6 data0_ext6; - UDA_DATA1 data1; -} UDA1341_regs_t; - -#define UDA1341_REGS_DFLT { \ - UDA_STATUS_0_DFLT, \ - UDA_STATUS_1_DFLT, \ - UDA_DATA0_0_DFLT, \ - UDA_DATA0_1_DFLT, \ - UDA_DATA0_2_DFLT, \ - UDA_DATA0_ext0_DFLT, \ - UDA_DATA0_ext1_DFLT, \ - UDA_DATA0_ext2_DFLT, \ - UDA_DATA0_ext4_DFLT, \ - UDA_DATA0_ext5_DFLT, \ - UDA_DATA0_ext6_DFLT, \ - UDA_DATA1_DFLT } - -/* - * Structure containing the necessary variables - * for one instance of this chip. - */ -typedef struct { - UDA1341_regs_t *regs; - int (*L3_write)(char addr, char *data, int len); - int (*L3_read)(char addr, char *data, int len); - int active; /* non zero if powered */ - int mix_modcnt; /* mixer mods count */ -} UDA1341_state_t; - -/* - * Function prototypes exported by this module - */ -extern int uda1341_mixer_ioctl (UDA1341_state_t *state, uint cmd, ulong arg); -extern void uda1341_reset (UDA1341_state_t *state); - # # USB (?) # diff -urN linux-2.4.5-rmk7-np2/drivers/usb/Config.in linux-2.4.5-rmk7-np2-ssv1/drivers/usb/Config.in --- linux-2.4.5-rmk7-np2/drivers/usb/Config.in Sat Jul 13 19:40:18 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/usb/Config.in Wed Oct 10 18:56:03 2001 @@ -26,9 +26,8 @@ dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB # if SA1111 & OHCI, then PCI support is required - if [ "$CONFIG_SA1111" = "y" -a "$CONFIG_USB_OHCI" != "n" ]; then + if [ "$CONFIG_ASSABET_NEPONSET" = "y" ]; then define_bool CONFIG_PCI y - define_bool CONFIG_SA1111_PCI y fi comment 'USB Device Class drivers' # # Video (?) # diff -urN linux-2.4.5-rmk7-np2/drivers/video/sa1100fb.c linux-2.4.5-rmk7-np2-ssv1/drivers/video/sa1100fb.c --- linux-2.4.5-rmk7-np2/drivers/video/sa1100fb.c Sat Jul 13 19:35:17 2002 +++ linux-2.4.5-rmk7-np2-ssv1/drivers/video/sa1100fb.c Wed Oct 10 21:22:48 2001 @@ -460,6 +460,33 @@ transp: { offset: 0, length: 0, }, }; +//-------------------- SSV-CHANGE -------------------- +#ifdef CONFIG_SA1100_DNP1110 +static struct sa1100fb_mach_info dnp1110_info __initdata = { + pixclock: 39721, bpp: 16, + xres: 640, yres: 480, + + hsync_len: 64, vsync_len: 2, + left_margin: 80, upper_margin: 31, + right_margin: 16, lower_margin: 12, + + sync: 0, + + lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Act, + lccr3: LCCR3_OutEnH| LCCR3_PixFlEdg | LCCR3_ACBsDiv(512) | + LCCR3_HorSnchL | LCCR3_VrtSnchL | + LCCR3_PixClkDiv(12), +}; + //***** RGB 565 ***** +static struct sa1100fb_rgb dnp1110_rgb_16 = { + red: { offset: 11, length: 5, }, + green: { offset: 5, length: 6, }, + blue: { offset: 0, length: 5, }, + transp: { offset: 0, length: 0, }, +}; +#endif +//------------------------------------------------------------ + #ifdef CONFIG_SA1100_ASSABET static struct sa1100fb_mach_info assabet_info __initdata = { #ifdef ASSABET_PAL_VIDEO @@ -742,6 +769,16 @@ * bitsy {12,4}, { 7,4}, { 1,4}, { 0,0} * freebird { 8,4}, { 4,4}, { 0,4}, {12,4} */ + +//---------- SSV-CHANGE ---------- +#ifdef CONFIG_SA1100_DNP1110 + if (machine_is_dnp1110()) { + inf = &dnp1110_info; + fbi->rgb[RGB_16] = &dnp1110_rgb_16; + } +#endif +//---------------------------------------- + #ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) { inf = &assabet_info;